$ gcc -O2 -S test.c -----------------------(1)
.file "test.c"
.globl accum
.bss
.align 4
.type accum, @object
.size accum, 4
accum:
.zero 4
.text
.p2align 2,,3
.globl sum
.type sum, @function
sum:
pushl %ebp
movl %esp, %ebp
movl 12(%ebp), %eax
addl 8(%ebp), %eax
addl %eax, accum
leave
ret
.size sum, .-sum
.p2align 2,,3
.globl main
.type main, @function
main:
pushl %ebp
movl %esp, %ebp
subl $8, %esp
andl $-16, %esp
subl $16, %esp
pushl $11
pushl $10
call sum
xorl %eax, %eax
leave
ret
.size main, .-main
.section .note.GNU-stack,"",@progbits
.ident "GCC: (GNU) 3.4.6 20060404 (Red Hat 3.4.6-9)"
这是从这个 C 程序生成的汇编代码:
#include <stdio.h>
int accum = 0;
int sum(int x,int y)
{
int t = x+y;
accum +=t;
return t;
}
int main(int argc,char *argv[])
{
int i = 0,x=10,y=11;
i = sum(x,y);
return 0;
}
此外,这是从上述程序生成的目标代码:
$objdump -d test.o -------------------------(2)
test.o: file format elf32-i386
Disassembly of section .text:
00000000 <sum>:
0: 55 push %ebp
1: 89 e5 mov %esp,%ebp
3: 8b 45 0c mov 0xc(%ebp),%eax
6: 03 45 08 add 0x8(%ebp),%eax
9: 01 05 00 00 00 00 add %eax,0x0
f: c9 leave
10: c3 ret
11: 8d 76 00 lea 0x0(%esi),%esi
00000014 <main>:
14: 55 push %ebp
15: 89 e5 mov %esp,%ebp
17: 83 ec 08 sub $0x8,%esp
1a: 83 e4 f0 and $0xfffffff0,%esp
1d: 83 ec 10 sub $0x10,%esp
20: 6a 0b push $0xb
22: 6a 0a push $0xa
24: e8 fc ff ff ff call 25 <main+0x11>
29: 31 c0 xor %eax,%eax
2b: c9 leave
2c: c3 ret
理想情况下, list (1) 和 (2) 必须相同。但我明白了 list (1) 中有 movl、pushl 等,而 mov、push 中有 李宁 (2)。我的问题是:
- 处理器上实际执行的正确汇编指令是什么?
- 在 list (1) 中,我在开头看到了这个:
.file "test.c"
.globl accum
.bss
.align 4
.type accum, @object
.size accum, 4
accum:
.zero 4
.text
.p2align 2,,3
.globl sum
.type sum, @function
最后是这个:
.size main, .-main
.section .note.GNU-stack,"",@progbits
.ident "GCC: (GNU) 3.4.6 20060404 (Red Hat 3.4.6-9)"
这是什么意思?
谢谢。
最佳答案
无论使用何种变体,该指令都称为 MOV
。 l
后缀只是一个 gcc/AT&T 汇编约定,用于指定所需操作数的大小,在本例中为 4 字节操作数。
在 Intel 语法中 - 如果存在任何歧义 - 通常不会为指令添加后缀,而是使用所需大小的指示符标记内存参数(例如 BYTE
、WORD
、DWORD
等),这只是实现同一目标的另一种方式。
89 55
是MOV
从32位寄存器EBP
到32位寄存器的正确字节序列ESP
。两个 list 都没有问题。
指定生成此汇编代码的文件:
.file "test.c"
表示 accum
是一个全局符号(具有外部链接的 C 变量):
.globl accum
接下来的字节应该放在bss
部分,这个部分在目标文件中不占用空间,但在运行时分配和清零。
.bss
在 4 字节边界上对齐:
.align 4
它是一个对象(一个变量,而不是一些代码):
.type accum, @object
它是四个字节:
.size accum, 4
这里是 accum
定义的地方,四个零字节。
accum:
.zero 4
现在从 bss
部分切换到通常存储函数的文本部分。
.text
添加最多三个字节的填充以确保我们在 4 字节 (2^2) 边界上:
.p2align 2,,3
sum
是一个全局符号,它是一个函数。
.globl sum
.type sum, @function
main
的大小是“这里”-“main
开始的地方”:
.size main, .-main
这些指定了 gcc 特定的堆栈选项。通常,这是您选择拥有可执行堆栈(不是很安全)或不拥有(通常是首选)的地方。
.section .note.GNU-stack,"",@progbits
确定生成此程序集的编译器版本:
.ident "GCC: (GNU) 3.4.6 20060404 (Red Hat 3.4.6-9)"
关于c - 分析汇编代码,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/4020683/