问题描述
我有一个简短的hello world程序:
I have this short hello world program:
#include <stdio.h>
static const char* msg = "Hello world";
int main(){
printf("%s\n", msg);
return 0;
}
我使用gcc将其编译为以下汇编代码:
I compiled it into the following assembly code with gcc:
.file "hello_world.c"
.section .rodata
.LC0:
.string "Hello world"
.data
.align 4
.type msg, @object
.size msg, 4
msg:
.long .LC0
.text
.globl main
.type main, @function
main:
.LFB0:
.cfi_startproc
pushl %ebp
.cfi_def_cfa_offset 8
.cfi_offset 5, -8
movl %esp, %ebp
.cfi_def_cfa_register 5
andl $-16, %esp
subl $16, %esp
movl msg, %eax
movl %eax, (%esp)
call puts
movl $0, %eax
leave
.cfi_restore 5
.cfi_def_cfa 4, 4
ret
.cfi_endproc
.LFE0:
.size main, .-main
.ident "GCC: (Ubuntu 4.8.4-2ubuntu1~14.04.3) 4.8.4"
.section .note.GNU-stack,"",@progbits
我的问题是:如果我要用汇编语言编写该程序(而不是用C编写然后编译为汇编语言),那么此代码的所有部分是否必不可少?我了解组装说明,但是有些部分我不理解.例如,我不知道什么是.cfi *,而且我想知道是否需要包括此文件才能在程序集中编写该程序.
My question is: are all parts of this code essential if I were to write this program in assembly (instead of writing it in C and then compiling to assembly)? I understand the assembly instructions but there are certain pieces I don't understand. For instance, I don't know what .cfi* is, and I'm wondering if I would need to include this to write this program in assembly.
推荐答案
在看起来似乎可以运行的平台上的绝对最低要求是
The absolute bare minimum that will work on the platform that this appears to be, is
.globl main
main:
pushl $.LC0
call puts
addl $4, %esp
xorl %eax, %eax
ret
.LC0:
.string "Hello world"
但是,这违反了许多 ABI 的要求.符合ABI计划的最低要求是
But this breaks a number of ABI requirements. The minimum for an ABI-compliant program is
.globl main
.type main, @function
main:
subl $24, %esp
pushl $.LC0
call puts
xorl %eax, %eax
addl $28, %esp
ret
.size main, .-main
.section .rodata
.LC0:
.string "Hello world"
目标文件中的所有其他内容是编译器未尽可能严格地优化代码,或者是可选批注将被写入目标文件.
Everything else in your object file is either the compiler not optimizing the code down as tightly as possible, or optional annotations to be written to the object file.
.cfi_*
指令尤其是可选注释.当且仅当抛出C ++异常时函数可能在调用堆栈上时,它们才是必要的,但是对于您可能要从中提取的任何程序,它们都是有用的.堆栈跟踪.如果您打算用汇编语言手工编写非平凡的代码,那么值得学习如何编写它们.不幸的是,它们的文献很少.我目前找不到我认为值得链接的任何内容.
The .cfi_*
directives, in particular, are optional annotations. They are necessary if and only if the function might be on the call stack when a C++ exception is thrown, but they are useful in any program from which you might want to extract a stack trace. If you are going to write nontrivial code by hand in assembly language, it will probably be worth learning how to write them. Unfortunately, they are very poorly documented; I am not currently finding anything that I think is worth linking to.
行
.section .note.GNU-stack,"",@progbits
了解是否要手工编写汇编语言也很重要;它是另一个可选的注释,但是却是一个有价值的注释,因为它的意思是此目标文件中的任何内容都不需要堆栈是可执行的".如果程序中的所有目标文件都带有此批注,则内核将使堆栈无法执行,从而在某种程度上提高了安全性.
is also important to know about if you are writing assembly language by hand; it is another optional annotation, but a valuable one, because what it means is "nothing in this object file requires the stack to be executable." If all the object files in a program have this annotation, the kernel won't make the stack executable, which improves security a little bit.
((为了表明您 do 需要堆栈是可执行的,请放置"x"
而不是""
.如果您使用其嵌套函数"扩展名,GCC可能会这样做.(Don不这样做.)
(To indicate that you do need the stack to be executable, you put "x"
instead of ""
. GCC may do this if you use its "nested function" extension. (Don't do that.))
可能值得一提的是,在GCC和GNU binutils使用的"AT& T"汇编语法(默认情况下)中,有以下三种类型的行:上面带有单个标记(以冒号结尾)的是标签. (我不记得在标签中可以显示哪些字符的规则.)一行 first 标记以点开头,而 not 以冒号结尾的行是对汇编程序的某种指令.其他就是汇编指令.
It is probably worth mentioning that in the "AT&T" assembly syntax used (by default) by GCC and GNU binutils, there are three kinds of lines: A linewith a single token on it, ending in a colon, is a label. (I don't remember the rules for what characters can appear in labels.) A line whose first token begins with a dot, and does not end in a colon, is some kind of directive to the assembler. Anything else is an assembly instruction.
这篇关于如果我要用汇编语言编写程序,此HelloWorld汇编代码的哪些部分必不可少?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持!