He desglosado el desmontaje para que usted muestre cómo se produjo el ensamblaje a partir de la fuente C.
8(%ebp)
= x
, 12(%ebp)
= y
, 16(%ebp)
= z
arith:
Crear el marco de pila:
pushl %ebp
movl %esp,%ebp
Mover
x
en
eax
,
y
en
edx
:
movl 8(%ebp),%eax
movl 12(%ebp),%edx
t1 = x + y
.
leal
(Load dirección efectiva) agregará
edx
y
eax
, y
t1
estará en
ecx
:
leal (%edx,%eax),%ecx
int t4 = y * 48;
en dos pasos a continuación, se multiplica por 3, y luego por 16.
t4
al final habrá en
edx
:
Multiplica edx
por 2 y agrega edx
al resultado, es decir. edx = edx * 3
:
leal (%edx,%edx,2),%edx
Shift left 4 bits, es decir. multiplicar por 16:
sall $4,%edx
int t2 = z+t1;
.
ecx
inicialmente sostiene
t1
,
z
es en
16(%ebp)
, al final de la instrucción
ecx
será la celebración de
t2
:
addl 16(%ebp),%ecx
int t5 = t3 + t4;
.
t3
era simplemente
x + 4
, y en lugar de calcular y almacenar
t3
, la expresión
t3
se coloca en línea. Esta instrucción esencial es
(x+4) + t4
, que es lo mismo que
t3
+
t4
. Agrega
edx
(
t4
) y
eax
(
x
), y agrega 4 como un
desplazamiento para lograr ese resultado.
leal 4(%edx,%eax),%eax
int rval = t2 * t5;
bastante sencilla éste; ecx
representa t2
y eax
representa t5
. El valor devuelto se transfiere a la persona que llama a través del eax
.
imull %ecx,%eax
Destruye el marco de pila y restaurar
esp
y
ebp
:
movl %ebp,%esp
popl %ebp
retorno de la rutina:
ret
De este ejemplo se puede ver que el resultado t es lo mismo, pero la estructura es un poco diferente. Lo más probable es que este código haya sido compilado con algún tipo de optimización o alguien lo haya escrito así para demostrar un punto.
Como han dicho otros, no se puede volver exactamente a la fuente desde el desmontaje. Depende de la interpretación de la persona que lee el ensamblaje para obtener un código C equivalente.
Para ayudar con el montaje de aprender y comprender el desmontaje de sus programas de C, puede hacer lo siguiente en Linux:
Compilar con información de depuración (-g
), que incrustar la fuente:
gcc -c -g arith.c
Si está en una máquina de 64 bits, puede indicarle al compilador que cree un binario de 32 bits con la bandera -m32
(lo hice para el ejemplo a continuación).
Uso objdump para volcar el archivo objeto con que es intercalada fuente:
objdump -d -S arith.o
-d
= desmontaje, -S
= fuente de visualización. Puede agregar -M intel-mnemonic
para usar la sintaxis de Intel ASM si lo prefiere a través de la sintaxis T de AT & que utiliza su ejemplo.
Salida:
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
Como se puede ver, sin optimizaciones del compilador produce un binario más grande que el ejemplo que tiene. Puede jugar con eso y agregar un indicador de optimización del compilador al compilar (es decir, -O1
, -O2
, -O3
). Cuanto más alto sea el nivel de optimización, más abstracto parecerá el desensamblaje.
Por ejemplo, con sólo el nivel 1 de optimización (gcc -c -g -O1 -m32 arith.c1
), el código de montaje producido es mucho más corto:
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
¿Qué nivel está utilizando cuando se compila la optimización? Si desea una conversión línea por línea, use -O0; de lo contrario, deberá tener en cuenta las optimizaciones. – Maz
... y revertir el código optimizado al orden de enunciado C original no es del todo posible. –
¿Estás seguro de que esta es una compilación ingenua? Parece que está algo optimizado. Escriba la expresión algebraica que calcula la función y vea si puede descubrir eso. –