【问题标题】:ARM endianness and byte ordering for .ascii vs .word.ascii 与 .word 的 ARM 字节顺序和字节顺序
【发布时间】:2023-04-06 20:30:01
【问题描述】:

我刚开始学习 ARM 汇编。我目前正在使用“GNU assembler version 2.35.2 (arm-linux-gnueabihf)”的 32 位 Raspian。

这是我将部分 ascii 加载到寄存器中的简单程序:

.global _start
_start:
    ldr r1,=helloworld
    ldr r2,[r1]

    @prepare to exit
    mov r0,#0
    mov r7,#1
    svc 0

.data
helloworld:
    .ascii "HelloWorld"

我将它加载到 gdb 中,可以看到我的寄存器 r2 加载了0x6c6c6548(在 ascii "lleH" 中)。一个快速的 objdump 显示:

Contents of section .data:
 0000 48656c6c 6f576f72 6c64               HelloWorld

我有以下问题:

  1. 字符串在内存中的样子如何?换句话说,当字节序出现时?加载到内存时会发生反转吗?或者字符串会按原样加载到内存中,但在加载到寄存器时会反转?
  2. 为什么下面程序.word的寄存器r2的内容是0x12345678而不是0x78563412?为什么没有遵循字节顺序?

注意:使用.word 代替.ascii

.global _start
_start:
    ldr r1,=helloworld
    ldr r2,[r1]
    mov r0,#0
    mov r7,#1
    svc 0

.data
helloworld:
    .word 0x12345678

编辑

第一个程序的内存转储显示,即使内存也有字符串,其顺序与源代码和目标文件中的顺序相同:

>>> x/32xb 0x1008c
0x1008c:    0x48    0x65    0x6c    0x6c    0x6f    0x57    0x6f    0x72
0x10094:    0x6c    0x64    0x41    0x11    0x00    0x00    0x00    0x61

这表明ldr 指令正在将该内存读取转换为 LSB 保存内存中第一个字节的小端格式。理解是否正确?但这仍然不能回答为什么 .word 没有发生这种情况。

【问题讨论】:

  • 字节从不反转。像最高有效字节是“第一个字节”一样读取寄存器的值会使字节看起来好像颠倒了,但这只是您读取它们的方式的影响。

标签: assembly arm cpu-architecture endianness


【解决方案1】:

.ascii 是一串字节 .word 是 32 位项目的列表,而不是 8 位项目,它们是无法比较的。您可能想要 .byte 吗?

.ascii "Hello"
.align
.word 0x12345678
.byte 0x12,0x34,0x56,0x78

组装和拆卸

00000000 <.text>:
   0:   6c6c6548    cfstr64vs   mvdx6, [ip], #-288  ; 0xfffffee0
   4:   0000006f    andeq   r0, r0, pc, rrx
   8:   12345678    eorsne  r5, r4, #120, 12    ; 0x7800000
   c:   78563412    ldmdavc r6, {r1, r4, sl, ip, sp}^

链接,复制到二进制文件并转储

00000000  48 65 6c 6c 6f 00 00 00  78 56 34 12 12 34 56 78 |Hello...xV4..4Vx|
00000010

到目前为止,一切都符合预期,这并不奇怪。 ascii 字符串是一串字节,我们按照声明它们的顺序查看它们。 word 是 word,这是一个 little endian 目标,0x12345678,0x78 是最低有效字节,所以它首先在最低地址。为了比较 .ascii 苹果和苹果,我们需要一个字节串,所以首先声明 0x12 就像首先声明 'H' 所以我们首先在内存中看到它。

ldr r0,label0
ldr r1,label1

.ascii "Hello"
.align
label0:
.word 0x12345678
label1:
.byte 0x12,0x34,0x56,0x78

组装和拆卸

