为什么我在跟踪 write() 时得到的结果与其他人不同?

发布于 2024-12-09 22:58:37 字数 2789 浏览 0 评论 0原文

我正在做一些 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    

这是我应该看到的吗?如果是的话,为什么和我一些同学看到的不一样? 在执行 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

以下说明适用于 Linux:

查找第二次调用 write,“call write”,在 secondaryCall 中 功能。在此行设置断点。据我所知是22。

在此行设置断点。

 break 22

在调试器中运行程序。

 run

程序将在您设置的断点处停止。 单步执行没有调试信息的代码。

  si 

您将在源布局中看到“[ 无可用源 ]”。所以你需要查看 拆解后的指令。

 layout asm

反复单步进入(si然后return/enter就会执行si命令 重复),直到您看到“sysenter”出现在屏幕的 asm 布局部分。 我试图将指令(包括它们的地址)从 asm 布局部分的顶部复制到并包括 sysenter 指令。

提示:您可以通过键入 Ctrl-x o 将键盘焦点更改到命令区域。这 方向键可用于返回较早的命令(它只是节省了一些 打字)。

I am doing some x86 exercises; my assignment has me stepping through the assembly code for the write() library call in a debugger until we reach a SYSENTER instruction, but I get different results from that of some of my classmates. What I saw leading up to SYSENTER was:

   │0xf7fdf421 <__kernel_vsyscall+1>        push   %edx                                                                                            
   │0xf7fdf422 <__kernel_vsyscall+2>        push   %ebp                                                                                            
   │0xf7fdf423 <__kernel_vsyscall+3>        mov    %esp,%ebp                                                                                       
   │0xf7fdf425 <__kernel_vsyscall+5>        sysenter    

Is this what I should see? If so, why is it different from what some of my classmates saw?
Also are %edx and %ebp registers saved on the stack before executing the sysenter instruction? (Would it not seem so according to the answer I got or am I wrong?)

Here's my original instructions from my assignment:

The assembly code:

.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

The following instructions are for Linux:

Find the line number of the second call to write, “call write”, in the secondCall
function. Set a break point at this line. Which is 22 according to me.

Set a break point at this line.

 break 22

Run the program inside the debugger.

 run

The program will stop at the break point you set.
Step into the code which does not have the debugging information.

  si 

You will see “[ No Source Available ]” in the source layout. So you need to view
the disassembled instructions.

 layout asm

Repeatedly step into (si and then return/enter will execute the si command
repeatedly) until you see “sysenter” appear in the asm layout section of the screen.
I am trying to copy the instructions (including their addresses) from the top of the asm layout section, down to and including the sysenter instruction.

Hint: You can change the focus of the keyboard to the command area by typing Ctrl-x o. This
way the arrow keys can be used to bring back earlier commands (it just saves some
typing).

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(1

来世叙缘 2024-12-16 22:58:37

您正在追踪所谓的“虚拟动态共享对象”(VDSO) - 其内容是 Linux 内核的实现细节。有多种情况会导致 VDSO 内容发生变化;因此这里没有单一的正确答案

特别是,在 32 位 x86 系统上,至少有三种不同的机制可用于进行系统调用:

  • INT $0x80
  • SYSCALL(最新的 AMD CPU)
  • SYSENTER(最新的 Intel CPU)

您会注意到,只有 INT $0x80 适用于所有 CPU(事实上,即使有更现代的替代方案,内核也使其可用于遗留应用程序)也可用);然而,它也很慢。内核将在启动时探测支持哪些版本,并选择使用最有效机制的 VDSO 版本。

因此,根据您的 CPU 型号,您可能会在 VDSO 中看到不同的代码 - 特别是,如果您有 AMD CPU,您可能会看到 SYSCALL 路径,如果您有对于非常旧的 CPU,您甚至可能会看到 INT $0x80 路径。如果您对其他内容感到好奇,这里是源代码:

最有可能的是,您实验室中获得不同结果的其他人拥有 AMD CPU,并且正在查看 SYSCALL 路径(或者他们有一台古董 PC,并且正在查看 <代码>INT $0x80路径)。

另请注意,在 64 位进程中,将直接使用 SYSCALL,根本不经过 VDSO。

You are tracing into what is called the 'virtual dynamic shared object' (VDSO) - the contents of which are an implementation detail of the linux kernel. There are a number of conditions that can cause the contents of the VDSO to change; as such there is no single correct answer here.

In particular, on 32-bit x86 systems, there are at least three different mechanisms that can be used to make a system call:

  • INT $0x80
  • SYSCALL (recent AMD CPUs)
  • SYSENTER (recent Intel CPUs)

You'll note that only INT $0x80 works on all CPUs (indeed, the kernel makes it available for legacy applications even when more modern alternatives are also available); however, it's also slow. The kernel will probe for which are supported at boot time, and select a version of the VDSO that uses the most efficient mechanism available.

As such, depending on your CPU model, you may see different code in the VDSO - in particular, if you have an AMD CPU, you're likely to see the SYSCALL path, and if you have a really old CPU you might even see the INT $0x80 path. If you're curious about the others, here's the source code:

Most likely, the other folks in your lab who got a different result had an AMD CPU and were looking at the SYSCALL path (or they had an antique PC, and were looking at the INT $0x80 path).

Note also that in a 64-bit process, SYSCALL will be used directly, without going through the VDSO at all.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文