main
은 특별한 기능이므로 다른 기능에서이 유형을 수행하면 더 좋은 결과를 얻을 수 있습니다 (바람직하게는 main
이없는 자체 파일 임). 예 :
void foo(int x) {
if (x == 0) {
printf("testing\n");
}
}
은 조립할 때 훨씬 분명합니다. 이렇게하면 최적화로 컴파일하고 조건부 동작을 계속 볼 수 있습니다. 최적화 레벨이 0 이상인 원본 프로그램을 컴파일한다면 컴파일러가 그 결과를 계산할 수 있기 때문에 아마도 비교를하지 못할 것입니다. 이 코드를 사용하면 컴파일러에서 매개 변수 부분 (x
)을 숨겨서 컴파일러에서이 최적화를 수행 할 수 없습니다.
이 현재 함수의 스택 프레임을 설정하는 것입니다
_main:
pushl %ebpz
movl %esp, %ebp
subl $24, %esp
andl $-16, %esp
여분의 물건이 실제로 무엇입니까. x86에서 스택 프레임은 스택 포인터의 값 (16, 32 또는 64 비트의 SP, ESP 또는 RSP)과 기본 포인터의 값 (BP, EBP 또는 RBP) 사이의 영역입니다. 이것은 아마도 지역 변수가 존재하지만 실제는 아니며 명시 적 스택 프레임은 대부분의 경우 선택 사항입니다. 그러나 alloca
및/또는 가변 길이 배열을 사용하면 그 사용이 필요합니다.
이 특정 스택 프레임 구조는 스택이 16 바이트 정렬되도록하기 때문에 main
기능과 다릅니다. ESP에서 뺄셈하면 스택 크기가 로컬 변수를 보유 할만큼 충분히 증가하고 andl
은 0에서 15까지 효과적으로 뺍니다. 따라서 16 바이트가 정렬됩니다. 이 정렬은 스택이 워드 정렬뿐만 아니라 캐시 정렬을 시작하도록하는 것을 제외하면 과도한 것처럼 보입니다.
movl $0, %eax
addl $15, %eax
addl $15, %eax
shrl $4, %eax
sall $4, %eax
movl %eax, -8(%ebp)
movl -8(%ebp), %eax
call __alloca
call ___main
나는이 모든 것이 무엇을 모른다. alloca
은 스택 포인터의 값을 변경하여 스택 프레임 크기를 늘립니다.
movl $0, -4(%ebp)
cmpl $0, -4(%ebp)
jne L2
movl $LC0, (%esp)
call _printf
L2:
movl $0, %eax
나는 이것이 무엇을하는지 생각합니다. 그렇지 않다면 call
은 문자열의 주소를 스택의 최상위 위치로 옮겨서 printf에 의해 검색 될 수 있다고 생각하면 movl
입니다. printf가 그 주소를 사용하여 printf의 다른 인수 (이 경우에는없는 경우)의 주소를 유추 할 수 있도록 스택에 전달되어야합니다.
leave
이 명령은 이전에 말한 스택 프레임을 제거합니다. 본질적으로 movl %ebp, %esp
이고 그 뒤에 popl %ebp
이옵니다. 스택 프레임을 생성하는 데 사용할 수있는 enter
명령어도 있지만 gcc는 스택 프레임을 사용하지 않았습니다. 스택 프레임을 명시 적으로 사용하지 않을 경우 EBP
을 일반 puropose 레지스터로 사용할 수 있으며 leave
대신 컴파일러에서 스택 프레임 크기를 스택 포인터에 추가하면 스택 크기가 프레임 크기만큼 감소합니다.
ret
설명 할 필요가 없습니다.
당신이 최적화
난 당신이 다른 최적화 수준이 FO을 모두 다시 컴파일 확신
컴파일, 그래서 당신은 아마 이상한 찾을 것입니다 발생할 수 있습니다 뭔가를 지적 할 것이다 때.형식 문자열에
%
이없고 추가 매개 변수가 전달되지 않은 경우 이
printf
및
fprintf
을 각각
puts
및
fputs
으로 바꾼 것을 확인했습니다. 이것은 (많은 이유로)
puts
과
fputs
으로 전화하는 것이 훨씬 저렴하고 결과적으로 당신이 원하는 것을 얻을 수 있기 때문입니다.
읽을 수 있도록 출력 인텔 구문을 설정해야합니다 ('-Mintel' IIRC). –
AT & T 구문은 완벽하게 악의적이며 UNIX에서 작업하는 경우에는 이중 언어로만 읽을 것을 권장합니다. – caf
투표가 너무 광범위하게 닫힙니다. –