sam*_*ath 0 c++ assembly compilation g++
我试图理解一个简单的 C++ 程序的汇编输出。这是我的 C++ 程序。
void func()
{}
int main()
{
func();
}
Run Code Online (Sandbox Code Playgroud)
当我使用带有 --save-temps 选项的 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
Run Code Online (Sandbox Code Playgroud)
根据我对汇编的了解,任何汇编程序都应该有 3 个部分,分别是数据、文本和 bss。此外,文本部分应以“全局 _start”开头。我在这个汇编代码中看不到它们中的任何一个。有人可以帮我理解上面的汇编代码。如果您也可以与 C++ 代码相关联,那就太好了。
非常感谢任何形式的帮助。
嗯,这里是一行一行的……
.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
Run Code Online (Sandbox Code Playgroud)
链接器知道查找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
Run Code Online (Sandbox Code Playgroud)
如果您想从头开始,并且不想让所有复杂的标准库内容妨碍您的发现,您可以执行以下操作并获得与您的 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
Run Code Online (Sandbox Code Playgroud)
退出系统调用有点痛苦,但很有必要。如果您没有它,它会尝试继续运行并运行“过去”您的代码的代码。由于这可能是重要的代码或数据,机器应该会以分段错误错误阻止您。有退出调用避免了这一切。如果您使用的是标准库(在您的 C++ 示例中会自动发生),则链接器会处理出口内容。
编译gcc -nostdlib -o test test.s(注意 gcc 被特别告知不要使用标准库)。我应该说这是针对 32 位系统的,很可能不适用于 64 位系统。我没有要测试的 64 位系统,但也许一些有用的 StackOverflower 会加入 64 位转换。
| 归档时间: |
|
| 查看次数: |
429 次 |
| 最近记录: |