如何使用 gcc/ld 将目标文件 link 转换为原始二进制文件?

How to link object files into a raw binary file with gcc/ld?

2019 年 12 月 2 日更新:

我在使用 m68k-elf 工具链时遇到问题。我想做的是像这样翻译一个简单的 68k 汇编文件 source.s

    .text 
    move.w %d0,%d1

到目标文件中,然后使用 linker 脚本 memmap.ldscript:

MEMORY 
{
    ROM1 (rx) : ORIGIN = 0x00, LENGTH = 16
    ROM2 (rx) : ORIGIN = 0x10, LENGTH = 16
}

SECTIONS 
{
    .text : 
    {
       *(.text)
    } >ROM2
}

OUTPUT_FORMAT(binary)

将link这个目标文件转换成原始二进制文件。最终文件应如下所示(在十六进制编辑器中查看):

00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
30 01 00 00 00 00 00 00 00 00 00 00 00 00 00 00

如果我这样构建它

m68k-elf-as -o source.o source.s 
m68k-elf-ld -T memmap.ldscript -o final.rom source.o 

那么final.rom只包含:

30 01

因此该部分的代码位于 0x00 而不是 0x05。

我需要 "raw" 机器码来刻录到 E(E)PROM。但是我想使用 linker 和 linker 脚本来 assemble 从几个源文件到目标文件的部分,然后 link 它们成为一个最终文件ROM 的部分位置由 linker 脚本控制。 m68k-elf 可以吗?

您需要通过创建包含某些内容的输出节来强制链接器发出 ROM1 区域。 manual says:

Other link script directives that allocate space in an output section will also create the output section. So too will assignments to dot even if the assignment does not create space, except for ‘. = 0’, ‘. = . + 0’, ‘. = sym’, ‘. = . + sym’ and ‘. = ALIGN (. != 0, expr, 1)’ when ‘sym’ is an absolute symbol of value 0 defined in the script. This allows you to force output of an empty section with ‘. = .’.

所以这应该有效:

MEMORY 
{
    ROM1 (rx) : ORIGIN = 0x00, LENGTH = 16
    ROM2 (rx) : ORIGIN = 0x10, LENGTH = 16
}

SECTIONS
{
    .dummy :
    {
       . = ORIGIN(ROM1) + LENGTH(ROM1);
    } >ROM1

    .text : 
    {
       *(.text)
       . = ORIGIN(ROM2) + LENGTH(ROM2);
    } >ROM2
}

OUTPUT_FORMAT(binary)

但是,至少对于我的 binutils 版本 2.33.1,它没有。 .=. 也不行。如果您只需要填充区域,则可以向其中发送一些数据,例如通过 BYTE(0) 指令并且有效:

MEMORY 
{
    ROM1 (rx) : ORIGIN = 0x00, LENGTH = 16
    ROM2 (rx) : ORIGIN = 0x10, LENGTH = 16
}

SECTIONS
{
    .dummy :
    {
       BYTE(0);
       . = ORIGIN(ROM1) + LENGTH(ROM1);
    } >ROM1

    .text : 
    {
       *(.text)
       . = ORIGIN(ROM2) + LENGTH(ROM2);
    } >ROM2
}

OUTPUT_FORMAT(binary)

如果您确实有 ROM1 的一些内容,那么当然只需为其创建输入部分,但要确保它始终存在,否则链接器会将其删除。奇怪的是,即使是零大小的部分也能正常工作。