Linux Compatibility on BSD for the PPC Platform
Pages: 1, 2, 3, 4
This function performs several tests. The first test is the
linux_elf32_signature(), which looks for an interpreter name specific to
Linux. The interpreter is a helper program used to run the executable.
This is the ld.so program used to launch dynamically linked programs.
The linux_elf32_signature() looks in the ELF headers for an interpreter
like /lib/ld.so or /lib/ld-linux.so, which is really Linux-specific. For instance, a NetBSD ELF program uses /usr/libexec/ld.elf_so, and a
System V Release 4 system should use /usr/lib/ld.so.
This test is good for dynamically linked binaries, but it fails for
statically linked binaries, for which there is no interpreter name in
the ELF header. To fix this flaw, there is a second test, enabled by the
LINUX_GCC_SIGNATURE macro, linux_elf32_gcc_signature(), which looks for
a GCC signature in the .comment ELF section of the executable. This is
not a very good test, since this GCC signature is specific to GCC but
not to Linux. Anyway, for some unknown reasons, this test failed on the
PowerPC.
We therefore have to find an alternative way of matching statically
linked Linux binaries. The objdump(1) command is useful to investigate
for such a new method: objdump -h program will dump the ELF section
headers of the program, and objdump -j .name -s program will dump the
content of named section .name. Here is an example of objdump -h output
for a statically linked Linux binary:
$ objdump -h hello
hello: file format elf32-powerpc
Sections:
Idx Name Size VMA LMA File off Algn
0 .text 00030930 018000a0 018000a0 000000a0 2**4
CONTENTS, ALLOC, LOAD, READONLY, CODE
1 .init 00000080 018309d0 018309d0 000309d0 2**2
CONTENTS, ALLOC, LOAD, READONLY, CODE
2 .fini 00000028 01830a50 01830a50 00030a50 2**2
CONTENTS, ALLOC, LOAD, READONLY, CODE
3 .rodata 00003f8c 01830a78 01830a78 00030a78 2**3
CONTENTS, ALLOC, LOAD, READONLY, DATA
4 __libc_atexit 00000004 01834a04 01834a04 00034a04 2**2
CONTENTS, ALLOC, LOAD, READONLY, DATA
5 .sdata2 00000000 01834a08 01834a08 00034a08 2**2
CONTENTS, ALLOC, LOAD, READONLY, DATA
6 .data 00000cb8 01874a08 01874a08 00034a08 2**2
CONTENTS, ALLOC, LOAD, DATA
7 .got2 00000010 018756c0 018756c0 000356c0 2**0
CONTENTS, ALLOC, LOAD, DATA
8 .ctors 00000010 018756d0 018756d0 000356d0 2**2
CONTENTS, ALLOC, LOAD, DATA
9 .dtors 00000008 018756e0 018756e0 000356e0 2**2
CONTENTS, ALLOC, LOAD, DATA
10 .got 00000010 018756e8 018756e8 000356e8 2**2
CONTENTS, ALLOC, LOAD, DATA
11 .sdata 0000011c 018756f8 018756f8 000356f8 2**2
CONTENTS, ALLOC, LOAD, DATA
12 .sbss 00000024 01875814 01875814 00035814 2**2
ALLOC
13 .bss 000008b8 01875838 01875838 00035814 2**2
ALLOC
14 .stab 00000cfc 00000000 00000000 00035814 2**2
CONTENTS, READONLY, DEBUGGING
15 .stabstr 00000fba 00000000 00000000 00036510 2**0
CONTENTS, READONLY, DEBUGGING
16 .comment 00002060 00000fba 00000fba 000374ca 2**0
CONTENTS, READONLY
Dumping the ELF section header, we can see that all statically linked Linux
programs have a section named __libc_atexit. This is specific to Linux,
and as far as we know, it does not occur on any other operating system.
A good point is that this __libc_atexit section does not seems to be
Linux/PowerPC specific: We can find it in Linux/i386 static binaries as
well.
We therefore have to write a new test in
sys/compat/linux/common/linux_exec_elf32.c, enabled by the
LINUX_ATEXIT_SIGNATURE macro. This test just checks if there is a
__libc_atexit section in the ELF header. With this test, statically
linked Linux binaries are matched. We can check this by enabling the
DEBUG_LINUX macro and looking at what the kernel outputs when we try to
run the binary. With this new test, it is very likely that the hello
world program now runs in compatibility.
In the event it does not work, the way of solving the problem is running
ktrace(1) on the program on the NetBSD box, and the Linux equivalent
(which is strace(1)) on a Linux box, and see what is going wrong.
Possible issues are badly translated syscalls. For instance, if we
incorrectly translated mmap() to dup2(), this shows up immediately on a
kernel trace, because we see that dup2() is called instead of mmap().
We need to rebuild kdump(1) if we want it to display the system
call names and arguments when running emulated binaries. Generally
speaking, we need to recompile kdump(1) each time we modify any
syscalls.master file.
Now that statically linked binaries work, we can try dynamically linked
binaries. Note that you need to download a set of Linux libraries from a
PowerPC Linux box in order to run dynamically linked programs. For the
hello world program, you need at least ld.so.1 and libc.6.
On the PowerPC, dynamically linked programs were immediately matched by
the linux_elf32_signature() test, but running them did not work, either
because it crashed, or because we got a Linux ld.so message saying
that we invoked ld.so without arguments. We will focus on these dynamic
binaries-specific issues in part 2.
Emmanuel Dreyfus is a system and network administrator in Paris, France, and is currently a developer for NetBSD.
Return to ONLamp.com.