汇编器什么时候使用像 R_X86_64_32S 这样的符号扩展重定位而不是像 R_X86_64_32 这样的零扩展更好?

2024-01-08

举个具体的例子,在 GAS 2.24 上,移动地址:

mov $s, %eax
s:

After:

as --64 -o a.o a.S
objdump -Sr a.o

使用零扩展:

0000000000000000 <s-0x5>:
   0:   b8 00 00 00 00          mov    $0x0,%eax
                        1: R_X86_64_32  .text+0x5

但是内存访问:

mov s, %eax
s:

编译为签名扩展:

0000000000000000 <s-0x7>:
   0:   8b 04 25 00 00 00 00    mov    0x0,%eax
                        3: R_X86_64_32S .text+0x7

在这种特定情况下或一般情况下使用是否有理由?我不明白汇编器如何对这两种情况做出更好的假设。

NASM 2.10.09 只是使用R_X86_64_32对于上述两者。更新:2.11 之后的边缘 nasm 提交 6377180 产生相同的 Gas 输出,正如 Ross 提到的,这似乎是一个错误。

我已经解释了我认为我理解的内容R_X86_64_32S at: https://stackoverflow.com/a/33289761/895245 https://stackoverflow.com/a/33289761/895245


区别在于符号允许的地址s。在第一种情况下,使用 R_X86_64_32,符号必须在 0x00000000'00000000 到 0x00000000'FFFFFFFF 的范围内。在 R_X86_64_32S 的第二种情况下,符号的地址必须在 0xFFFFFFFF'80000000 和 0x00000000'7FFFFFFF 之间。如果s最终的地址超出了这些范围,那么链接器将给出错误。

这对应于 CPU 如何解释 32 位值s编码成两条指令。在第一条指令中,它是立即操作数,32 位值被零扩展到 RAX。在第二条指令中,32 位值是内存操作数中的位移,因此经过符号扩展以形成 64 位地址。

NASM 不应为第二条指令使用无符号 R_X86_64_32 重定位。这不是哪个更好的问题,这里使用 R_X86_64_32 根本就是不正确的。 NASM 将允许地址s为 0x00000000'80000000,但 CPU 最终会访问 0xFFFFFFFF'80000000。

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

