【问题标题】:Assembly simple project, seg faulting组装简单的项目,段错误
【发布时间】:2016-03-03 20:33:53
【问题描述】:

我正在尝试为我的装配课做作业,老师的例子有一行

movl (%eax),%ebx

我的代码使用了完全相同的行,但是每当 gdb 到达它时,我就会遇到段错误。我不明白为什么。请帮我。这是完整的代码,在 32 位 Linux 上通过 QEMU 运行。

.text
.byte 12, 0x12, 012
.word 34, 0x34, 034
L1:
.long 23, 0x23, 023
.global _start
_start:
  # do not change, remove or add anything other than specifying the underscores
  movl $0x1700121C,%eax  #hex for 385880604
  movl (%eax),%ebx       #moving contents of eax into ebx, long to long
  movw 0x17,%bx          #attemtping to move via memory location (probably buggy)
  movb $0x12,%bh

  # at this point, %ebx should have the value of 385880604
checkHere:

  movl $1,%eax
  movl $0,%ebx
  int  $0x80

请帮忙。感谢您的宝贵时间。

【问题讨论】:

  • movl (%eax),%ebx%eax 中的任何内容视为指针,并检索该地址的 32 位值并将其放入 %ebx。如果0x1700121C 不是一个有效的指针(至少看起来不是),它将出现段错误。
  • 但是我们在上面一行中得到的代码是 movl $____,%eax 这不是说它必须是一个常数吗?
  • 是的,$ 意味着后面会跟着一个常量,但通常当涉及到指针时,它将是标签的名称。所以它将是$label,其中label 是您想要其地址(指针)的标签的名称。
  • 那我应该用 L1 替换 0x1700121C,你觉得呢?
  • 我没有完整的问题,所以知道 L1 是否正确我无法回答,但$L1 将是有效的语法。如果我们有完整的问题,那就更容易回答了。

标签: assembly x86 computer-science cpu-registers


【解决方案1】:

"movl $0x1700121C,%eax #hex for 385880604" 需要引用标签/内存地址。

【讨论】:

    【解决方案2】:

    此分配的目标是最终以给定值 (0x1700121C) 填充某个寄存器 (ebx)。

    当一个程序运行时,它可以被放置在内存中的任何位置,对于程序和它分配的内存(例如变量)。

    您告诉它查看绝对地址,这不是您想要的。您实际上并不知道您的程序及其分配的 RAM 字节在哪里结束。您想在此处使用相对地址。 (在后台,可执行文件头中的一些信息有助于实现这一点,如果您好奇的话)

    但是你如何获得相对地址呢?您可以利用L1。你不知道它的确切数字地址,但你知道它从.long 23 开始的任何地方开始。您可以在 L1 上进行数学运算以获取相对地址。由于内存中 L1 指向的任何位置之前都有一些字节,因此您需要减去。

    .words 是 2 个字节,其中有 3 个字节,再加上在那之前的 3 个字节,所以 L1 - 9 将您带到该数据的第一个字节。

    【讨论】:

    • 它实际上不是与位置无关的机器码。但是,它与位置无关的源代码,因此您在更改代码时不必修改常量:使用符号标签可以让链接器填写正确的绝对地址。可执行文件指定将它们映射到虚拟内存的位置。动态库确实需要使用与位置无关的代码(gcc -fPIC),这在 32 位模式下是相当大的负担。 64 位模式添加了 RIP 相对寻址,这使得 PIC 便宜。 (见this guide I wrote about addressing modes
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2022-08-10
    • 2015-10-31
    • 1970-01-01
    相关资源
    最近更新 更多