Linux Compatibility on BSD for the PPC Platform: Part 2
by Emmanuel Dreyfus05/17/2001
Managing dynamic executables
In this article, we'll take a closer look at the problems that prevent dynamic Linux binaries from working in compatibility mode on the NetBSD/PowerPC platform. This includes the way the arguments are passed to the Linux program, and ELF auxilliary table handling.
Passing arguments to the program
The first problem here is Linux's ld.so did not get its command-line arguments. In fact, no program running in Linux emulation -- either statically linked or dynamically linked -- was actually able to get its arguments. This could be outlined by building this sample program on a Linux box (statically, of course), and trying to run it on the NetBSD box:
/*
* arg.c -- An argument printer
*/
#include <stdio.h>
int main (int argc, char **argv) {
int i;
for (i=0; i<= argc; i++) {
printf ("argc[%d]=%s\n", i, argv[i]);
if (argc > 1)
return atoi (argv[1]);
return 0;
}
This programs tests argument and return value passing between
the kernel and the emulated executable. When running it, we get no
output at all. The program got a null argc, which demonstrated the
problem passing command-line arguments.
The arguments are passed to the program using the stack. When preparing
the program launch, the kernel sets up the stack so the program
will be able to find argc, argv, and envp. To inspect this
mechanism a bit deeper, we can use a stack dumper, like the following
piece of code :
/*
* sd.c -- A stack dumper
*/
#include <stdio.h>
#include <sys/types.h>
#include <ctype.h>
extern long end;
extern long etext;
extern long edata;
extern char **environ;
void stackdump (long, char **);
int main (int argc, char **argv) {
long sign = 0x89abcdef;
printf ("argc=0x%p\n", &argc);
printf ("argv=0x%p\n", &argv);
printf ("environ=0x%p\n", &environ);
stackdump (sign, argv);
return 0;
}
void stackdump (long arg, char **argv) {
unsigned long i,j;
long signature = 0x01234567;
if (0)
printf ("%lx %lx\n", arg, signature);
printf ("etext=0x%lx\nedata=0x%lx\nend=0x%lx\n", etext, edata, end);
for (i = (((long)argv-0x400)/16)*16; i <= 0x7fffffff; i=i+16) {
printf ("%08lx ",i);
for (j=0; j <= 15; j=j+2) {
printf ("%02x", (*(char*)(i+j)));
printf ("%02x ", (*(char*)(i+j+1)));
}
for (j = 0; j <= 15; j++) {
if (isprint (*(char*)(i+j)))
printf ("%c", *(char*)(i+j));
else
printf (".");
}
printf ("\n");
}
}
This program also uses global and local variables to help study argument
passing. It dumps the stack from an arbitrary address until it
reaches the end of the stack and crashes, because pages after the stack
are not accessible when running in user mode. We do not really care
about this crash because it displays what we are looking for. However,
this can be a problem if you are working on a terminal that is unable to scroll back and want to pipe the stack dump's output to more(1) or
less (1).
If you want to do this, you will have to modify the program so
it catches the SIGSEGV signal. You will also have to ensure that
linux_sendsig() in linux_machdep.c does not crash anything. Most likely,
you will keep that function empty. The easy solution is certainly
to get a terminal that has a scrollback feature.


