我正在尝试通过EBP从被调用方获取调用者中定义的局部变量。它应该是可能的,但如果不是,请解释原因。
这是我现在的代码:
#include <stdio.h>
void TEST(int a, int b, int c){
int answer;
printf("a: %d | b: %d | c: %d\n", a, b, c);
__asm__ __volatile__(
".intel_syntax;"
"mov %0, dword ptr ds:[ebp + 20];" <-- EBP+20 == d == 42
".att_syntax;"
: "=r" (answer)
:
:
);
printf("Answer: %d\n", answer);
}
int main(void){
int a = 13;
int b = 14;
int c = 15;
int d = 42;
TEST(a, b, c);
}
当TEST
被调用时,我希望堆栈看起来如下:
|+20| | 13 <-- d
|+16| | 14 <-- c
|+12| | 15 <-- b
|+ 8| | 42 <-- a
|+ 4| | return address
| 0| | EBP
|- 4| | local var answer
|- 8| | ...
如果我尝试编译以下代码,我会得到:
test.c: Assembler messages:
test.c:7: Error: segment register name expected
错误在哪里?
答案 0 :(得分:1)
move mem2,mem1
是不允许的。但是即使在intel语法上也会由gcc处理。我的假设是不正确的。 Gcc
会为intel
和at&t
语法生成正确的代码。
"movl mem1,%0"
: "=r" (mem2)
Gcc将为我们生成有效的代码:
mov mem1,%eax
mov %eax,mem2
gcc无法得到段寄存器名称。但是有段ds
register.Plus即使没有提到段寄存器也应该没问题。实际问题只是前缀问题
应该完成:
为了解决这个问题,我们必须使用nonprefix
或者加上前缀%
它在x64机器上。你应该改变rbp-&gt; ebp。并且还可以更改0x10
#include <stdio.h>
#include <stdlib.h>
#include <stdint.h>
void TEST(int a, int b, int c) {
int answer;
int x = 16;
__asm__ __volatile__(
".intel_syntax noprefix ;"
"mov %0, dword ptr ds:[rbp + %1+0];"
".att_syntax;"
: "=r" (answer)
: "r"((uintptr_t)x) /* x is input operand */
);
printf("Answer: %d\n", answer);
__asm__ __volatile__(
" movl 0(%%rbp,%1,1),%0"
: "=r" (answer)
: "r"((uintptr_t)x) /* x is input operand */
);
printf("Answer: %d\n", answer);
__asm__ __volatile__(
"movl 0x10(%%rbp),%0"
: "=r" (answer)
);
printf("Answer: %d\n", answer);
__asm__ __volatile__(
".intel_syntax;"
"mov %0, dword ptr [%%rbp + 0x10];"
".att_syntax;"
: "=r" (answer)
);
printf("Answer: %d\n", answer);
//the same as you wrote, just I added noprefix
__asm__ __volatile__(
".intel_syntax noprefix ;"
"mov %0, dword ptr ds:[rbp + 0x10];"
".att_syntax;"
: "=r" (answer)
);
printf("Answer: %d\n", answer);
//this lines just to test if we refer the same address as address of d
void *addressd;
__asm__ __volatile__(
"lea 0x10(%%rbp),%0"
: "=r" (addressd)
);
printf("TEST: address of d %p\n", addressd);
}
int main(void) {
int a = 13;
int b = 14;
int c = 15;
int d = 42;
TEST(a, b, c);
printf("address of d %p", &d);
}
答案 1 :(得分:1)
我猜你的例子仅用于教育目的,所以没关系。
但一般都要注意,你不能依赖堆栈上的变量顺序。 (你甚至不能依赖于在堆栈中找到它们。)
例如,如果您d
int d[1] = {42}
d,a,b,c
,则会有几个编译器发出a,b,c,d
而不是{{1}}。如果你打开优化器,一切都会发生(为什么你会使用内联汇编与未经优化的C代码混合?)。