2014-12-29 4 views
0

간단한 C++ 프로그램의 어셈블리 출력을 이해하려고합니다. 이것은 내 C++ 프로그램입니다.간단한 C++ 프로그램의 어셈블리 출력

void func() 
{} 

int main() 
{ 
    func(); 
} 

나는 나는 다음과 같은 어셈블리 코드를 얻을 수 위의 프로그램의 어셈블리 코드를 얻을 수 --save-임시 직원 옵션을 g ++ 사용하는 경우.

.file "main.cpp" 
    .text 
    .globl _Z4funcv 
    .type _Z4funcv, @function 
_Z4funcv: 
.LFB0: 
    .cfi_startproc 
    pushq %rbp 
    .cfi_def_cfa_offset 16 
    .cfi_offset 6, -16 
    movq %rsp, %rbp 
    .cfi_def_cfa_register 6 
    popq %rbp 
    .cfi_def_cfa 7, 8 
    ret 
    .cfi_endproc 
.LFE0: 
    .size _Z4funcv, .-_Z4funcv 
    .globl main 
    .type main, @function 
main: 
.LFB1: 
    .cfi_startproc 
    pushq %rbp 
    .cfi_def_cfa_offset 16 
    .cfi_offset 6, -16 
    movq %rsp, %rbp 
    .cfi_def_cfa_register 6 
    call _Z4funcv 
    movl $0, %eax 
    popq %rbp 
    .cfi_def_cfa 7, 8 
    ret 
    .cfi_endproc 
.LFE1: 
    .size main, .-main 
    .ident "GCC: (Ubuntu 4.8.2-19ubuntu1) 4.8.2" 
    .section .note.GNU-stack,"",@progbits 

어셈블리 내 지식에 따르면 데이터, 텍스트 및 BSS있는 모든 어셈블리 프로그램의 3 개 부분이 있어야한다. 또한 텍스트 섹션은 'global _start'로 시작해야합니다. 나는이 어셈블리 코드에서 그 중 어떤 것도 볼 수 없다. 누군가 위의 어셈블리 코드를 이해하는 데 도움을 줄 수 있습니까? C++ 코드와도 관련이 있다면 훌륭 할 것입니다.

모든 종류의 도움을 주시면 감사하겠습니다.

+1

일반적으로 어셈블리 소스 코드가 아닌 객체 (이진) 코드와 일치하는 맵 파일 내의 섹션을 찾아야한다고 생각합니다. –

+0

'_start'는 링크 할 CRT (C 런타임)에있을 가능성이 큽니다. 차례대로'main' 함수를 호출 할 것입니다. 또한 사용하지 않는 섹션을 정의 할 필요가 없습니다. – Michael

+2

두 번째 줄에는 어셈블러 지시문'.text'가 있습니다. 이것은 텍스트 섹션입니다. 전역 변수가 없으므로 다른 섹션은 필요하지 않습니다. – rkhb

답변

4

음, 여기가

.file "main.cpp"    # Debugging info (not essential) 
    .text       # Start of text section (i.e. your code) 
    .globl _Z4funcv    # Let the function _Z4funcv be callable 
            # from outside (e.g. from your main routine) 
    .type _Z4funcv, @function # Debugging info (possibly not essential) 
_Z4funcv:       # _Z4funcv is effectively the "name" of your 
            # function (C++ "mangles" the name; exactly 
            # how depends on your compiler -- Google "C++ 
            # name mangling" for more). 
.LFB0:        # Debugging info (possibly not essential) 
    .cfi_startproc     # Provides additional debug info (ditto) 
    pushq %rbp     # Store base pointer of caller function 
            # (standard function prologue -- Google 
            # "calling convention" or "cdecl") 
    .cfi_def_cfa_offset 16   # Provides additional debug info (ditto) 
    .cfi_offset 6, -16    # Provides additional debug info (ditto) 
    movq %rsp, %rbp    # Reset base pointer to a sensible place 
            # for this function to put its local 
            # variables (if any). Standard function 
            # prologue. 
    .cfi_def_cfa_register 6  # Debug ... 
    popq %rbp     # Restore the caller's base pointer 
            # Standard function epilogue 
    .cfi_def_cfa 7, 8    # Debug... 
    ret       # Return from function 
    .cfi_endproc     # Debug... 
