3

In the past I have embedded resource files (images) into programs by first converting them to .o files using the GNU linker. For example:

ld -r -b binary -o file.o file.svg

Starting with FreeBSD 12, the default linker has changed from GNU's to LLVM's. Although the linker appears to understand the command line options, it results in an error. For example:

ld -r -b binary -o file.o file.svg
ld: error: target emulation unknown: -m or at least one .o file required

Also tried using the command line options from the ld.lld(1) manual page:

ld --relocatable --format=binary -o file.o file.svg
ld: error: target emulation unknown: -m or at least one .o file required

Am I using the correct tool? Do I need to specify a value for the -m option?

1

It seems you need to add -z noexecstack (This was added for ELF binaries as well in LLD 7.0.0). The default is to have an executable stack region which is vulnerable to exploitation via stack memory. Your binary image does not have an executable stack and I believe that is why it fails. The error throws you off as it asks you to tell what target emulation to use for your stack (which you do not have).

David Herrmann did all the hard work and have found a cross platform solution which covers:

  • GNU-ld
  • GNU-gold
  • GNU-libtool
  • work with cross-compiling
  • work with LLVM
  • do not require any external non-standard tools

The magic invocation is then:

$(LD) -r -o "src/mydata.bin.o" -z noexecstack --format=binary "src/mydata.bin"

And most often you want that binary segment to be read-only:

$(OBJCOPY) --rename-section .data=.rodata,alloc,load,readonly,data,contents "src/mydata.bin.o"

UPDATE:

I could not test as my system was:

$ uname -r
11.2-STABLE
$ ld -V
GNU ld 2.17.50 [FreeBSD] 2007-07-03
  Supported emulations:
   elf_x86_64_fbsd
   elf_i386_fbsd

I spun up a VM with FreeBSD 12.0 to test this out and found this:

$ uname -r
12.0-RELEASE
$ ld -V
LLD 6.0.1 (FreeBSD 335540-1200005) (compatible with GNU linkers)

The -z noexecstack was only added in 7.0.0 and it is not listed in the man page for 6.0.1. More annoyingly specifying unsupported values for -z does not trigger an error!

I have not upgraded to LLVM 7 to test if that does the trick. @Richard Smith found a proper solution himself by specifying the emulation with -m in another answer. That route would be so much easier if LLD listed supported emulations with -V.

If you use the file command on file.o you will see it identifies as SYSV ELF. This might be good enough for you. But if you want the exact samme as the system then use elf_amd64_fbsd which is an alias for elf_x86_64_fbsd. Annoyingly ld -V does not output supported emulations with LLD as GNU ld does.

$ file /bin/cat
/bin/cat: ELF 64-bit LSB executable, x86-64, version 1 (FreeBSD), dynamically linked, interpreter /libexec/ld-elf.so.1, for FreeBSD 12.0 (1200086), FreeBSD-style, stripped
$ ld -r -b binary -m elf_amd64 -o data.o data.bin
$ file data.o
data.o: ELF 64-bit LSB relocatable, x86-64, version 1 (SYSV), not stripped
$ ld -r -b binary -m elf_amd64_fbsd -o data.o data.bin
$ file data.o
data.o: ELF 64-bit LSB relocatable, x86-64, version 1 (FreeBSD), not stripped

elf_amd64_fbsd is an alias for elf_x86_64_fbsd (see D7837 and D24356). Hopefully LLD will add the emulations to the -V output.

  • I tried adding the -z noexecstack option, but I get the same error message. As you say, it's not a useful error message, you get the same error message if you type ld with no parameters at all! – Richard Smith Jan 16 at 17:40
1

Is it really worth the trouble? That wasn't portable in the first place.

You should better convert your .svg to a C char array; Example:

$ cat Makefile
.SUFFIXES: .svg
.svg.c:
        od -tx1 $< | sed 's/ /,0x/g;s/[^,]*//;1s/,/char $*[]={/;$$s/$$/};/' > $@

$ make file.o
od -tx1 file.svg | sed 's/ /,0x/g;s/[^,]*//;1s/,/char file[]={/;$s/$/};/' > file.c
cc    -c -o file.o file.c
rm file.c

Of course, you can set the name of the array to something different / more robust (eg. char $(subst /,_,$*)[] = ... instead of char $*[] = ... with GNU make). Also, you could build an ad-hoc bin2c converter written in C instead of that horrible od+sed combo.

  • I like the idea of a bin2c converter – Richard Smith Jan 17 at 14:17
1

After looking through the source, the correct target emulation for my platform is elf_amd64. So the conversion from binary to object file works using:

ld -r -b binary -m elf_amd64 -o file.o file.svg
  • If you use the file command on file.o you will see it identifies as SYSV ELF. This might be good enough for you. But if you want the exact samme as the system then use elf_amd64_fbsd which is an alias for elf_x86_64_fbsd. Annoyingly ld -V does not output supported emulations as GNU ld does. – Claus Andersen Jan 18 at 12:11

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.