如何通过gcc从x86内联程序集中获取EIP
我想从下面的代码中获取EIP的值,但是编译没有通过 命令: gcc-o xxx x86_内联组件c-m32&./xxx 文件内容x86_inline_asm.c:如何通过gcc从x86内联程序集中获取EIP,gcc,assembly,x86,inline-assembly,Gcc,Assembly,X86,Inline Assembly,我想从下面的代码中获取EIP的值,但是编译没有通过 命令: gcc-o xxx x86_内联组件c-m32&./xxx 文件内容x86_inline_asm.c: #include <unistd.h> #include <stdio.h> #include <stdlib.h> int main() { unsigned int eip_val; __asm__("mov %0,%%eip":"=r"(eip_val)); ret
#include <unistd.h>
#include <stdio.h>
#include <stdlib.h>
int main()
{
unsigned int eip_val;
__asm__("mov %0,%%eip":"=r"(eip_val));
return 0;
}
#包括
#包括
#包括
int main()
{
未签名的国际通行证;
__asm_uu__;(“mov%0,%%eip”:“=r”(eip_val));
返回0;
}
如何使用内联程序集获取EIP的值,并且可以在x86下成功编译。
如何修改代码并使用命令完成它?我不知道这方面的gcc内联汇编语法,但对于masm:
call next0
next0: pop eax ;eax = eip for this line
在Masm的情况下,$表示当前位置,并且由于调用是一条5字节指令,因此不带标签的替代语法为:
call $+5
pop eax
我不知道这方面的gcc内联汇编语法,但对于masm:
call next0
next0: pop eax ;eax = eip for this line
在Masm的情况下,$表示当前位置,并且由于调用是一条5字节指令,因此不带标签的替代语法为:
call $+5
pop eax
这听起来不太可能有用(而只是获取整个函数的地址,如
void*tmp=main
),但这是可能的
只需获取标签地址,或使用
(当前行的地址),并让链接器担心如何将正确的立即数输入机器代码。因此,您并不是在体系结构上读取EIP
,而是从即时消息读取它当前拥有的值
asm volatile("mov $., %0" : "=r"(address_of_mov_instruction) );
AT&T语法是mov-src,dst
,所以如果将其组装起来,您编写的将是一个跳转
(在体系结构上,EIP=指令执行时的结束,因此可以说您应该这样做
asm volatile(
"mov $1f, %0 \n\t" // reference label 1 forward
"1:" // GAS local label
"=r"(address_after_mov)
);
我使用的是asm volatile
,以防此asm语句通过内联或其他方式在同一函数内重复多次。如果希望每个实例获得不同的地址,则它必须是volatile
。否则编译器可以假定此asm语句的所有实例都产生相同的输出。通常t会好的
从架构上讲,在32位模式下,LEA没有RIP相对寻址,因此实际读取EIP的唯一好方法是call/pop。它不是通用寄存器,因此不能仅将其用作
mov
或任何其他指令的源或目标
但实际上,您根本不需要内联asm。 显示如何使用GNU C扩展,其中
&&label
获取其地址
int foo;
void *addr_inside_function() {
foo++;
lab1: ; // labels only go on statements, not declarations
void *tmp = &&lab1;
foo++;
return tmp;
}
在函数之外,您无法安全地使用此地址;我返回它只是作为一个示例,让编译器在asm中放置一个标签,看看会发生什么。如果没有该标签的goto
,它仍然可以非常积极地优化函数,但您可能会发现它作为asm goto(…)的输入很有用
函数中的其他位置
但无论如何,它编译成这个asm
# gcc -O3 -m32
addr_inside_function:
.L2:
addl $2, foo
movl $.L2, %eax
ret
因此,clang加载全局,计算foo+1并存储它,然后在标签计算foo+2并存储它之后(而不是加载两次)。因此,您仍然无法从任何地方有效地跳转到标签,因为它取决于
foo
在eax
中的旧值,以及存储foo+2
的期望行为,这听起来不太可能有用(而只是获取整个函数的地址,如void*tmp=main
),但这是可能的
只需获取标签地址,或使用
(当前行的地址),并让链接器担心如何将正确的立即数输入机器代码。因此,您不是从体系结构上读取EIP
,而是从立即数读取它当前拥有的值
asm volatile("mov $., %0" : "=r"(address_of_mov_instruction) );
AT&T语法是mov-src,dst
,所以如果将其组装起来,您编写的将是一个跳转
(在体系结构上,EIP=指令执行时的结束,因此可以说您应该这样做
asm volatile(
"mov $1f, %0 \n\t" // reference label 1 forward
"1:" // GAS local label
"=r"(address_after_mov)
);
我使用的是asm volatile
,以防此asm语句通过内联或其他方式在同一函数内重复多次。如果希望每个实例获得不同的地址,则它必须是volatile
。否则编译器可以假定此asm语句的所有实例都产生相同的输出。通常t会好的
从架构上讲,在32位模式下,LEA没有RIP相对寻址,因此实际读取EIP的唯一好方法是call/pop。它不是通用寄存器,因此不能仅将其用作
mov
或任何其他指令的源或目标
但实际上,您根本不需要内联asm。 显示如何使用GNU C扩展,其中
&&label
获取其地址
int foo;
void *addr_inside_function() {
foo++;
lab1: ; // labels only go on statements, not declarations
void *tmp = &&lab1;
foo++;
return tmp;
}
在函数之外,您无法安全地使用此地址;我返回它只是作为一个示例,让编译器在asm中放置一个标签,看看会发生什么。如果没有该标签的goto
,它仍然可以非常积极地优化函数,但您可能会发现它作为asm goto(…)的输入很有用
函数中的其他位置
但无论如何,它编译成这个asm
# gcc -O3 -m32
addr_inside_function:
.L2:
addl $2, foo
movl $.L2, %eax
ret
因此,clang加载全局,计算foo+1并存储它,然后在标签计算foo+2并存储它之后(而不是加载两次)。因此,您仍然无法从任何位置有效地跳转到标签,因为它取决于
eax
中有foo
的旧值,并且取决于所需的行为是存储foo+2
没有mov-foo、eip
或mov-eip、foo
指令。没有mov-foo、eip
或mov-eip、foo代码>指令。仅就记录而言,call+0
是特殊情况,不会破坏返回地址预测。因此,这很好,而且不会比call
调用一个帮助函数更糟糕,该函数会像许多人期望的那样返回返回地址。/。仅就记录而言,call+0
是特殊情况,不会破坏返回地址预测