Warm tip: This article is reproduced from serverfault.com, please click

assembly-如何使用objdump查找导致崩溃的指令

(assembly - How to find the instruction causing crash using objdump)

发布于 2020-12-02 16:24:44

嗨,我正在做有关使用Pintos的操作系统的作业。我被要求在一项测试中找到错误的说明。测试框架期望Pintos输出“什么都不做:exit(162)”。这是进程退出时Pintos打印的标准消息。但是,Pintos没有输出此消息。相反,由于内存访问冲突(分段错误),无所事事程序在用户空间中崩溃了。

#include "tests/lib.h"

int
main (int argc UNUSED, char *argv[] UNUSED)
{
  return 162;
}

我调查了这个测试的结果,

FAIL
Test output failed to match any acceptable form.

Acceptable output:
  do-nothing: exit(162)
Differences in `diff -u' format:
- do-nothing: exit(162)
+ Page fault at 0xc0000008: rights violation error reading page in user context.
+ do-nothing: dying due to interrupt 0x0e (#PF Page-Fault Exception).
+ Interrupt 0x0e (#PF Page-Fault Exception) at eip=0x8048757
+  cr2=c0000008 error=00000005
+  eax=00000000 ebx=00000000 ecx=00000000 edx=00000000
+  esi=00000000 edi=00000000 esp=bfffffe4 ebp=00000000
+  cs=001b ds=0023 es=0023 ss=0023

问题:

  1. 程序尝试从导致用户崩溃的用户空间访问哪个虚拟地址? 答:从结果文件来看,我认为是0xc000008
  2. 导致崩溃的指令的虚拟地址是什么? 答:eip = 0x8048757,它是指令的虚拟地址。
  3. 要进行调查,请使用objdump反汇编“什么都不做”的二进制文件。程序崩溃时所在的函数的名称是什么?将该函数的反汇编代码复制到Gradescope上,并确定程序崩溃所在的指令。

我不知道如何找到3.问题的答案,“ objdump -S do-nothing.o”的输出非常简单:

Disassembly of section .text:

00000000 <main>:

int
main (int argc UNUSED, char *argv[] UNUSED)
{
  return 162;
}
   0:   b8 a2 00 00 00          mov    $0xa2,%eax
   5:   c3                      ret    

A:

void
_start (int argc, char *argv[])
{
 8048754:   83 ec 1c                sub    $0x1c,%esp
  exit (main (argc, argv));
 8048757:   8b 44 24 24             mov    0x24(%esp),%eax
 804875b:   89 44 24 04             mov    %eax,0x4(%esp)
 804875f:   8b 44 24 20             mov    0x20(%esp),%eax
 8048763:   89 04 24                mov    %eax,(%esp)
 8048766:   e8 35 f9 ff ff          call   80480a0 <main>
 804876b:   89 04 24                mov    %eax,(%esp)
 804876e:   e8 49 1b 00 00          call   804a2bc <exit>
  1. 查找上面确定的功能的C代码。对于#3中反汇编函数中的每条指令,请用几句话来解释为什么有必要和/或想做什么。
#include <syscall.h>

int main (int, char *[]);
void _start (int argc, char *argv[]);

void
_start (int argc, char *argv[])
{
  exit (main (argc, argv));
}
  1. 为什么你在#3中标识的指令想在你在#1中标识的虚拟地址处访问内存?不要用寄存器的值来解释。我们正在寻找更高级的解释。 答:我发现了错误的指示,但我更加困惑,
8048757:    8b 44 24 24             mov    0x24(%esp),%eax

**为什么该指令会导致分段错误?**

sub    $0x1c,%esp
mov    0x24(%esp),%eax

首先,它分配了一些堆栈空间(0x1c),然后将参数argv移至0x24(%esp)[在更改堆栈指针之前为0x8]到%eax,为什么这个简单的指令会导致分段错误?

Questioner
badtastetea
Viewed
0
238k 2020-12-18 16:20:20

我不是PintOS的专家,但是我可以提供一些见解。你正在目标文件(.o上使用OBJDUMP 这些是未链接的ELF对象文件,没有任何VMA(虚拟内存地址)起点(也称为起点),并且在每个PintOS程序中均不包含任何用户模式运行时代码。诸如C启动之类的事情,它会设置用户模式应用程序,并main使用argcargv参数在处启动代码

你需要执行的操作是使用常规PintOS构建过程将目标文件构建到用户模式程序中。userland可执行文件的名称.o与已.o删除文件的名称相同do-nothing是可执行文件的名称,看起来它们可以在目录中找到pintos/src/userprog/build/tests/userprog/在此可执行文件上运行OBJDUMP,搜索地址0x8048757。你应该能够轻松地找到函数名称和所有代码。有了这些信息,你应该能够回答第三个问题。你对问题1和2的答案是正确的。