为OSX编译二进制文件以进行链接

9

我正在尝试将二进制文件编译成MACH_O对象文件,以便将其链接到dylib中。这个dylib是用C/C++编写的。

在Linux上,使用以下命令:

ld -r -b binary -o foo.o foo.bin

我已经尝试了各种选项,在OSX上却没有成功:

ld -r foo.bin -o foo.o
gives:
ld: warning: -arch not specified
ld: warning: ignoring file foo.bin, file was built for unsupported file format which is not the architecture being linked (x86_64)

创建了一个空的 .o 文件。
ld -arch x86_64 -r foo.bin -o foo.o 
ld: warning: ignoring file foo.bin, file was built for unsupported file format which is not the architecture being linked (x86_64)

再次创建了一个空的.o文件。使用nm命令检查这些文件: nm foo.o nm: 没有名称列表

实际上,二进制文件是固件,将被下载到外部设备。

感谢您的查看。


你只需要执行类似于 ld -dylib -o libFoo.dylib fooSource*.o 的操作。问题似乎出在 foo.bin 上 - 如果你执行 file foo.bin 呢?它会显示什么? - Mike K
文件foo.bin的输出为: foo.bit:Xilinx BIT数据 - 来自foo.ncd;HW_TIMEOUT=FALSE;Us - 用于0xFFFFFFFF - 构建slx16ftg256(011/03/15) - 数据长度0x31373a35 - Satpal
嗯,恐怕LLVM clang ld没有像GNU ld那样进行二进制嵌入。你可以尝试从MacPorts(http://www.macports.org/)安装GCC吗?不确定是否有帮助,但值得一试。 - Mike K
谢谢,我会研究一下MacPorts。 - Satpal
有没有人知道如何在ld上使用-sectcreate选项? - Satpal
1个回答

11

这是最接近Linux链接器命令的翻译,用于执行二进制嵌入到OSX链接器中:

touch stub.c
gcc -o stub.o -c stub.c
ld -r -o foo.o -sectcreate binary foo_bin foo.bin stub.o

foo.bin将被存储在foo.o对象的段binary、节foo_bin中(这些名称是任意选择的,但被选为模仿Linux上ELF的GNU ld)。

stub是必需的,因为ld拒绝创建仅自定义段/节。如果您直接链接真正的代码对象,则不需要它。

要从节中获取数据,请使用getsectbyname(结构体在mach-o/loader.h中定义):

#include <mach-o/getsect.h>
const struct section_64 *sect = getsectbyname("binary", "foo_bin");
char *buffer = calloc(1, sect->size+1);
memcpy(buffer, sect->addr, sect->size); // whatever

getsectdata

#include <mach-o/getsect.h>
size_t size;
char *data = getsectdata("binary", "foo_bin", &size);
char *buffer = calloc(1, size+1);
memcpy(buffer, data, size); // whatever

(我将其用于存储文本数据,因此通过 calloc 的字符串化,可将大小加1并复制块)

警告:自10.7以来,ASLR变得更加强大,并且与 getsect* 函数混淆在一起,导致段错误。在 run 之前,在GDB中 set disable-aslr off 以在调试条件下重现EXC_BAD_ACCESS(SIGSEGV)。人们不得不费尽周折才能找到真正的地址并再次使其正常工作。

一个简单的解决方法是获取偏移量和大小,打开二进制文件并直接从磁盘读取数据。以下是一个可工作的示例:

// main.c, build with gcc -o main main.c foo.o
#include <stdlib.h>
#include <fcntl.h>
#include <unistd.h>
#include <string.h>
#include <stdio.h>
#include <mach-o/getsect.h>

int main() {
    // finding the filename of the running binary is left as an exercise to the reader
    char *filename = "main";

    const struct section_64 *sect = getsectbyname("binary", "foo_bin");
    if (sect == NULL) {
        exit(1);
    }

    char *buffer = calloc(1, sect->size+1);
    int fd = open(filename, O_RDONLY);
    if (fd < 0) {
        exit(1);
    }
    lseek(fd, sect->offset, SEEK_SET);
    if (read(fd, buffer, sect->size) != sect->size) {
        close(fd);
        exit(1);
    }

    printf("%s", buffer);
}

2
看起来有稍微更新的 getsection* 版本的 getsect* 函数可用,不受 ASLR 问题的影响。比直接读取原始二进制文件要好一些。 - Gavin Maclean
1
http://gareus.org/wiki/embedding_resources_in_executables 还指出,传递给“-sectcreate”的部分名称不能超过16个字符... - cfstras
所以它是使用GNU的工具链完成的,有没有办法使用苹果的链接器(clang)来完成呢? - undefined

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接