Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Compile a binary file for linking OSX

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

like image 806
Satpal Avatar asked Jan 19 '12 08:01

Satpal


People also ask

How do I create a binary file on Mac?

use a Hex editor to create the file. that way you get actual binary data instead of encoded text that consists of 1 and 0 characters. a web search for osx hex editor turns up quite a few options. Depending on your choice of products, you may have to enter the data in Hex, but that will still result in a binary file.

Does Macos have a compiler?

Mac C compilers compile C code into an executable. This executable can be run directly to run the C code. Clang and GCC(GNU Compiler Collection) are the common compilers that are used to compile C code.

How do I open a binary file on a Mac?

If your Mac correctly interprets the BIN file extension and recognizes the file as MacBinary, it will be identified accordingly in list-view Finder windows. If your Mac doesn't immediately decompress a BIN file, right-click on the file and choose "Open With." Select "Archive Utility. app" from the list of options.

What is a binary file in Mac?

MacBinary is a file format that combines the two forks of a classic Mac OS file into a single file, along with HFS's extended metadata. The resulting file is suitable for transmission over FTP, the World Wide Web, and electronic mail.


1 Answers

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);
}
like image 90
Lloeki Avatar answered Oct 05 '22 08:10

Lloeki