00000000 <label0-0x10>:
   0:   e59f0008    ldr r0, [pc, #8]    ; 10 <label0>
   4:   e59f1008    ldr r1, [pc, #8]    ; 14 <label1>
   8:   6c6c6548    cfstr64vs   mvdx6, [ip], #-288  ; 0xfffffee0
   c:   0000006f    andeq   r0, r0, pc, rrx

00000010 <label0>:
  10:   12345678    eorsne  r5, r4, #120, 12    ; 0x7800000

00000014 <label1>:
  14:   78563412    ldmdavc r6, {r1, r4, sl, ip, sp}^

再次不足为奇。 DISASSEMBLER 试图将这些字节转换为指令并将它们显示为单词,因此我们分别看到 0x12345678 和 0x78563412,这些值将落在 r0 和 r1 中

链接并复制到二进制和十六进制转储-C

00000000  08 00 9f e5 08 10 9f e5  48 65 6c 6c 6f 00 00 00  |........Hello...|
00000010  78 56 34 12 12 34 56 78                           |xV4..4Vx|
0

而且我们没有改变任何东西,所以输出不会改变数据项。

【讨论】:

    【解决方案2】:

    字节序或字节顺序是组成数字的字节在内存中的表示顺序。

    字符串是一个字节数组。该字符串的每个字节都受字节序的影响,但对于单个字节,小字节序和大字节序得出相同的结果。

    对于第二个问题:字节序仅影响存储在内存中的数据。汇编器为您提供计算机程序的人类可读表示。令牌0x12345678 代表某个数字。当传输到内存时,此令牌将按适当的字节顺序写入内存。汇编器会处理这个。

    在调试器中观看程序执行时,您还将看到寄存器内容为0x12345678。这是因为寄存器不是内存的一部分,也不是按字节划分的。每个寄存器保存一个 32 位数字。 CPU 以配置的字节顺序在寄存器和内存之间传输数据(请参阅SETEND 指令)并且如果没有将寄存器划分为字节,就没有有意义的方式为其分配字节顺序。调试器只能显示它的数值。这就是您在程序中分配给它的值。太疯狂了,嗯?

    【讨论】:

    • 谢谢。我知道寄存器不是字节可寻址的(但可以是字节可访问的)。我为第一个程序创建了我的目标文件的hexdump,可以看到与字符串顺序相同的48 65 6C 6C 6F 57 6F 72 6C 64(对于HelloWorld)。但是对于第二个程序的目标文件,我看到了78 56 34 12。所以看起来汇编器已经反转了.word。现在目标文件的内容按原样加载到内存中。当我使用像ldr 这样的指令时,cpu 以字节为单位将数据从内存读取到寄存器中,因此将第一个字节读入 lsb,然后读取下一个字节,依此类推,直到 msb 产生 4 个字节。
    • 这样,我们间接加载了数字0x12345678,按照源文件中的正确顺序。我的这种理解正确吗?
    • @Naveen 在 x86 上这是正确的,但它仍然不能真正指示寄存器的字节顺序。您只需为寄存器的特定部分指定一个特定名称,但由于没有指令来索引寄存器文件,因此实际上没有字节顺序。
    • 有人可能会争辩说存在字节顺序,例如使用 SIMD 寄存器,其中存在 TBL 之类的查表指令,但字节顺序与这些指令完全隔离,并且某些架构(如 PowerPC)具有小端和大端字节序的查表指令。
    • @Naveen: re: register endianness: it's more clear-cut for vectors, as fuz said: 它们在运行时是可索引的,而且 SIMD 元素内的位移可以跨越连接的边界移动位它们一起变成更大的整数。见How does endianness work with SIMD registers?。您可以对 RAX 进行位移,然后访问 AL 和 AH,因此很明显 AL 是最低有效字节,但它没有地址;以任何其他方式公开顺序的唯一方法是通过 AX、EAX 或 RAX 的单词、dword 或 qword 存储的字节顺序。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2019-09-21
    • 2010-11-14
    • 2014-05-18
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多