2017-11-21 1 views
-1

C 프로그램에서 생성 된 어셈블리 코드의 의미를 찾으려고합니다. 다음은 C로 작성된 프로그램입니다 :컴파일러가 쓸모없는 어셈블리 코드를 생성 할 수 있습니까?

int* a = &argc; 
int b = 8; 
a = &b; 

설명과 함께 생성 된 어셈블리 코드입니다. 주의

프롤로그 :

leal 4(%esp), %ecx 
andl $-16, %esp 
pushl -4(%ecx) 
pushl %ebp 
movl %esp, %ebp 
pushl %ecx 
subl $36, %esp 

로드 %의 EAX에는 argc의 주소 :

movl %ecx, %eax 

부분 내가하지 않습니다 이해가 안 한 부분이있다

movl 4(%eax), %edx 
movl %edx, -28(%ebp) 

스택 스매싱 보호 코드 (설정) :

A와 B의 6,
movl %gs:20, %ecx 
movl %ecx, -12(%ebp) 
xorl %ecx, %ecx 

부하 값 (main.c에의 참조)

leal -20(%ebp), %eax 
movl %eax, -16(%ebp) 

스택 스매싱 프로텍터 번호 :

movl %eax, -16(%ebp) 
movl $8, -20(%ebp) 

은 (a = & b)의 ​​값을 수정 (확인 적층인지 확인)

movl $0, %eax 
movl -12(%ebp), %edx 
xorl %gs:20, %edx 
je .L7 
call __stack_chk_fail 

를 스택이 정상이면 :

.L7: 
    addl $36, %esp 
    popl %ecx 
    popl %ebp 
    leal -4(%ecx), %esp 
    ret 

그래서 내가 사용하지 않는 부분은 사용되지 않은 주소 인 -28 (% ebp)의 값을 수정합니다. 누군가이 부분이 생성 된 이유를 알고 있습니까?

+6

최적화하지 않고 컴파일하면 (기본값) 컴파일러 출력에는 필요하지 않더라도 메모리에 대한 모든로드/저장이 포함됩니다. 코드를 가져 와서'main'이 아닌 함수에 넣고 최적화 ('-O3')로 컴파일하십시오. –

+0

main()을 사용하지 말고 테스트중인 코드를 다른 함수 이름으로 만드십시오.main() 질문은 질문을 받고 수십 배의 답변을했습니다 ... –

+2

당신은 컴파일러에게 최적화 플래그를 지정하지 않음으로써 뇌를 끄고 이상한 코드를 생성하는지 궁금합니다. – fuz

답변

6

컴파일러의 기능을 확인하는 좋은 방법입니다.

int main(int argc, char **argv) 
{ 
    int* a = &argc; 
    int b = 8; 
    a = &b; 
} 

컴파일 오브젝트 파일에 디버그 정보와 :

$ gcc -c -g main.c 

보기 어셈블리 :

$ objdump -S main.o 

main.o:  file format elf64-x86-64 


Disassembly of section .text: 

0000000000000000 <main>: 
int main(int argc, char **argv) 
{ 
    0: 55      push %rbp 
    1: 48 89 e5    mov %rsp,%rbp 
    4: 89 7d ec    mov %edi,-0x14(%rbp) 
    7: 48 89 75 e0    mov %rsi,-0x20(%rbp) 
    int* a = &argc; 
    b: 48 8d 45 ec    lea -0x14(%rbp),%rax 
    f: 48 89 45 f8    mov %rax,-0x8(%rbp) 
    int b = 8; 
    13: c7 45 f4 08 00 00 00 movl $0x8,-0xc(%rbp) 
    a = &b; 
    1a: 48 8d 45 f4    lea -0xc(%rbp),%rax 
    1e: 48 89 45 f8    mov %rax,-0x8(%rbp) 
    22: b8 00 00 00 00   mov $0x0,%eax 
} 
    27: 5d      pop %rbp 
    28: c3      retq 

는 다음과 같은 행동을 할 당신이라는 파일을 main.c가 있다고 가정 전체 최적화 :

$ gcc -c -g -O3 main.c 

그리고 어셈블리를 다시 봅니다 :

$ objdump -S main.o 

main.o:  file format elf64-x86-64 


Disassembly of section .text.startup: 

0000000000000000 <main>: 
int main(int argc, char **argv) 
{ 
    int* a = &argc; 
    int b = 8; 
    a = &b; 
} 
    0: 31 c0     xor %eax,%eax 
    2: c3      retq 

그래서 대답은 예입니다. 컴파일러는 필요없는 명령어를 생성 할 수 있습니다. 이것이 최적화를 설정 한 이유입니다. 그들이 꺼지면 컴파일러는 전혀 생각하지 않고 매우 일반적인 방식으로 작업을 수행합니다. 예를 들어, 사용되지 않는 변수에 대한 공간을 예약합니다.

+0

감사합니다. 내가 놀랍게도 발견 한 것은 어셈블리 부분이 C 소스 코드의 어느 부분에도 해당하지 않는다는 것입니다. 그러나 프로그램이 아무 것도하지 않기 때문에 어셈블리의 모든 라인을 쓸모없는 것으로 간주해야합니다. –

+1

컴파일러가 수행하는 작업을보기 위해 컴파일 및 디스 어셈블 할 C 함수를 만드는 기술이 있습니다. 낮은 최적화 수준 컴파일러는 모든 것을 스택/메모리에 저장하고 거기에서 형식을 검색 한 다음 죽은 코드가 있으면 결코 읽지 않는 무언가를 쓸 수 있습니다.하지만 프로그램이 그렇게했을 수도 있기 때문에 부분적으로는 그렇습니다. 데드 코드가 아니거나 무언가로 최적화 된 테스트 기능을 작성하는 것은 약간의 연습을 필요로합니다. –

+1

@DJ_Joe : https://stackoverflow.com/questions/38552116/how-to-remove-noise-from-gcc-clang-assembly-output을 참조하십시오. 특히 Matt Godbolt의 CppCon2017 토크 : "What Has My Compiler 최근에 나를 위해? 컴파일러의 뚜껑을 풀어 라. "] (https://youtu.be/bSkpMdDe4g4), 정확히 @ old_time이 말한 내용입니다. –

관련 문제