Анализ кода сборки
$ 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 , %esp
andl $-16, %esp
subl , %esp
pushl
pushl
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 x8,%esp
1a: 83 e4 f0 and xfffffff0,%esp
1d: 83 ec 10 sub x10,%esp
20: 6a 0b push xb
22: 6a 0a push xa
24: e8 fc ff ff ff call 25 <main+0x11>
29: 31 c0 xor %eax,%eax
2b: c9 leave
2c: c3 ret
в идеале , листинг (1) и (2) должны быть одинаковыми. Но я вижу что в листинге (1) есть movl, pushl и т. д., Тогда как mov, push in lising (2). Мой вопрос:
- какая правильная инструкция по сборке фактически выполняется на процессоре?
- в листинге (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)"
что это значит?
спасибо.
2 ответов
инструкция называется MOV
какой вариант используется. The l
суффикс-это просто соглашение сборки gcc / AT&T, чтобы указать размер требуемых операндов, в данном случае 4 байтовых операндов.
в синтаксисе Intel-где есть какая-либо двусмысленность-вместо суффикса инструкции обычно помечают параметр памяти индикатором требуемого размера (например,BYTE
, WORD
, DWORD
, etc.), это просто еще один способ достижения той же вещь.
89 55
правильная последовательность байт MOV
из 32-разрядного регистра EBP
в 32-разрядный регистр ESP
. Нет ничего плохого в листинге.
указывает файл, из которого был создан этот код сборки:
.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
started":
.size main, .-main
здесь указаны конкретные параметры стека gcc. Обычно именно здесь вы выбираете исполняемый стек (не очень безопасный) или нет (обычно привилегированный.)
.section .note.GNU-stack,"",@progbits
определите, какая версия компилятора сгенерировала эту сборку:
.ident "GCC: (GNU) 3.4.6 20060404 (Red Hat 3.4.6-9)"
список ассемблера и список дизассемблера показывают один и тот же код, но используют другой синтаксис. Прилагаемый -l является вариантом синтаксиса, используемым gcc. То, что у вас другой синтаксис в инструментах (вывод C-компилятора и дизассемблер), показывает слабость вашей цепочки инструментов.
disassemnbly при смещении 11 в сумме: показывает только некоторые байты мусора. Точка входа в следующую функцию main выровнена на 4 байта, что дает этот пробел, заполняется мусором.
куча .операторы определяются документацией ассемблера. Обычно они не дают исполняемого кода.