汇编器什么时候使用像 R_X86_64_32S 这样的符号扩展重定位而不是像 R_X86_64_32 这样的零扩展更好? 的相关文章

  • x86 实模式下的段大小

    我对实模式下段的大小有一个疑问 因为它们不能超过 64K 但可以小于那个 http support microsoft com kb 120069 我的问题是这些段大小和基地址是如何初始化的 就像保护模式下有 GDT 和 LDT 一样 实模
  • 我试图在 AAM 指令之后使用 AX 中存储的值将其除以 2,为什么它不适用于 2 位数字输出?

    英语不是我的母语 请原谅输入错误 我将在此处显示的代码是一项作业 我真的需要了解发生了什么事 我在 DosBox 0 74 和 TASM 汇编器中使用 Intel 8086 语法 当我必须除以 2 时 代码的问题在于三角形的面积 注意 程序
  • elf .rel.text 部分中 R_386_32/R_386_PC32 的含义

    为了理解重定位的概念 我编写了一个简单的 chk c 程序 如下所示 1 include
  • 汇编编程语言:程序仅当输入为 ESC 时退出,并在退出前要求确认(y/n),否则循环

    我只是汇编语言编程的初学者 我们的第一个任务是让程序仅在输入为 ESC 时退出 退出之前请求确认 y n 否则循环 我知道 ESC 在 ASCII 代码中具有等效值 但我对插入位置或是否需要添加更多内容感到困惑 请帮我 这是程序 model
  • ARM 调用约定是否允许函数不将 LR 存储到堆栈中?

    正如标题所示 我在理解 ARM 架构的调用约定时遇到问题 特别是 我仍然很难知道当你调用子程序时 LR 寄存器会发生什么 我认为 当您进入子程序时 处理 LR 寄存器的最明显 最安全的方法是将其存储到堆栈中 但该行为没有出现在文档中 因此我
  • 在 REP MOVSW 之前 PUSH CS / POP DS 的目的是什么?

    为什么在下面的代码中我们压入代码段 PUSH CS 然后将其弹出到数据段 POP DS 我将这些行明确指定为 line1 和 line2 请告诉我 MOVSW 在这里是如何工作的 IF HIGHMEMORY PUSH DS MOV BX D
  • 为什么我可以使用 ret 退出 main?

    我即将弄清楚程序堆栈到底是如何设置的 我了解到用以下方式调用该函数 call pointer 实际上等同于 mov register pc programcounter add register 1 where 1 is one instr
  • 一条指令可以同时处于两种寻址模式吗?

    我在书中读到了以下内容从头开始编程 处理器有多种不同的访问数据的方式 称为 寻址模式 最简单的模式是立即模式 其中 要访问的数据嵌入在指令本身中 例如 如果我们想将寄存器初始化为 0 而不是给出 计算机要从中读取 0 的地址 我们将指定立即
  • 遍历内存编辑每个字节

    我正在编写汇编代码 提示用户输入一串小写字符 然后输出包含所有大写字符的相同字符串 我的想法是迭代从特定地址开始的字节 并从每个字节中减去 20H 将小写变为大写 直到到达具有特定值的字节 我对 Assembly 相当缺乏经验 所以我不确定
  • AVX512 掩码寄存器(k1...k7)的 GNU C 内联 asm 输入约束?

    AVX512 为其算术命令引入了 opmask 功能 一个简单的例子 上帝螺栓 org https godbolt org z P7xWD8 include
  • 汇编-符号标志和奇偶校验标志

    我不明白什么时候设置标志标志 什么时候设置奇偶校验 据我所知 符号标志表示运算结果的符号 0表示正数 1表示负数 那么为什么在下一个代码中 mov al 5 sub al 124 SF为零 结果是负数 关于PF 为什么a和b中设置了PF a
  • 取消的分支与常规分支有何不同?

    特别是对于 SPARC Assembly 取消的分支与常规分支有何不同 我一直认为 当我需要填充分支指令的 nop 延迟槽时 需要取消分支指令 但是 我认为我在这一部分上是不正确的 因为您可以在不取消分支的情况下填充 nop 如果不采用分支
  • 为什么不能执行 mov [eax], [ebx] [重复]

    这个问题在这里已经有答案了 我可以做这个 mov eax ebx 和这个 mov eax ebx 甚至这个 mov eax ebx 但不是这个 错误C2415 mov eax ebx 只是wtf 为什么 它与 ptr1 ptr2 相同 为什
  • 在linux x86平台上学习ARM所需的工具[关闭]

    Closed 此问题正在寻求书籍 工具 软件库等的推荐 不满足堆栈溢出指南 help closed questions 目前不接受答案 我有一个 x86 linux 机器 在阅读一些关于 ARM 的各种信息时 我很好奇 现在我想花一些时间学
  • 如何手动加载并执行 ELF 二进制可执行文件?

    假设二进制文件是PIC 如何将其加载到内存并执行入口点 我这样做是为了熟悉 ELF 所以execve不允许 这些是基本步骤 阅读程序头以查找 LOAD 指令并确定您需要的映射的总长度 以页为单位 将最低地址的 LOAD 指令映射到总长度 可
  • 为什么 RISC-V S-B 和 U-J 指令类型以这种方式编码?

    我正在读一本书 计算机组织与设计RISC V版 我遇到了 S B 和 U J 指令类型的编码 我上面提到的那些类型有奇怪的编码立即字段 S B 类型将直接字段分为两部分 这是有道理的 因为所有指令编码都必须相似 但我无法理解为什么立即字段以
  • 两个基本的 ANTLR 问题

    我正在尝试使用 ANTLR 来获取简单的语法并生成汇编输出 我在 ANTLR 中选择的语言是 Python 许多教程看起来非常复杂或详细阐述与我无关的事情 我真的只需要一些非常简单的功能 所以我有两个问题 将值从一个规则 返回 到另一规则
  • 为什么 GCC 不将 a*a*a*a*a*a 优化为 (a*a*a)*(a*a*a)?

    我正在对科学应用程序进行一些数值优化 我注意到的一件事是 GCC 会优化调用pow a 2 通过将其编译成a a 但是调用pow a 6 没有优化 实际会调用库函数pow 这大大降低了性能 相比之下 英特尔 C 编译器 http en wi
  • 页面错误陷阱的成本

    我有一个应用程序 它定期 每 1 或 2 秒后 通过分叉自身来获取检查点 因此 检查点是原始进程的一个分支 它一直保持空闲状态 直到原始进程发生某些错误时被要求启动 现在我的问题是fork的写时复制机制的成本有多大 每当原始进程写入内存页面
  • 为什么当大小大于 50 时,该程序花费的时间会呈指数级增长?

    所以我正在为类编写一个 ARM 汇编快速排序方法 我对大部分内容都有了解 除了复杂性没有意义 我们将其与我们制作的另一种冒泡排序方法进行比较 它对于具有 1 个参数和 10 个参数的示例表现更好 然而 我什至无法比较 100 个参数测试 因

随机推荐