BSD DevCenter
oreilly.comSafari Books Online.Conferences.


IRIX Binary Compatibility, Part 3
Pages: 1, 2, 3

If we had to rediscover the second and third argument usage without looking at Linux sources, we could try to dig up some information using gdb. The goal is to look at what is at the address pointed to by the second argument. To achieve this, we can break just at the syssgi(2) system call stub in libc. We can get the address of the syssgi(2) system call stub in libc using the GNU nm(1) command with the -D option. This will list all of the dynamic symbols from a binary.

$ nm -D /lib/ | grep syssgi
0fa33260 A _syssgi
0fa33260 W syssgi

Then we just have to set the breakpoint and run:

$ gdb ftp
(gdb) b *0x0fa33260
Breakpoint 1 at 0xfa33260
(gdb) run
Starting program: ./ftp

Breakpoint 1, 0xfa33260 in ?? ()
(gdb) info registers
          zero       at       v0       v1       a0       a1       a2       
 R0   00000000 00000001 7fffe788 00000001 00000044 00000005 7fffe7c8 

The SVR4 ABI states that registers A0 to A3 are used to pass the first four arguments to a function. A0 is equal to 0x44, which corresponds to the ELFMAP request. This is the first syssgi(2) argument. Here we are!

A1 is still the file descriptor. It is 5 and not 3 because we are running with gdb and there are more files open. However, a ktrace(1) would show that this is the file descriptor just returned by open(2). What we are looking for is the buffer pointed to by the second argument to syssgi(ELFMAP), which is the third argument to syssgi(2), stored in A2. Let us dump the memory pointed to by A2:

(gdb) x/20wx $a2
0x7fffe7c8:     0x00000001      0x00000000      0x0fb60000      
0x7fffe7d8:     0x00035000      0x00035000      0x00000005      
0x7fffe7e8:     0x00000001      0x00038000      0x0fbd8000      
0x7fffe7f8:     0x00002000      0x00002000      0x00000006      
0x7fffe808:     0x00000000      0x01200000      0x00000000      

It is difficult here to recognize a program header array. But if we re-read the kernel trace, we can see that the program has just read 512 bytes at 0x7fffe754.

1613 ftp      CALL  read(0x5,0x7fffe754,0x200)
1613 ftp      RET   read 512/0x200
1613 ftp      CALL  syssgi(0x44,0x5,0x7fffe7c8,0x2,0,0xfb3509c)

These 512 bytes are the beginning of the /lib/rld file; that is, the ELF headers. If the program has just called syssgi(2) without modifying this area, then 0x7fffe7c8 should point to data that is a plain copy of what is in the /lib/rld file, at offset 0x7fffe7c8 - 0x7fffe754 = 0x74.

We can check that this is true:

$ hexdump -s 0x74 -n 80 /lib/rld
0000074 0000 0001 0000 0000 0fb6 0000 0fb6 0000
0000084 0003 5000 0003 5000 0000 0005 0000 4000
0000094 0000 0001 0003 8000 0fbd 8000 0fbd 8000
00000a4 0000 2000 0000 2000 0000 0006 0000 4000
00000b4 0000 0000 0120 0000 0000 0000 f3ff fffe

Now we know that the program passed some data to syssgi(ELFMAP) from the file. We do not know yet that this is a program header array, but we are getting closer. The question is: what data is in the file at offset 0x74?

Probably some header information, since this is not that far away from the beginning of the file.

The job can be finished using a small C program:

/* cc -o elfdump elfdump.c */
#include <elf.h>
#include <stdio.h>

int main(void) {
        Elf32_Ehdr buf;

        (void)read(0, &buf, sizeof(buf));
        printf("buf.e_phoff = 0x%08x\n", buf.e_phoff);
        printf("buf.e_phentsize = 0x%08x\n", buf.e_phentsize);
        printf("buf.e_phnum = 0x%08x\n", buf.e_phnum);

        return 0;

Here is elfdump output :
$ elfdump < /lib/rld
buf.e_phoff = 0x00000034
buf.e_phentsize = 0x00000020
buf.e_phnum = 0x00000004

Now we know that the program header table is at offset 0x34, that each entry is 0x20 bytes long, and there are 4 entries. Syssgi(ELFMAP) was hence passed a pointer to the third program headers: 0x34 + 2 * 0x20 = 0x74.

If we list the program headers, we are now fully convinced that syssgi(ELFMAP) was given a pointer to the two loadable (see LOAD lines below) program headers. Note that vaddr, paddr, memsz, and other values fit values we saw in the memory dump earlier.

$ objdump -p /lib/rld

/lib/rld:     file format elf32-bigmips

Program Header:
0x70000002 off    0x000000b8 vaddr 0x0fb600b8 paddr 0x0fb600b8 align 
         filesz 0x00000080 memsz 0x00000080 flags r--
0x70000000 off    0x00000138 vaddr 0x0fb60138 paddr 0x0fb60138 align 
         filesz 0x00000018 memsz 0x00000018 flags r--
    LOAD off    0x00000000 vaddr 0x0fb60000 paddr 0x0fb60000 align 
         filesz 0x00035000 memsz 0x00035000 flags r-x
    LOAD off    0x00038000 vaddr 0x0fbd8000 paddr 0x0fbd8000 align 
         filesz 0x00002000 memsz 0x00002000 flags rw-

We also discover that the return address is the vaddr field of the first loadable section; that is, the first section in the program header array.

As a conclusion on this topic, I would say that it is possible to guess what an undocumented system call such as syssgi(ELFMAP) does, and generally what arguments it expects, but it is really much easier if you already have an idea of what you are looking for.

Pages: 1, 2, 3

Next Pagearrow

Sponsored by: