链接器插入不必要的操作码填充
Linker Inserts Unnecessary Opcode Padding
我最近在为基于 Motorola 68000 的系统 (SEGA Mega Drive) 链接多个目标文件时遇到了一个小问题。问题是,当一个目标文件的输入部分结束而下一个目标文件开始时,链接器会用零填充内存地址,以便下一个目标文件开始对齐四字节边界。下面的文本是链接器输出的内存映射。如您所见,.text output 部分包含三个目标文件。前两个(main.o、swap.o)是用 C 编写的,使用 m68k-elf-gcc 编译和汇编。第三个(swap_asm.o)是用68000汇编手写的,使用vasm组装而成。 swap.o 开头的函数通常从地址 0x0000001E 开始。但是,链接器在 swap.o 文件的开头*填充了两个字节,特别是 0x0000。所以,swap.o 从 0x00000020 开始。但是,swap_asm.o 没有对齐并且从非四字节对齐地址 0x00000036 开始。有没有办法让链接器不添加任何填充并立即启动 swap.o ?我知道有一些解决方法,比如用 NOP 填充 space,但我想知道是否有办法不做 *fill*?
.text 0x00000000 0x4c
main.o(.text)
.text 0x00000000 0x1e main.o
0x00000000 main
swap.o(.text)
*fill* 0x0000001e 0x2
.text 0x00000020 0x16 swap.o
0x00000020 swap
swap_asm.o(.text)
.text 0x00000036 0x16 swap_asm.o
0x00000036 swap_asm
68000 处理器要求指令对齐(此要求也适用于数据)。尽管有 CPU 要求(不可跳过),链接器还使用脚本,其中的段需要对齐(通常是为了满足此 cpu 要求)
虽然链接器脚本是可以调整的,但更改对齐方式可能会使链接器生成不正确的代码(由于上段所述),但无论如何,您可以尝试测试一下.
Motorola 68000(以及更多 MegaDrive 的 16 位版本)在奇数地址上请求 16 位传输时触发总线错误陷阱。如果是 32 位,也会发生同样的情况(但这种情况也会发生在 68030 上,我认为 68040 已经处理了这使得多个总线访问,就像英特尔处理器一样)
所以我找到了答案。当汇编程序检测到汇编文件中正在处理长(32 位)数据时,它会自动将输入部分沿 4 字节边界对齐。实际上,您可以在链接描述文件中使用 SUBALIGN 覆盖它。这是我的链接描述文件沿 2 字节边界对齐输入部分。
MEMORY
{
rom : ORIGIN = 0x00000000, LENGTH = 0x00400000
}
SECTIONS
{
.text : SUBALIGN(0x2) {
*(.header)
*(.boot)
obj/main.o(.text)
*(.text)
*(.isr)
*(.vdp)
} > rom
.data : { *(.data) } > rom
.bss : { *(.bss) } > rom
}
新链接映射:
.text 0x00000000 0x4a
main.o(.text)
.text 0x00000000 0x1e main.o
0x00000000 main
swap.o(.text)
.text 0x0000001e 0x14 swap.o
0x0000001e swap
swap_asm.o(.text)
.text 0x00000034 0x16 swap_asm.o
0x00000034 swap_asm
我最近在为基于 Motorola 68000 的系统 (SEGA Mega Drive) 链接多个目标文件时遇到了一个小问题。问题是,当一个目标文件的输入部分结束而下一个目标文件开始时,链接器会用零填充内存地址,以便下一个目标文件开始对齐四字节边界。下面的文本是链接器输出的内存映射。如您所见,.text output 部分包含三个目标文件。前两个(main.o、swap.o)是用 C 编写的,使用 m68k-elf-gcc 编译和汇编。第三个(swap_asm.o)是用68000汇编手写的,使用vasm组装而成。 swap.o 开头的函数通常从地址 0x0000001E 开始。但是,链接器在 swap.o 文件的开头*填充了两个字节,特别是 0x0000。所以,swap.o 从 0x00000020 开始。但是,swap_asm.o 没有对齐并且从非四字节对齐地址 0x00000036 开始。有没有办法让链接器不添加任何填充并立即启动 swap.o ?我知道有一些解决方法,比如用 NOP 填充 space,但我想知道是否有办法不做 *fill*?
.text 0x00000000 0x4c
main.o(.text)
.text 0x00000000 0x1e main.o
0x00000000 main
swap.o(.text)
*fill* 0x0000001e 0x2
.text 0x00000020 0x16 swap.o
0x00000020 swap
swap_asm.o(.text)
.text 0x00000036 0x16 swap_asm.o
0x00000036 swap_asm
68000 处理器要求指令对齐(此要求也适用于数据)。尽管有 CPU 要求(不可跳过),链接器还使用脚本,其中的段需要对齐(通常是为了满足此 cpu 要求)
虽然链接器脚本是可以调整的,但更改对齐方式可能会使链接器生成不正确的代码(由于上段所述),但无论如何,您可以尝试测试一下.
Motorola 68000(以及更多 MegaDrive 的 16 位版本)在奇数地址上请求 16 位传输时触发总线错误陷阱。如果是 32 位,也会发生同样的情况(但这种情况也会发生在 68030 上,我认为 68040 已经处理了这使得多个总线访问,就像英特尔处理器一样)
所以我找到了答案。当汇编程序检测到汇编文件中正在处理长(32 位)数据时,它会自动将输入部分沿 4 字节边界对齐。实际上,您可以在链接描述文件中使用 SUBALIGN 覆盖它。这是我的链接描述文件沿 2 字节边界对齐输入部分。
MEMORY
{
rom : ORIGIN = 0x00000000, LENGTH = 0x00400000
}
SECTIONS
{
.text : SUBALIGN(0x2) {
*(.header)
*(.boot)
obj/main.o(.text)
*(.text)
*(.isr)
*(.vdp)
} > rom
.data : { *(.data) } > rom
.bss : { *(.bss) } > rom
}
新链接映射:
.text 0x00000000 0x4a
main.o(.text)
.text 0x00000000 0x1e main.o
0x00000000 main
swap.o(.text)
.text 0x0000001e 0x14 swap.o
0x0000001e swap
swap_asm.o(.text)
.text 0x00000034 0x16 swap_asm.o
0x00000034 swap_asm