MARS MIPS 模拟器的内置汇编器比要求的对齐程度更高?

2023-12-11

我有以下数据段

.data
a:  .byte   0x11
    .align  1
b:  .word   0x22334455

假设地址“a”为 0x10010000,则 b 处字的预期地址为 0x10010002,但 MARS 将字存储在 0x10010004,忽略显式“.align”指令。顺便说一句,我使用 MARS MIPS 模拟器(MacBook Pro 上的版本 4.5)来汇编上述代码。

因此,我的问题是:这是一个错误,还是预期 MARS 的行为与 SGI 1992 年的 MIPS 汇编语言文档不同,例如本 Pascal / 装配手册第 8-1 页?

(MARS 和非 MARS MIPS asm 文档同意.align在 MIPS 语法中采用 2 的幂 arg,所以.align 1与 2^1 = 2 字节边界对齐。与其他一些架构的 GAS / Unix 汇编语法不同,其中.align= 字节对齐,其中 arg 为1会是多余的。)


TL:DR:MARS 工具提示具有误导性;您需要使用以下命令禁用该部分其余部分的自动对齐.align 0。你不能just下一个单词对齐不足。


.align 1确实按2对齐,这不是问题。例如尝试一下之间.byte or .ascii伪指令。

例如该源生成 0x00110062 作为 .data 部分的第一个字,就像.byte 'b', 0, 0x11, 0 would.

.data
  a:   .ascii "b"
  b:
      .align 1
      .byte   0x11

And the b:标签有地址2, after对齐填充。

(我将 MARS 设置为“紧凑”内存布局,数据部分从地址开始0为了简单起见。)


到目前为止我们所看到的确实与您为其​​ Unix 汇编器链接的 Silicon Graphics 文档相匹配。 (这与 GNU 等现代汇编器的方式非常不同as(又名 GAS)和 clang 工作。)

SGI 文档说:

前进位置计数器以使表达式低阶 计数器零的位。通常情况下,.half, .word, .float, and .double指令会自动适当地对齐其数据。为了 例子,.word执行隐式 .align 2 (.double执行 .align 3)。您可以使用以下命令禁用自动对齐功能.align 0。这 汇编器在下一次恢复自动对齐.text, .data, .rdata, or .sdata指示。

紧邻自动或显式对齐之前的标签 也进行了重新调整。例如,foo: .align 3; .word 0是一样的 作为.align 3; foo: .word0.

这并没有说明有关使用的任何内容.align 1 to under- 对齐下一个.word。只是您可以完全关闭隐式对齐作为数据指令的一部分.align 0。拥有.align 1覆盖并欠对齐下一个.word不必禁用自动对齐本来是有意义的并且是一个有效的设计,但这不是他们选择实现的功能。

(注意.align 0很特别:按 1 字节对齐永远不需要插入任何填充;当前位置始终是字节边界。因为没有理由使用.align 0为了对齐单个位置,语法的设计者可以用不同的含义重载它:禁用自动对齐。)

MARS 确实支持这一点。 (And then .align 1会做你所期望的,对齐到 2^1 = 2 没有隐式.align 2作为...的一部分.word之后增加对齐。)

a:   .byte 1
 .align 1
b:
 .align 0              # on this line or any earlier line
 .word   0x22334455

 .word   0x66666666    # this word is also misaligned; auto-align is disabled

数据部分输出:

0x44550001    0x66662233    0x00006666     as little-endian words
01 00 55 44   33 22 66 66   66 66 00 00    as bytes

是的,.align(明确地或作为.word) 不只是在当前位置插入填充,它还插入它before任何前面的标签,就在最后一条数据之后。

您当然可以使用发出任何您想要的数据.byte or .half如果您确实想避免隐式对齐 4 字节边界而不禁用自动对齐,请使用指令。您通常实际上并不想要这样,并且在大多数情况下它可以帮助初学者避免遇到对齐问题。 MIPS 是一种高度面向字的 ISA,因此通常没有理由出现未对齐的情况.word.

我看到的唯一 MARS 错误是可用性:一个非常具有误导性的工具提示。

目前它说在指定字节边界上对齐下一个数据项:(0=字节、1=半、2=字、3=双)。这似乎意味着您可以未对齐.word。这是非常具有误导性的.align 0这实际上禁用了该部分其余部分的自动对齐。