.LFE0:        # Debug... 
    .size _Z4funcv, .-_Z4funcv # Debug... 
    .globl main     # Declares that the main function 
            # is callable from outside 
    .type main, @function  # Debug... 
main:        # Your main routine (name not mangled) 
.LFB1:        # Debug... 
    .cfi_startproc     # Debug... 
    pushq %rbp     # Store caller's base pointer 
            # (standard prologue) 
    .cfi_def_cfa_offset 16   # Debug... 
    .cfi_offset 6, -16    # Debug... 
    movq %rsp, %rbp    # Reset base pointer 
            # (standard prologue) 
    .cfi_def_cfa_register 6  # Debug... 
    call _Z4funcv    # Call `func` (note name mangled) 
    movl $0, %eax    # Put `0` in eax (eax is return value) 
    popq %rbp     # Restore caller's base pointer 
            # (standard epilogue) 
    .cfi_def_cfa 7, 8    # Debug... 
    ret       # Return from main function 
    .cfi_endproc     # Debug... 
.LFE1: 
    .size main, .-main   # Debug... 
    .ident "GCC: (Ubuntu 4.8.2-19ubuntu1) 4.8.2" # fluff 
    .section .note.GNU-stack,"",@progbits  # fluff 

링커는 main을 찾기 위해 알고 ... 라인으로 라인 (그리고 하지start)는 표준 C 또는 C++ 라이브러리를 (사용하는 경우하는 것이 보통 당신이 달리 말하지 않는 한). 일부 스텁 코드 (start 포함)를 최종 실행 파일에 연결합니다.

그래서, 정말, 유일한 중요한 비트는 ...

.text       
    .globl _Z4funcv    
_Z4funcv: 
    pushq %rbp 
    movq %rsp, %rbp 
    popq %rbp 
    ret 
    .globl main 
main: 
    pushq %rbp 
    movq %rsp, %rbp 
    call _Z4funcv 
    movl $0, %eax 
    popq %rbp 
    ret 

처음부터 시작하고, 모든 복잡한 표준 라이브러리 물건 당신의 발견의 방법으로 점점이없는 싶은 경우에, 당신이 할 수있는 이런 일을하고 C++ 코드로 동일한 결과를 얻을 :

.text 
    .globl _func 
_func:     # Just as above, really 
    push %ebp 
    mov %esp, %ebp 
    pop %ebp 
    ret 
    .globl _start 
_start:     # A few changes here 
    push %ebp 
    mov %esp, %ebp 
    call _func 
    movl $1, %eax  # Invoke the Linux 'exit' syscall 
    movl $0, %ebx  # With a return value of 0 (pick any char!) 
    int $0x80   # Actual invocation 

출구 콜은 약간 고통스러운, 그러나 필요합니다. 가지고 있지 않으면 코드를 "지나쳤습니다"코드를 계속 실행하려고 시도합니다. 중요한 코드 또는 데이터가 될 수 있으므로 기기가 Segmentation Fault (세그먼트 오류) 오류로 중지해야합니다. 퇴장 호출을하면이 모든 것을 피할 수 있습니다. 표준 라이브러리를 사용하는 경우 (C++ 예에서 자동으로 수행됨) 종료 문은 링커가 처리합니다. gcc -nostdlib -o test test.s

컴파일 (GCC이라고 지적은 특히 표준 라이브러리를 사용하지말했다). 나는 이것이 32 비트 시스템을위한 것이라고 말하고 64 비트에서는 작동하지 않을 것입니다. 테스트 할 64 비트 시스템이 없지만, 아마도 도움이되는 StackOverflower가 64 비트 번역으로 칩입니다.