c - 当我调用 jmp 时,我在 c 内联汇编中遇到了段错误

标签 c assembly x86 segmentation-fault inline-assembly

我在使用 jmp 时遇到了段错误。

第一次,我只是使用jmp 0x30,我得到了segmentation fault。

我用gdb调试了我的程序,我看到在调用jmp之后,它跳转到了一个绝对地址。

(gdb) b main
Breakpoint 1 at 0x80483b7: file f.c, line 3.
(gdb) r
Starting program: /root/work/f

Breakpoint 1, main () at f.c:3
3       __asm__("jmp 0x30\n"
(gdb) n
0x00000030 in ?? ()
(gdb)

我也觉得可能是相对地址,所以我修改了jmp的param为disassemble maincall的地址>。 就是这样,

#include<stdio.h>
int main(){
__asm__("jmp 0x080483e6\n"
"popl %esi\n"
"movl %esi,0x8(%esi)\n"
"movb $0x0,0x7(%esi)\n"
"movl $0x0,0xc(%esi)\n"
"movl $0xb,%eax\n"
"movl %esi,%ebx\n"
"leal 0x8(%esi),%ecx\n"
"leal 0xc(%esi),%edx\n"
"int $0x80\n"
"movl $0x1, %eax\n"
"movl $0x0, %ebx\n"
"int $0x80\n"
"call 0x2a\n"
".string \"/bin/sh\"\n");
return 0;
}

但是我明白了

Breakpoint 1, main () at f.c:3
3       __asm__("jmp 0x080483e6\n"
(gdb) n

Program received signal SIGSEGV, Segmentation fault.
0x0000002a in ?? ()
(gdb)

我找到了这个相关问题 confusing with JMP instruction ,我这样修改了我的代码。

#include<stdio.h>
int main(){
__asm__("jmp L\n"
"sub:\n"
"popl %esi\n"
"movl %esi,0x8(%esi)\n"
"movb $0x0,0x7(%esi)\n"
"movl $0x0,0xc(%esi)\n"
"movl $0xb,%eax\n"
"movl %esi,%ebx\n"
"leal 0x8(%esi),%ecx\n"
"leal 0xc(%esi),%edx\n"
"int $0x80\n"
"movl $0x1, %eax\n"
"movl $0x0, %ebx\n"
"int $0x80\n"
"jmp exit\n"
"L:\n"
"call sub\n"
".string \"/bin/sh\"\n"
"exit:\n");
return 0;
}

但不适合我,调用jmp后,指令地址还是jmp

那一行
(gdb) b main
Breakpoint 1 at 0x80483b7: file f.c, line 3.
(gdb) r
Starting program: /root/work/f

Breakpoint 1, main () at f.c:3
3       __asm__("jmp L\n"
(gdb) n

Program received signal SIGSEGV, Segmentation fault.
0x080483ba in main () at f.c:3
3       __asm__("jmp L\n"
(gdb) n

Program terminated with signal SIGSEGV, Segmentation fault.
The program no longer exists.
(gdb)

我不知道问题出在哪里,非常感谢您的帮助!

最佳答案

我不认为段错误是由 jmp L 指令引起的。

看看我在这里做了什么:

(gdb) b main
Breakpoint 1 at 0x80483be: file test.c, line 3.
(gdb) run
Starting program: /home/cad/a.out 

Breakpoint 1, main () at test.c:3
3       __asm__("jmp L\n"
(gdb) display/i $pc
1: x/i $pc
=> 0x80483be <main+3>:  jmp    0x80483ec <main+49>
(gdb) si
0x080483ec      3       __asm__("jmp L\n"
1: x/i $pc
=> 0x80483ec <main+49>: call   0x80483c0 <main+5>
(gdb) si
0x080483c0      3       __asm__("jmp L\n"
1: x/i $pc
=> 0x80483c0 <main+5>:  pop    %esi
(gdb) si
0x080483c1      3       __asm__("jmp L\n"
1: x/i $pc
=> 0x80483c1 <main+6>:  mov    %esi,0x8(%esi)
(gdb) si

Program received signal SIGSEGV, Segmentation fault.
0x080483c1 in main () at test.c:3
3       __asm__("jmp L\n"
1: x/i $pc
=> 0x80483c1 <main+6>:  mov    %esi,0x8(%esi)
(gdb)

如您所见,我在 main 处设置了一个断点并启用了对每条执行的机器指令的反汇编 (display/i $pc)。然后我逐步执行机器指令 (si)。结果发现错误指令是 mov %esi,0x8(%esi) at 0x80483c1

据我所知,问题是 gdb 只显示它执行的下一个完整的语句。由于语句以分号结尾,整个 __asm__("...") 算作一个语句,gdb 只打印它的第一行,即 __asm__("jmp L\n",只要调试器单步执行 __asm__ 语句即可。


我们弄清楚了,现在让我们找出导致段错误的原因。

当您跳转到L 时,执行call sub。这会将 32 位返回地址压入堆栈。 sub 中的第一条指令,pop %esi,用返回地址填充 %esi 并将其从堆栈中移除。
当您现在执行 mov %esi,0x8(%esi) 时,CPU 会尝试将 %esi 移动到返回地址后面的 0x8 字节点,即在代码段内。而且,看起来,代码在您的操作系统上是只读的,因此程序会出错。

关于c - 当我调用 jmp 时,我在 c 内联汇编中遇到了段错误,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/39685490/

相关文章:

c - 多线程程序 POSIX

c - 程序集:从 C 调用或作为独立程序创建时的数据段

c - 编写 MIPS 机器指令并从 C 执行它们

c# - 处理器架构问题(x86 与任何 cpu)

两个具有自动存储期限的不同对象在地址比较下是否可以比较相等?

c - 如何从编码 key (替换密码)C 中生成解码 key

c - 如果使用 Glade,GtkDrawingArea 在绘制时不会更新

c - 我如何在 C 中测量时间?

assembly - MIPS计算跳转指令的机器编码

visual-c++ - _umul128 在 Windows 32 位上