Я разбил разборку для вас, чтобы показать, как сборка была произведена из источника C.
8(%ebp)
= x
, 12(%ebp)
= y
, 16(%ebp)
= z
arith:
Создать кадр стека:
pushl %ebp
movl %esp,%ebp
<ч />
Переместить x
в eax
, y
в edx
:
movl 8(%ebp),%eax
movl 12(%ebp),%edx
<ч />
t1 = x + y
. leal
(Загрузить эффективный адрес) добавит edx
и eax
, а t1
будет в ecx
:
leal (%edx,%eax),%ecx
<ч />
int t4 = y * 48;
в два этапа ниже, умножьте на 3, затем на 16. t4
в конечном итоге будет в edx
:
Умножьте edx
на 2 и добавьте edx
к результату, т.е. edx = edx * 3
leal (%edx,%edx,2),%edx
Сдвиг влево на 4 бита, т.е. умножить на 16:
sall $4,%edx
<ч />
int t2 = z+t1;
. ecx
первоначально содержит t1
, z
находится в 16(%ebp)
, в конце инструкции ecx
будет удерживать t2
:
addl 16(%ebp),%ecx
<ч />
int t5 = t3 + t4;
. t3
было просто x + 4
, и вместо вычисления и хранения t3
выражение t3
помещается в строку. Эта инструкция обязательна для (x+4) + t4
, что аналогично t3
+ t4
. Он добавляет edx
(t4
) и eax
(x
) и добавляет 4 как смещение для достижения этого результата.
leal 4(%edx,%eax),%eax
<Ч />
int rval = t2 * t5;
Довольно прямолинейно; ecx
представляет t2
, а eax
представляет t5
. Возвращаемое значение передается вызывающей стороне через eax
.
imull %ecx,%eax
<ч />
Уничтожить кадр стека и восстановить esp
и ebp
:
movl %ebp,%esp
popl %ebp
<ч />
Возвращение из рутины:
ret
<ч />
Из этого примера вы можете видеть, что результат тот же, но структура немного другая. Скорее всего, этот код был скомпилирован с какой-то оптимизацией, или кто-то написал его сам, чтобы продемонстрировать свою точку зрения.
Как уже говорили другие, вы не можете точно вернуться к источнику после разборки. Человек, читающий сборку, должен интерпретировать эквивалентный код С.
<ч />
Чтобы помочь в изучении ассемблера и понимания дизассемблирования ваших программ на C, вы можете сделать следующее в Linux:
Компиляция с отладочной информацией (-g
), которая будет включать источник:
gcc -c -g arith.c
Если вы работаете на 64-битной машине, вы можете указать компилятору создать 32-битный бинарный файл с флагом -m32
(я сделал это для примера ниже).
Используйте objdump для выгрузки объектного файла с чередованием его источника:
objdump -d -S arith.o
-d
= разборка, -S
= источник отображения. Вы можете добавить -M intel-mnemonic
, чтобы использовать синтаксис Intel ASM, если вы предпочитаете его синтаксису AT & T, который используется в вашем примере.
Выход:
arith.o: file format elf32-i386
Disassembly of section .text:
00000000 <arith>:
int arith(int x, int y, int z)
{
0: 55 push %ebp
1: 89 e5 mov %esp,%ebp
3: 83 ec 20 sub $0x20,%esp
int t1 = x+y;
6: 8b 45 0c mov 0xc(%ebp),%eax
9: 8b 55 08 mov 0x8(%ebp),%edx
c: 01 d0 add %edx,%eax
e: 89 45 fc mov %eax,-0x4(%ebp)
int t2 = z+t1;
11: 8b 45 fc mov -0x4(%ebp),%eax
14: 8b 55 10 mov 0x10(%ebp),%edx
17: 01 d0 add %edx,%eax
19: 89 45 f8 mov %eax,-0x8(%ebp)
int t3 = x+4;
1c: 8b 45 08 mov 0x8(%ebp),%eax
1f: 83 c0 04 add $0x4,%eax
22: 89 45 f4 mov %eax,-0xc(%ebp)
int t4 = y * 48;
25: 8b 55 0c mov 0xc(%ebp),%edx
28: 89 d0 mov %edx,%eax
2a: 01 c0 add %eax,%eax
2c: 01 d0 add %edx,%eax
2e: c1 e0 04 shl $0x4,%eax
31: 89 45 f0 mov %eax,-0x10(%ebp)
int t5 = t3 + t4;
34: 8b 45 f0 mov -0x10(%ebp),%eax
37: 8b 55 f4 mov -0xc(%ebp),%edx
3a: 01 d0 add %edx,%eax
3c: 89 45 ec mov %eax,-0x14(%ebp)
int rval = t2 * t5;
3f: 8b 45 f8 mov -0x8(%ebp),%eax
42: 0f af 45 ec imul -0x14(%ebp),%eax
46: 89 45 e8 mov %eax,-0x18(%ebp)
return rval;
49: 8b 45 e8 mov -0x18(%ebp),%eax
}
4c: c9 leave
4d: c3 ret
Как видите, без оптимизации компилятор создает бинарный файл большего размера, чем в вашем примере. Вы можете поэкспериментировать с этим и добавить флаг оптимизации компилятора при компиляции (т. Е. -O1
, -O2
, -O3
). Чем выше уровень оптимизации, тем более абстрактной будет казаться разборка.
Например, при оптимизации уровня 1 (gcc -c -g -O1 -m32 arith.c1
) полученный код сборки значительно короче:
00000000 <arith>:
int arith(int x, int y, int z)
{
0: 8b 4c 24 04 mov 0x4(%esp),%ecx
4: 8b 54 24 08 mov 0x8(%esp),%edx
int t1 = x+y;
8: 8d 04 11 lea (%ecx,%edx,1),%eax
int t2 = z+t1;
b: 03 44 24 0c add 0xc(%esp),%eax
int t3 = x+4;
int t4 = y * 48;
f: 8d 14 52 lea (%edx,%edx,2),%edx
12: c1 e2 04 shl $0x4,%edx
int t5 = t3 + t4;
15: 8d 54 11 04 lea 0x4(%ecx,%edx,1),%edx
int rval = t2 * t5;
19: 0f af c2 imul %edx,%eax
return rval;
}
1c: c3 ret