这不是如何.align适用于使用 GAS 语法(GNUas或叮当声)。(例如,参见气体手册)

在我的 Linux 桌面上,我使用以下命令组装了源代码clang -c -target mipsel mips-align.s(“mipsel”是 Little-Endian MIPS,与 MARS 使用的相同。)

然后我使用 llvm-objdump 转储 .data 部分(使用“反汇编”,因为这是最简单的方法,尽管我必须清理不从字边界开始的 b: 标签的重叠部分。)

$ llvm-objdump -D mips-align-clang-output.o         
00000000 a:
       0: 11 00                # manually cleaned up this line
00000002 b:
       2: 55 44 33 22                   addi    $19, $17, 17493

注意b有地址2, not 4。 (这是一个未链接的.o;当链接到可执行文件时,地址会更高。静态地用于位置相关的可执行文件,或者仅在运行时的 PIE)

在 GAS 语法中,.align只需插入填充在那个位置直到到达对齐边界。所以你通常想要放置这样的指令before标签,因此标签地址对齐并位于填充之后。也没有隐含的.align作为其他指令的一部分。

MARS(和老式 SGI)的行为对我来说听起来有点像“训练轮”,但我想这对于像 MIPS 这样的严重面向字的 ISA 来说是有意义的。这可以解释为什么我在 SO 上看到过一些代码.asciz其次是.word加载/存储到单词时不会出现对齐错误!不过,让汇编器为您计算字符串常量的长度也有缺点:


如果 MARS 的内置汇编器允许你这样做msg_len = msg_end - msg(从末尾和开头减去标签.ascii例如,就像在 GAS 或 NASM 语法中一样),移动前面的标签可能会破坏.word在一个字符串之后。 (通过在字符串循环的长度计算中包含填充。)

但是 MARS 的汇编器太糟糕了,无法让您在汇编时计算尺寸,因此追溯移动较早的标签通常不是问题。我不确定经典的 MIPS 汇编器是否允许您在汇编时减去本地标签以获得恒定的长度(例如addiu $t0, $zero, end-start) 或不。 MARS 不会,所以这个奇怪的(如果你习惯了现代汇编器)“错误”功能通常不会导致这个问题,除非你la将开始和结束标签放入寄存器中,以便在指针增量循环中使用bne循环条件。

硬编码是愚蠢的,当汇编器让你这样做时(通过不提供良好的label - label特征。)

看起来 MARS 只是从 SGI 的汇编器(或者这个设计决策最初来自的地方)继承了这个错误特征。

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

