问题描述
我有一个简短的 hello world 程序:
I have this short hello world program:
#include <stdio.h>
static const char* msg = "Hello world";
int main(){
printf("%s
", 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.
(为了表明你确实需要堆栈是可执行的,你把 "x"
而不是 ""
.GCC 可能会做如果你使用它的嵌套函数"扩展,这个.(不要那样做.))
(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"汇编语法中,共有三种行: A 行上面有一个标记,以冒号结尾,是一个标签.(我不记得哪些字符可以出现在标签中的规则.)第一个标记以点开头并且不以冒号结尾的行是汇编程序的某种指令.其他任何东西都是汇编指令.
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 汇编代码的哪些部分是必不可少的?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持!