Jay*_*Jay -2 c linux x86 assembly system-calls
我正在做一些x86练习; 我的任务让我write()在调试器中逐步调试库调用的汇编代码,直到我们达到SYSENTER指令,但是我得到的结果与我的一些同学不同.我看到的SYSENTER是:
?0xf7fdf421 <__kernel_vsyscall+1> push %edx
?0xf7fdf422 <__kernel_vsyscall+2> push %ebp
?0xf7fdf423 <__kernel_vsyscall+3> mov %esp,%ebp
?0xf7fdf425 <__kernel_vsyscall+5> sysenter
Run Code Online (Sandbox Code Playgroud)
这是我应该看到的吗?如果是这样,为什么它与我的一些同学看到的不一样?在执行sysenter指令之前,%edx和%ebp寄存器也保存在堆栈中吗?(根据我得到的答案,或者我错了,它似乎不是这样吗?)
这是我作业的原始说明:
汇编代码:
.file "A3Program2.c"
.section .rodata
.LC0:
.string "hello\n"
.LC1:
.string "xxxx\n"
.text
.globl secondCall
.type secondCall, @function
secondCall:
pushl %ebp
movl %esp, %ebp
subl $40, %esp
movl $6, 8(%esp)
movl $.LC0, 4(%esp)
movl $1, (%esp)
call write
movl %eax, -12(%ebp)
movl $8, 8(%esp)
movl $.LC1, 4(%esp)
movl $1, (%esp)
call write
addl %eax, -12(%ebp)
movl 12(%ebp), %eax
movl 8(%ebp), %edx
leal (%edx,%eax), %eax
addl %eax, -12(%ebp)
movl -12(%ebp), %eax
leave
ret
.size secondCall, .-secondCall
.globl firstCall
.type firstCall, @function
firstCall:
pushl %ebp
movl %esp, %ebp
subl $40, %esp
movl $2, 4(%esp)
movl $4, (%esp)
call secondCall
movl %eax, -12(%ebp)
movl -12(%ebp), %eax
leave
ret
.size firstCall, .-firstCall
.globl main
.type main, @function
main:
pushl %ebp
movl %esp, %ebp
andl $-16, %esp
subl $16, %esp
call firstCall
movl %eax, 12(%esp)
movl $0, %eax
leave
ret
.size main, .-main
.ident "GCC: (Ubuntu/Linaro 4.4.4-14ubuntu5) 4.4.5"
.section .note.GNU-stack,"",@progbits
Run Code Online (Sandbox Code Playgroud)
以下说明适用于Linux:
在secondCall函数中找到第二次写入调用的行号"call write".在此行设置断点.根据我的说法,这是22.
在此行设置断点.
break 22
Run Code Online (Sandbox Code Playgroud)
在调试器中运行程序.
run
Run Code Online (Sandbox Code Playgroud)
程序将在您设置的断点处停止.进入没有调试信息的代码.
si
Run Code Online (Sandbox Code Playgroud)
您将在源布局中看到"[No Source Available]".所以你需要查看反汇编的指令.
layout asm
Run Code Online (Sandbox Code Playgroud)
重复步入(si然后返回/输入将重复执行si命令),直到您看到"sysenter"出现在屏幕的asm布局部分中.我试图从asm布局部分的顶部复制指令(包括它们的地址),直到并包括sysenter指令.
提示:您可以通过键入Ctrl-x o将键盘的焦点更改为命令区域.这样,箭头键可以用来带回早期的命令(它只是节省一些打字).
bdo*_*lan 10
您正在追踪所谓的"虚拟动态共享对象"(VDSO) - 其内容是Linux内核的实现细节.有许多条件可能导致VDSO的内容发生变化; 因此,这里没有一个正确答案.
特别是,在32位x86系统上,至少有三种不同的机制可用于进行系统调用:
INT $0x80SYSCALL (最近的AMD CPU)SYSENTER (最近的英特尔CPU)您会注意到只INT $0x80适用于所有CPU(实际上,内核使其可用于遗留应用程序,即使还有更现代的替代方案); 然而,它也很慢.内核将探测引导时支持哪些内核,并选择使用最有效机制的VDSO版本.
因此,根据您的CPU型号,您可能会在VDSO中看到不同的代码 - 特别是,如果您有AMD CPU,您可能会看到SYSCALL路径,如果您有一个非常老的CPU,您甚至可能会看到INT $0x80路径.如果你对其他人感到好奇,这里是源代码:
INT $0x80 方法SYSCALL 方法SYSENTER方法 -阅读为什么意见%ecx,%edx和%ebp推最有可能的是,你实验室中得到不同结果的其他人有一个AMD CPU并且正在寻找SYSCALL路径(或者他们有一台古董PC,正在寻找INT $0x80路径).
另请注意,在64位进程中,SYSCALL将直接使用,而无需通过VDSO.