MARS MIPS 模拟器的内置汇编器比要求的对齐程度更高? 的相关文章

  • 近调用/跳转表并不总是在引导加载程序中工作

    一般问题 我一直在开发一个简单的引导加载程序 并在某些环境中偶然发现了一个问题 在这些环境中 此类指令不起作用 mov si call tbl SI Call table pointer call call tbl Call print c
  • 在 x86-64 CPU 上通过交叉修改代码重现意外行为

    Question 对于可能在 x86 或 x86 x64 系统上触发意外行为的交叉修改代码有哪些想法 在这些系统中 交叉修改代码中的所有操作均已正确完成 但在执行处理器之前执行序列化指令除外修改代码 如下所述 我有一个 Core 2 Duo
  • 为什么当大小大于 50 时,该程序花费的时间会呈指数级增长?

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

    我正在使用 Easy 68K 模拟器创建一个简单的黑杰克游戏 需要使用随机数来分配牌 我的牌必须在 2 到 11 的范围内 我似乎每次都得到相同的数字 但它不在我预期的范围内 我的卡值需要以 D3 结束 因此我有以下随机数代码 CLR L
  • __declspec(align) 用于多个声明

    抱歉 这个非常简单的问题 无法在谷歌上找到答案 这个声明语法是 declspec align 16 float rF 4 declspec align 16 float gF 4 declspec align 16 float bF 4 相
  • 寄存器寻址模式与直接寻址模式

    我在试卷中遇到过这个问题 它指出 哪种给定的寻址模式更快 为什么 寄存器寻址方式 直接寻址方式 现在根据我的说法 寄存器寻址模式应该更快 因为寄存器是计算机中最快的存储位置 这是正确答案吗 请帮忙 谢谢 两种寻址模式之间的区别是 地址的来源
  • 程序集比较标志理解

    我正在努力理解汇编程序中的以下代码片段 if EAX gt 5 EBX 1 else EBX 2 在汇编程序中 可以写如下 根据我的书 模拟jge操作说明 https www felixcloutier com x86 jcc您通常会使用
  • 阴影空间示例

    EDIT 我接受了下面的答案 并添加了我自己的代码的最终修订版 希望它向人们展示影子空间分配的实际示例 而不是更多的文字 编辑 2 我还设法在 YouTube 视频 所有内容 的注释中找到了一个调用约定 PDF 的链接 其中有一些关于 Li
  • std::aligned_alloc() 的重新分配等效项是什么?

    我发觉到std aligned alloc https en cppreference com w cpp memory c aligned alloc进入 C 17 我喜欢它 但是 当我需要重新分配时会发生什么 我可以手动执行此操作 假设
  • 如何在 icarus verilog 中包含文件?

    我知道基本的 include filename v 命令 但是 我试图包含另一个文件夹中的模块 现在 该模块还包括同一文件夹中存在的其他模块 但是 当我尝试在最顶层运行该模块时 出现错误 C Users Dell Desktop MIPS
  • AVX-512 指令编码 - {er} 含义

    在 Intel x86 指令集参考中 有许多 AVX 512 指令在指令中具有可选的 er 例如 VADDPD 的一种形式定义为 EVEX NDS 512 66 0F W1 58 r VADDPD zmm1 k1 z zmm2 zmm3 m
  • 设置 IRQ 映射

    我正在遵循一些教程和参考文献来尝试设置我的内核 我在教程中遇到了一些不熟悉的代码 但根本没有解释它 这是我被告知映射的代码16 IRQs 0 15 到 ISR 地点32 47 void irq remap void outportb 0x2
  • 这个反斜杠在这段汇编代码中起什么作用?

    我不确定这些推线有什么区别 修剪下来来自 Linux 的 x86 entry calling h https github com torvalds linux blob 241e39004581475b2802cd63c111fec43b
  • 如何编译GCC生成的asm?

    我正在玩一些汇编代码 有些事情困扰着我 我编译这个 include
  • 为什么 FMA _mm256_fmadd_pd() 内在函数有 3 个 asm 助记符:“vfmadd132pd”、“231”和“213”?

    有人可以向我解释一下为什么融合乘法累加指令有 3 种变体 vfmadd132pd vfmadd231pd and vfmadd213pd 而只有一个 C 内在函数 mm256 fmadd pd 为了简单起见 在 AT T 语法中 有什么区别
  • GCC的sqrt()编译后如何工作?使用哪种root方法?牛顿-拉夫森?

    只是对标准感到好奇sqrt 来自 GCC 上的 math h 我自己编码的sqrt 使用牛顿拉夫森来做到这一点 是的 我知道 fsqrt 但CPU是如何做到这一点的呢 我无法调试硬件 现代 CPU 中的典型 div sqrt 硬件使用 2
  • 在 x86 汇编中将 64 位常量移至内存

    我正在使用 Intel x64 程序集 NASM 编译器 尝试将 0x4000000000000000 常量移至内存 该常量在 ieee 754 标准双精度中应等于 2 0 我正在使用的代码是 define two 0x4000000000
  • 从类模板参数为 asm 生成唯一的字符串文字

    我有一个非常特殊的情况 我需要为类模板中声明的变量生成唯一的汇编程序名称 我需要该名称对于类模板的每个实例都是唯一的 并且我需要将其传递给asm关键字 see here https gcc gnu org onlinedocs gcc 12
  • 将字段中的位扩展到掩码中所有(重叠+相邻)集位的最快方法?

    假设我有 2 个名为 IN 和 MASK 的二进制输入 实际字段大小可能是 32 到 256 位 具体取决于用于完成任务的指令集 每次调用时两个输入都会改变 Inputs IN 1100010010010100 MASK 000111101
  • Intel:序列化指令和分支预测

    英特尔架构开发人员手册 http www intel com content www us en architecture and technology 64 ia 32 architectures software developer v

随机推荐