Compile a binary file for linking OSX
Asked Answered
I

1

9

I'm trying to compile a binary file into a MACH_O object file so that it can be linked it into a dylib. The dylib is written in c/c++.

On linux the following command is used: ld -r -b binary -o foo.o foo.bin

I have tried various option on OSX but to no avail:

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)

An empty .o file is created

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)

Again and empty .o file is created. Checking the files with nm gives: nm foo.o nm: no name list

The binary file is actually, firmware that will be downloaded to an external device.

Thanks for looking

Inaudible answered 19/1, 2012 at 8:35 Comment(5)
you should just need to do something like ld -dylib -o libFoo.dylib fooSource*.o. the problem seems to be with foo.bin - if you do file foo.bin what does it say?Directive
The output of file foo.bin is: foo.bit: Xilinx BIT data - from foo.ncd;HW_TIMEOUT=FALSE;Us - for 0xFFFFFFFF - built slx16ftg256(011/03/15) - data length 0x31373a35Inaudible
hmm, i'm afraid it doesn't look like the LLVM clang ld does the binary blob embedding that the gnu ld does. you might want to try installing gcc from macports (macports.org)? not sure if that'd help, but might be worth a try.Directive
Thanks will look into macports.Inaudible
Wonder if anyone know howto use the -sectcreate option on ld?Inaudible
M
11

Here's the closest translation to the Linux linker command to perform binary embedding with the OSX linker:

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 will be stored in segment binary, section foo_bin (both names are arbitrary but chosen to mimic GNU ld for ELF on Linux) of the foo.o object.

stub is necessary because ld refuses to create just a custom segment/section. You don't need it if you link directly with a real code object.

To get data back from the section, use getsectbyname (struct is defined in 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

or 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

(I used it to store text data, hence the stringification via calloc zeroing of size+1 plus blob copying)

Warning: Since 10.7, ASLR got stronger and messes badly with getsect* functions, resulting in segfaults. set disable-aslr off in GDB before running to reproduce EXC_BAD_ACCESS (SIGSEGV) in debug conditions. People had to jump through inordinate hoops to find the real address and get this working again.

A simple workaround is to get the offset and size, open the binary and read the data straight from disk. Here is a working example:

// 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);
}
Maki answered 7/12, 2012 at 23:1 Comment(3)
It looks like there are slightly newer getsection* versions of the getsect* functions that can be used and which aren't affected by the ASLR problems. Slightly nicer than having to read the raw binary.Truckload
gareus.org/wiki/embedding_resources_in_executables also notes that the section name passed to -sectcreate cannot be longer than 16 characters...Evidential
So it is done using the GNU's toolchain, and is there a way to do it using apples linker (clang)?Illumination

© 2022 - 2024 — McMap. All rights reserved.