【问题标题】:How do I use the GNU linker instead of the Darwin Linker?如何使用 GNU 链接器而不是 Darwin 链接器?
【发布时间】:2017-04-18 22:31:26
【问题描述】:

我正在运行 OS X 10.12,并且正在开发一个基本的基于文​​本的操作系统。我开发了一个引导加载程序,它似乎运行良好。我唯一的问题是,当我尝试将内核编译为纯二进制时,链接器将无法工作。我做了一些研究,我认为这是因为 OS X 运行的是 Darwin 链接器而不是 GNU 链接器。因此,我下载并安装了 GNU binutils。但是还是不行……

这是我的内核:

void main() {
    // Create pointer to a character and point it to the first cell of video
    // memory (i.e. the top-left)
    char* video_memory = (char*) 0xb8000;

    // At that address, put an x
    *video_memory = 'x';
} 

这是我尝试编译它的时候:

Hazims-MacBook-Pro:32 bit root# gcc -ffreestanding -c kernel.c -o kernel.o
Hazims-MacBook-Pro:32 bit root# ld -o kernel.bin -T text 0x1000 kernel.o --oformat binary
ld: unknown option: -T
Hazims-MacBook-Pro:32 bit root# 

我很想知道如何解决这个问题。感谢您的宝贵时间。

【问题讨论】:

  • 你有一个额外的空间,你错过了= 登录-T text 0x1000 应该是-Ttext=0x1000。请参阅手册。如果还是不行,请按照手册再次尝试--section-start=.text=0x1000
  • @Jester 在尝试您所说的内容时出现此错误:'ld: unknown option: --section-start=.text=0x1000'
  • ld --version 说什么?
  • ld --version 不起作用所以我尝试了 ld -v 并提出了这个:'@(#)PROGRAM:ld PROJECT:ld64-274.1 配置为支持拱门:armv6 armv7 armv7s arm64 i386 x86_64 x86_64h armv6m armv7k armv7m armv7em (tvOS) LTO 支持使用:LLVM 版本 8.0.0,(clang-800.0.42.1) TAPI 支持使用:Apple TAPI 版本 1.30'
  • 这不是您声称的 GNU 链接器。要么你没有正确安装它,要么你没有调用正确的二进制文件。

标签: c gcc assembly operating-system ld


【解决方案1】:

你是对的,你可能需要 binutils 来解决这个问题,尤其是在你编写裸机代码的时候;虽然 clang as 声称是一个交叉编译器,但由于各种原因,它在这里远非最佳或可用。注意到您正在我推断的 ARM 上进行开发;你想要这个。

https://developer.arm.com/open-source/gnu-toolchain/gnu-rm

除了 gcc 明显比 clang 做得更好之外,还有一个问题是 ld 不能从 binutils 包构建在 OS X 上;它在某些配置中静默失败,因此尽管观看了 libiberty 等构建,您实际上可能从未实际安装过它,它甚至有时会执行编译该目标源的动​​作,并且只是拒绝将它链接到...指责 OP 的糟糕语气,如果你有相关经验,即曾经在这种情况下建造过这个,你就会知道这显然是令人讨厌的。如果您不劝阻人们提出合理的问题,那就太好了。

在 CXXfilt 包中,他们咕哝着 apple-darwin 不是目标;尝试将 FAKE_TARGET 改为 mn10003000-whatever 或他们使用的任何东西,一段时间后改为 apple-rhapsody。

如果您说需要从某些东西中剥离重定位或想要恢复到系统的静态链接,那么您仍然可以更好地从当前构建它们。默认情况下,该 clang 安装中也缺少此功能...无论如何,并不是 ld 不能与 macho 一起使用,它就在那里,实际上是代码方面...我确信

关于在内存中定位内容,您可能需要参考链接描述文件

http://svn.screwjackllc.com/?p=noid.git;a=blob_plain;f=new_mbed_bs.link_script.ld

因为我在那里有一些代码可以直接将东西放在内存中,而不是在命令行上执行它,所以使用链接器脚本更具可重复性。它有点复杂,但它正在做的是设置几个内存区域以与我的内存分配器一起使用,您可以使用 malloc,但您不应该使用实际的 malloc;动态内存在非动态时很好……呵呵……

该脚本还为堆栈和堆位置设置标志,虽然它们只是标记,没有加载直到运行时间,它们实际上是由启动代码放置的,堆栈和堆,这是在汇编中,相当可读且很好评论(难以置信,我知道)...巧妙的技巧,你对易失性内存有一些持久性,所以我留出一点点来翻转,你可以做一些事情,比如让它控制在下一个电源上运行的引导加载程序循环。再次,您对链接器是 100% 正确的;似乎你正朝着正确的方向前进。顺便说一句,您可以在加载对象之前修改对象并将其预加载到内存中,类似于此方法,有很多方法,但是,请查看 objcopy 和 objdump ...您可以使用 gdb 转储结构的 srecs在内存中,记下地址,然后在链接之前但在组装之后使用 dd 将您使用 gdb 提取的记录插入到提取的部分中。这是我最喜欢的方式之一,因为它是 smartass 路线:D 也是,如果你很紧在内存上,需要预先计算常量,这是优化事物的一种方式......这种方式实际上更接近 ld 正在做的事情,只是手工完成......现在可能阻力最小的路径是链接器脚本。

【讨论】:

    【解决方案2】:

    -T 是 gcc 编译器标志,而不是链接器标志。看看这个:

    使用这些组件,您现在可以实际构建最终内核。我们使用编译器作为链接器,因为它可以更好地控制链接过程。请注意,如果您的内核是用 C++ 编写的,则应该改用 C++ 编译器。

    然后您可以使用以下方法链接您的内核:

    i686-elf-gcc -T linker.ld -o myos.bin -ffreestanding -O2 -nostdlib boot.o kernel.o -lgcc

    注意:一些教程建议使用 i686-elf-ld 而不是编译器进行链接,但这会阻止编译器在链接期间执行各种任务。

    文件 myos.bin 现在是您的内核(不再需要所有其他文件)。请注意,我们链接的是 libgcc,它实现了您的交叉编译器所依赖的各种运行时例程。留下它会在未来给你带来问题。如果您没有构建和安装 libgcc 作为交叉编译器的一部分,您现在应该返回并使用 libgcc 构建一个交叉编译器。编译器依赖于这个库,无论你是否提供它都会使用它。

    这一切都直接取自OSDev,它非常清楚地记录了整个过程,包括一个准系统内核。

    【讨论】:

    • 虽然这是真的,但我认为 OP 正在尝试设置 ld 确实有 -Ttext 选项的部分开始。
    • 那么一定是我的链接器。这里没有-T 选项。 :)
    • @DavidHoelzer 这给了我这个错误 'Hazims-MacBook-Pro:32 bit root# gcc -T 0x1000 -o myos.bin -ffreestanding kernel.c //// ld: unknown option: - T ///// clang: 错误:链接器命令失败,退出代码为 1(使用 -v 查看调用)'
    猜你喜欢
    • 2017-08-31
    • 1970-01-01
    • 2013-10-26
    • 1970-01-01
    • 2011-05-28
    • 2013-10-10
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多