英文:
How does the arm-none-eabi-as choose section alignment?
问题
我正在使用 arm-none-eabi-as
进行实验,试图理解它如何对齐各个段。我有以下的源代码:
; source.s
.text
.byte 0xff
.byte 0xff
.byte 0xff
我正在检查生成的目标文件:
$ arm-none-eabi-as -mthumb -o source.o source.s
$ arm-none-eabi-readelf -S source.o
有 8 个段头,从偏移量 0xec 开始:
段头:
[Nr] 名称 类型 地址 偏移 大小 ES Flg Lk Inf Al
[ 0] NULL 00000000 000000 000000 00 0 0 0
[ 1] .text PROGBITS 00000000 000034 000003 00 AX 0 0 1
[ 2] .data PROGBITS 00000000 000037 000000 00 WA 0 0 1
[ 3] .bss NOBITS 00000000 000037 000000 00 WA 0 0 1
[ 4] .ARM.attributes ARM_ATTRIBUTES 00000000 000037 000014 00 0 0 1
[ 5] .symtab SYMTAB 00000000 00004c 000060 10 6 6 4
[ 6] .strtab STRTAB 00000000 0000ac 000004 00 0 0 1
[ 7] .shstrtab STRTAB 00000000 0000b0 00003c 00 0 0 1
.text
段是字节对齐的,并包含了 3 个字节。
现在,我在 source.s
中添加了一条指令:
; source.s
.text
.byte 0xff
nop
.byte 0xff
.byte 0xff
查看目标文件,突然之间 .text
段变成了半字对齐:
有 8 个段头,从偏移量 0x114 开始:
段头:
[Nr] 名称 类型 地址 偏移 大小 ES Flg Lk Inf Al
[ 0] NULL 00000000 000000 000000 00 0 0 0
[ 1] .text PROGBITS 00000000 000034 000006 00 AX 0 0 2
[ 2] .data PROGBITS 00000000 00003a 000000 00 WA 0 0 1
[ 3] .bss NOBITS 00000000 00003a 000000 00 WA 0 0 1
[ 4] .ARM.attributes ARM_ATTRIBUTES 00000000 00003a 000014 00 0 0 1
[ 5] .symtab SYMTAB 00000000 000050 000080 10 6 8 4
[ 6] .strtab STRTAB 00000000 0000d0 000007 00 0 0 1
[ 7] .shstrtab STRTAB 00000000 0000d7 00003c 00 0 0 1
是什么导致汇编器在第二种情况下决定对段进行填充呢?我感到困惑,因为:
- 如果段是
.data
,那么汇编器不会填充它,这是有道理的,但是 - 即使段是
.text
,只有在看到一条指令时汇编器才会填充它(我可以有很多数据指令,除非也有指令,否则段不会填充),最后 nop
指令明显不是对齐的,但汇编器却没有问题,但它仍然决定关注段的对齐。
在这里,汇编器是如何决定填充的?
我能否强制汇编器不填充 .text
段,即使我有一条指令?
英文:
I am playing with arm-none-eabi-as
trying to understand how it aligns sections. I have the following source:
; source.s
.text
.byte 0xff
.byte 0xff
.byte 0xff
I am inspecting the resulting object file:
$ arm-none-eabi-as -mthumb -o source.o source.s
$ arm-none-eabi-readelf -S source.o
There are 8 section headers, starting at offset 0xec:
Section Headers:
[Nr] Name Type Addr Off Size ES Flg Lk Inf Al
[ 0] NULL 00000000 000000 000000 00 0 0 0
[ 1] .text PROGBITS 00000000 000034 000003 00 AX 0 0 1
[ 2] .data PROGBITS 00000000 000037 000000 00 WA 0 0 1
[ 3] .bss NOBITS 00000000 000037 000000 00 WA 0 0 1
[ 4] .ARM.attributes ARM_ATTRIBUTES 00000000 000037 000014 00 0 0 1
[ 5] .symtab SYMTAB 00000000 00004c 000060 10 6 6 4
[ 6] .strtab STRTAB 00000000 0000ac 000004 00 0 0 1
[ 7] .shstrtab STRTAB 00000000 0000b0 00003c 00 0 0 1
The .text
section is byte-aligned and contains the 3 bytes.
Now, I add an instruction to source.s
:
; source.s
.text
.byte 0xff
nop
.byte 0xff
.byte 0xff
Looking into the object file, now all of a sudden the .text
section is halfword-aligned:
There are 8 section headers, starting at offset 0x114:
Section Headers:
[Nr] Name Type Addr Off Size ES Flg Lk Inf Al
[ 0] NULL 00000000 000000 000000 00 0 0 0
[ 1] .text PROGBITS 00000000 000034 000006 00 AX 0 0 2
[ 2] .data PROGBITS 00000000 00003a 000000 00 WA 0 0 1
[ 3] .bss NOBITS 00000000 00003a 000000 00 WA 0 0 1
[ 4] .ARM.attributes ARM_ATTRIBUTES 00000000 00003a 000014 00 0 0 1
[ 5] .symtab SYMTAB 00000000 000050 000080 10 6 8 4
[ 6] .strtab STRTAB 00000000 0000d0 000007 00 0 0 1
[ 7] .shstrtab STRTAB 00000000 0000d7 00003c 00 0 0 1
What is causing the assembler to decide to pad the section in the second case? I am confused because:
- if the section is
.data
then the assembler will not pad it anyway, which makes sense, but - even if the section is
.text
, the assembler won't pad it unless it sees an instruction (I can have as many data directives, the section won't be padded without having also an instruction), and finally - the
nop
instruction is definitely not aligned and the assembler has no problem with it, but it still decides to care about section alignment.
How is the assembler deciding here to pad?
Can I force the assembler to not pad the .text
section even if I had an instruction?
答案1
得分: 1
以下是我在与binutils的人讨论后所了解到的内容:
汇编器不关心是否在任何特定部分编码了不对齐的指令。但是,它关心两个方面:
- 任何部分的整体对齐与该部分中最对齐的元素匹配,并且
- 每个标有执行标志的部分都会填充以匹配其对齐。
汇编器强制执行(2),因为以后这些部分可能需要合并,合并后,所有元素必须保持其对齐(因此它会填充这些部分以确保这一属性)。
原始帖子中显示的两种情况之间的区别是:
- 在第一种情况(没有指令的情况下),最对齐的元素是
.byte
,对齐为1
,因此整个部分的对齐为1
, - 而在第二种情况下,
nop
thumb指令成为最对齐的元素,因此该部分现在对齐为2
。
由于示例中的部分是一个.text
部分,并且具有X
标志,因此汇编器将填充第二种情况下的部分以匹配其对齐。然而,nop
指令仍然在部分内不对齐。
英文:
Here is what I learned after discussing it with the binutils folks:
The assembler does not care if one encodes misaligned instructions in any particular section. However, it cares about two aspects:
- that the overall section alignment of any section is matching to the most aligned element within that section, and
- that every section which is marked with the eXecute flag is padded to match its alignment.
The assembler enforces (2) because later those sections might need to be merged and after the merge all the elements within must keep their alignment (thus it pads the sections to ensure this property).
The difference between the two cases shown in the original post is that:
- in the first case (without the instruction), the most aligned element was
.byte
with an alignment of1
, thus giving the entire section an alignment of1
, while - in the second case, the
nop
thumb instruction becomes the most aligned element and the section is now2
-aligned.
Since the section in the example is a .text
section and has the X
flag set, the assembler will pad the section in the second case to match its alignment. Nevertheless, the nop
instruction is still misaligned inside the section.
答案2
得分: 0
Instruction in thumb(2) mode must start at a 16 bit offset. If you use .arm
, you will see padding to 32 bits. It is part of the ISA. Your NOP
instruction will not function (if somehow you jump directly to the NOP
). Of course, the rest of the stream is garbage. For the normal case that the NOP
in a text section is code, you want it to be aligned. The low bit in a pointer is typically used to denote a 'Thumb' or 'ARM' mode routine.
It would be an odd case to have a NOP as data; if so, define it yourself if you don't want padding.
.set UNALIGNED_NOP, 0xbf00 ; double check this constant.
You are using a tool in a completely wrong way. Use the '.rodata' section if you want data. The assemblers job is to convert human mnemonics to binary. For the normal case of NOP
in a text section, you want it to be executable. If the tools are not supported your use case, there would be dozens of other cases which would break. For instance,
;; basic block
;; xxxx
b label
.word xxxx ; ltorg, etc.
.word yyyy
.byte xx
label:
add r0, r0, #1 ; crash because it is not aligned.
英文:
> How is the assembler deciding here to pad?
Instruction in thumb(2) mode must start at a 16 bit offset. If you use .arm
, you will see padding to 32 bits. It is part of the ISA. Your NOP
instruction will not function (if somehow you jump directly to the NOP
). Of course, the rest of the stream is garbage. For the normal case that the NOP
in a text section is code, you want it to be aligned. The low bit in a pointer is typically used to denote a 'Thumb' or 'ARM' mode routine.
> Can I force the assembler to not pad the .text section even if I had an instruction?
It would be an odd case to have a NOP as data; if so, define it yourself if you don't want padding.
.set UNALIGNED_NOP, 0xbf00 ; double check this constant.
You are using a tool in a completely wrong way. Use the '.rodata' section if you want data. The assemblers job is to convert human mnemonics to binary. For the normal case of NOP
in a text section, you want it to be executable. If the tools are not supported your use case, there would be dozens of other cases which would break. For instance,
;; basic block
;; xxxx
b label
.word xxxx ; ltorg, etc.
.word yyyy
.byte xx
label:
add r0, r0, #1 ; crash because it is not aligned.
通过集体智慧和协作来改善编程学习和解决问题的方式。致力于成为全球开发者共同参与的知识库,让每个人都能够通过互相帮助和分享经验来进步。
评论