Анализ кода сборки
$ 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 байта, что дает этот пробел, заполняется мусором.
куча .операторы определяются документацией ассемблера. Обычно они не дают исполняемого кода.