gcc 生成对下一条指令地址的调用
gcc generate `call` to the address of the next instruction
我正在使用 cc -g -O0 -m32
:
编译下一个代码
void f() {
int l;
short s;
char c;
l = 0xdeadbeef;
s = l;
c = l;
printf("l = 0x%x (%d bits)\n", l, sizeof(l) * 8);
printf("s = 0x%x (%d bits)\n", s, sizeof(s) * 8);
printf("c = 0x%x (%d bits)\n", c, sizeof(c) * 8);
}
以下几行的用途是什么?
0x00001e89 <+9>: call 0x1e8e <f+14>
0x00001e8e <+14>: pop %eax
0x00001e8f <+15>: lea 0xe8(%eax),%ecx
当我使用 gdb 反汇编时
(gdb) disassemble f
Dump of assembler code for function f:
0x00001e80 <+0>: push %ebp
0x00001e81 <+1>: mov %esp,%ebp
0x00001e83 <+3>: push %ebx
0x00001e84 <+4>: push %edi
0x00001e85 <+5>: push %esi
0x00001e86 <+6>: sub [=12=]x3c,%esp
0x00001e89 <+9>: call 0x1e8e <f+14>
0x00001e8e <+14>: pop %eax
0x00001e8f <+15>: lea 0xe8(%eax),%ecx
0x00001e95 <+21>: mov [=12=]x20,%edx
0x00001e9a <+26>: movl [=12=]xdeadbeef,-0x10(%ebp)
0x00001ea1 <+33>: mov -0x10(%ebp),%esi
0x00001ea4 <+36>: mov %si,%di
0x00001ea7 <+39>: mov %di,-0x12(%ebp)
0x00001eab <+43>: mov -0x10(%ebp),%esi
0x00001eae <+46>: mov %esi,%ebx
0x00001eb0 <+48>: mov %bl,-0x13(%ebp)
0x00001eb3 <+51>: mov -0x10(%ebp),%esi
0x00001eb6 <+54>: mov %ecx,(%esp)
0x00001eb9 <+57>: mov %esi,0x4(%esp)
0x00001ebd <+61>: movl [=12=]x20,0x8(%esp)
0x00001ec5 <+69>: mov %eax,-0x18(%ebp)
0x00001ec8 <+72>: mov %edx,-0x1c(%ebp)
0x00001ecb <+75>: call 0x1f5a
0x00001ed0 <+80>: mov -0x18(%ebp),%ecx
0x00001ed3 <+83>: lea 0xfc(%ecx),%edx
0x00001ed9 <+89>: mov [=12=]x10,%esi
0x00001ede <+94>: movswl -0x12(%ebp),%ecx
0x00001ee2 <+98>: mov %edx,(%esp)
0x00001ee5 <+101>: mov %ecx,0x4(%esp)
0x00001ee9 <+105>: movl [=12=]x10,0x8(%esp)
0x00001ef1 <+113>: mov %eax,-0x20(%ebp)
0x00001ef4 <+116>: mov %esi,-0x24(%ebp)
0x00001ef7 <+119>: call 0x1f5a
0x00001efc <+124>: mov -0x18(%ebp),%ecx
0x00001eff <+127>: lea 0x110(%ecx),%edx
0x00001f05 <+133>: mov [=12=]x8,%esi
0x00001f0a <+138>: movsbl -0x13(%ebp),%ecx
0x00001f0e <+142>: mov %edx,(%esp)
0x00001f11 <+145>: mov %ecx,0x4(%esp)
0x00001f15 <+149>: movl [=12=]x8,0x8(%esp)
0x00001f1d <+157>: mov %eax,-0x28(%ebp)
0x00001f20 <+160>: mov %esi,-0x2c(%ebp)
0x00001f23 <+163>: call 0x1f5a
0x00001f28 <+168>: mov %eax,-0x30(%ebp)
0x00001f2b <+171>: add [=12=]x3c,%esp
0x00001f2e <+174>: pop %esi
0x00001f2f <+175>: pop %edi
0x00001f30 <+176>: pop %ebx
0x00001f31 <+177>: pop %ebp
0x00001f32 <+178>: ret
End of assembler dump.
这是生成与位置无关的代码的技巧。您可以看到下一条指令是 pop %eax
,它将从堆栈中获取 return 地址。当然,return 地址是 pop
本身的地址,因此它获得了指令的绝对地址,因此它可以用作访问与代码相关的内容的基础。
它立即用于获取第一个 printf
调用的第一个参数,文字格式字符串。你可以看到 ecx
是基于 eax
在第 +15
行加载的,然后 ecx
被写在第一个参数槽中第 +54
行的堆栈上作为根据调用约定。
参考点也存储在第 +69
行的 -0x18(%ebp)
处。与第一个 printf
一样,它随后被重新用于后续格式字符串,请参阅第 +83
和 +127
.
行
我正在使用 cc -g -O0 -m32
:
void f() {
int l;
short s;
char c;
l = 0xdeadbeef;
s = l;
c = l;
printf("l = 0x%x (%d bits)\n", l, sizeof(l) * 8);
printf("s = 0x%x (%d bits)\n", s, sizeof(s) * 8);
printf("c = 0x%x (%d bits)\n", c, sizeof(c) * 8);
}
以下几行的用途是什么?
0x00001e89 <+9>: call 0x1e8e <f+14>
0x00001e8e <+14>: pop %eax
0x00001e8f <+15>: lea 0xe8(%eax),%ecx
当我使用 gdb 反汇编时
(gdb) disassemble f
Dump of assembler code for function f:
0x00001e80 <+0>: push %ebp
0x00001e81 <+1>: mov %esp,%ebp
0x00001e83 <+3>: push %ebx
0x00001e84 <+4>: push %edi
0x00001e85 <+5>: push %esi
0x00001e86 <+6>: sub [=12=]x3c,%esp
0x00001e89 <+9>: call 0x1e8e <f+14>
0x00001e8e <+14>: pop %eax
0x00001e8f <+15>: lea 0xe8(%eax),%ecx
0x00001e95 <+21>: mov [=12=]x20,%edx
0x00001e9a <+26>: movl [=12=]xdeadbeef,-0x10(%ebp)
0x00001ea1 <+33>: mov -0x10(%ebp),%esi
0x00001ea4 <+36>: mov %si,%di
0x00001ea7 <+39>: mov %di,-0x12(%ebp)
0x00001eab <+43>: mov -0x10(%ebp),%esi
0x00001eae <+46>: mov %esi,%ebx
0x00001eb0 <+48>: mov %bl,-0x13(%ebp)
0x00001eb3 <+51>: mov -0x10(%ebp),%esi
0x00001eb6 <+54>: mov %ecx,(%esp)
0x00001eb9 <+57>: mov %esi,0x4(%esp)
0x00001ebd <+61>: movl [=12=]x20,0x8(%esp)
0x00001ec5 <+69>: mov %eax,-0x18(%ebp)
0x00001ec8 <+72>: mov %edx,-0x1c(%ebp)
0x00001ecb <+75>: call 0x1f5a
0x00001ed0 <+80>: mov -0x18(%ebp),%ecx
0x00001ed3 <+83>: lea 0xfc(%ecx),%edx
0x00001ed9 <+89>: mov [=12=]x10,%esi
0x00001ede <+94>: movswl -0x12(%ebp),%ecx
0x00001ee2 <+98>: mov %edx,(%esp)
0x00001ee5 <+101>: mov %ecx,0x4(%esp)
0x00001ee9 <+105>: movl [=12=]x10,0x8(%esp)
0x00001ef1 <+113>: mov %eax,-0x20(%ebp)
0x00001ef4 <+116>: mov %esi,-0x24(%ebp)
0x00001ef7 <+119>: call 0x1f5a
0x00001efc <+124>: mov -0x18(%ebp),%ecx
0x00001eff <+127>: lea 0x110(%ecx),%edx
0x00001f05 <+133>: mov [=12=]x8,%esi
0x00001f0a <+138>: movsbl -0x13(%ebp),%ecx
0x00001f0e <+142>: mov %edx,(%esp)
0x00001f11 <+145>: mov %ecx,0x4(%esp)
0x00001f15 <+149>: movl [=12=]x8,0x8(%esp)
0x00001f1d <+157>: mov %eax,-0x28(%ebp)
0x00001f20 <+160>: mov %esi,-0x2c(%ebp)
0x00001f23 <+163>: call 0x1f5a
0x00001f28 <+168>: mov %eax,-0x30(%ebp)
0x00001f2b <+171>: add [=12=]x3c,%esp
0x00001f2e <+174>: pop %esi
0x00001f2f <+175>: pop %edi
0x00001f30 <+176>: pop %ebx
0x00001f31 <+177>: pop %ebp
0x00001f32 <+178>: ret
End of assembler dump.
这是生成与位置无关的代码的技巧。您可以看到下一条指令是 pop %eax
,它将从堆栈中获取 return 地址。当然,return 地址是 pop
本身的地址,因此它获得了指令的绝对地址,因此它可以用作访问与代码相关的内容的基础。
它立即用于获取第一个 printf
调用的第一个参数,文字格式字符串。你可以看到 ecx
是基于 eax
在第 +15
行加载的,然后 ecx
被写在第一个参数槽中第 +54
行的堆栈上作为根据调用约定。
参考点也存储在第 +69
行的 -0x18(%ebp)
处。与第一个 printf
一样,它随后被重新用于后续格式字符串,请参阅第 +83
和 +127
.