【问题标题】:New versions of LD cannot take ELF files as input to link新版本的 LD 无法将 ELF 文件作为链接的输入
【发布时间】:2021-10-07 21:16:32
【问题描述】:

我一直在使用 GNU LD 2.34 版作为链接器,使用 C 语言编写一个 32 位操作系统项目。

作为构建过程的一部分,我使用以下命令:

ld -m elf_i386 -nostdlib -T ld/loader.ld build/bootloader/loader.o build/bootloader/loader.elf -o loader_full.elf

使用 GNU LD 2.34 版时,此命令成功。但是,当我使用高于此的版本时,会出现以下错误:

ld: cannot use executable file 'build/bootloader/loader.elf' as input to a link

如有必要,这里是完整的 Makefile 脚本:

CC_FLAGS = -g -m32 -ffreestanding -nostartfiles -nostdlib -fno-stack-protector
LD_FLAGS = -m elf_i386 -nostdlib

CC := gcc ${CC_FLAGS}
LD := ld ${LD_FLAGS} 

BOOTLOADER_DRIVERS = kernel/drivers/disk/ata.c kernel/drivers/io/screen.c kernel/drivers/utils/mem.c kernel/drivers/utils/ports.c

raw: prep os-image.bin

convert_vmdk: os-image.vmdk 

all: prep os-image.bin

ESFS_raw_write: ESFS_raw_write.c
    gcc $^ -o $@

# run OS in QEMU
run: 
    qemu-system-i386 -drive format=raw,file=os-image.bin

# assemble boot sector
build/bootloader/boot_sect.bin: boot/boot_sect.asm
    nasm $^ -f bin -o $@

# compile second stage bootloader
build/bootloader/loader_2.o build/drivers/*.o: boot/*.c ${BOOTLOADER_DRIVERS}
    ${CC} -c $^
    mv loader.o build/bootloader/loader_2.o
    mv *.o build/drivers/

# link object files into kernel loader
build/bootloader/loader.elf: build/bootloader/loader_2.o build/drivers/*.o
    ${LD} -T ld/loader.ld $^ -o $@
    rm build/bootloader/loader_2.o

# assemble first stage bootloader
build/bootloader/loader.o: boot/loader.asm
    nasm $^ -f elf -o $@

# link first and second stage bootloaders
build/bootloader/loader_full.elf: build/bootloader/loader.o build/bootloader/loader.elf
    ${LD} -T ld/loader.ld $^ -o $@

# make bootloader binary file
build/bootloader/loader.bin: build/bootloader/loader_full.elf
    objcopy $^ -O binary $@
    ./scripts/pad_loader.sh
    # clean up unnecessary files
    # rm build/bootloader/*.o build/bootloader/*.elf build/drivers/*.o

build/kernel/interrupt.o: kernel/cpu/interrupt.asm
    nasm $^ -f elf -o $@

# compile kernel & write to 10MB raw drive image
build/kernel/hdd.bin: kernel/drivers/*/*.c kernel/cpu/*.c kernel/libc/*.c build/kernel/interrupt.o kernel/*.c
    ${CC} $^ -o build/kernel/kernel.o -T ld/kernel.ld
    ./scripts/write_kernel_to_drive.sh

# concat 3 boot stages into os-image file
os-image.bin: build/bootloader/boot_sect.bin build/bootloader/loader.bin build/kernel/hdd.bin
    cat $^ > $@

os-image.vmdk: 
    VBoxManage convertfromraw os-image.bin os-image.vmdk --format VMDK
    VBoxManage internalcommands sethduuid /home/tim/Dev/OSDev/os-image.vmdk 6372c00a-a62e-4241-9a21-90fa4c22f019

# prepare directory structure for build process
prep:
    mkdir -p build/bootloader
    mkdir -p build/drivers
    mkdir -p build/kernel

# clean up build files and os-image binary
clean:
    -rm -rf build/
    -rm *.bin *.vmdk
    -rm ESFS_raw_write

该项目也在 GitHub 上,因此您可以自己构建它: http://github.com/TimCve/OSDev.git

【问题讨论】:

    标签: linux makefile operating-system ld elf


    【解决方案1】:

    并不是ld 不能将ELF 文件作为输入。就是它不会将 executable 文件作为输入。错误是:

    ld: 不能使用可执行文件“...”作为链接的输入

    https://sourceware.org/bugzilla/show_bug.cgi?id=26223

    在构建.elf 文件后简单地使用chmod -x $@ 是否有效?

    【讨论】:

    • 感谢您的回答,但这不起作用,即使文件不可执行我也得到完全相同的错误,有没有办法让 LD 能够将可执行文件作为输入?跨度>
    • 我猜它不是在查看位,而是在查看文件本身中的某些内容。除了退回到旧版本并等待修复上述错误(或者您可以构建自己的应用补丁)之外,我没有其他解决方案。您可能应该在该错误中添加一条注释,询问状态是什么,因为它似乎在超过 1 年的时间里没有被触及,并且从那时起就有了 binutils 版本,包括几周前的一个版本。也许这让每个人都没有注意到。
    【解决方案2】:

    我刚刚遇到了类似的问题。

    似乎 ld 版本 GNU ld (GNU Binutils) 2.36.1 将文件链接成可执行格式。

    要修复它,请在您的 ld 命令中添加 -r 以输出可重定位的格式文件。

    来自ld manual

    -r
    --可重定位
    生成可重定位的输出——即生成一个输出文件,该文件又可以用作 ld 的输入。这通常称为部分链接。作为副作用,在支持标准 Unix 幻数的环境中,此选项还将输出文件的幻数设置为 OMAGIC。如果未指定此选项,则生成绝对文件。链接 C++ 程序时,此选项不会解析对构造函数的引用;为此,请使用-Ur。此选项与-i 的作用相同。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2013-01-16
      • 1970-01-01
      • 2017-10-14
      • 2013-11-14
      • 2019-03-20
      • 2014-10-19
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多