gcl-devel
[Top][All Lists]
Advanced

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

[Gcl-devel] ld from 2.14.90.0.8 puts no value into undefined symbols


From: Bernhard Kaindl
Subject: [Gcl-devel] ld from 2.14.90.0.8 puts no value into undefined symbols
Date: Wed, 31 Mar 2004 23:25:47 +0200 (CEST)

Hi,
   ltrace was also hit by the binutils change in 2.14.90.0.8
which was discussed under this subject here and on the bintutils
list:

http://mail.gnu.org/archive/html/gcl-devel/2004-02/msg00258.html
http://sources.redhat.com/ml/binutils/2004-03/msg00008.html

I had to implement a fix for ltrace and I had no chance to do
some workaround as it was apparently done here as far as I
could understand.

ltrace was also affected (apparently like gcl) by no longer having
the address of the PLT table entries of the non-local function in
available in the symbol table.

ltrace relies on the PLT table entry address to be able to set
break points for library call traceing(it's purpose)

I fixed ltrace to calculate missing PLT table entry addresses
so that it works again (I've seen it on i386, but it should
still work on all architectures, I assume):

The fix is:

        for(i = 0; i < ehdr->e_shnum; i++) {

+               char * secname = maddr
+                        + shdr[ehdr->e_shstrndx].sh_offset+shdr[i].sh_name;
+
+               if (!strncmp(secname, ".plt", 5)) {
+                       lte->plt_start   = (void *)shdr[i].sh_addr;
+                       lte->plt_entsize = shdr[i].sh_entsize;
+               }

Here(where ltrace loops over all sections to find the section of
the symbol table), I'm adding a check which also checks for the
section called ".plt", because the address where it's mapped into
memory is the PLT table entry of the first non-local function.

+       lte.plt_addr = lte.plt_start;
        for(i = 0; i < lte.symtab_len / sizeof(Elf_Sym); i++) {
                Elf_Sym *symtab = lte.symtab;
                char *strtab = lte.strtab;
 
-               if (!symtab[i].st_shndx && symtab[i].st_value) {
+               if (!symtab[i].st_shndx
+                 && ELF32_ST_BIND(symtab[i].st_info) != STB_LOCAL
+                 && ELF32_ST_TYPE(symtab[i].st_info) == STT_FUNC) {
+
+                       /* Address of next entry in plt table */
+                       lte.plt_addr += lte.plt_entsize * sizeof(void *);

Then, when looping over the symbol table, I check if the entry is a
non-local function, and only if it is, I'm incrementing the pointer
into the PLT table which I just got before.

+       if (lte->symtab[i].st_value)
+               library_symbols->enter_addr = (void *)lte->symtab[i].st_value;
+       else
+               library_symbols->enter_addr = lte->plt_addr;

Then, if the toolchain of the does not provide a address value in the
symbol table, I use the calculated PLT entry address.

The structures and macros used here are defined on Linux in /usr/include/elf.h

The code above worked as far as I could see.

Bernhard
==============================================================

PS:

I'm sure libbfd can provide the same ELF section information.

(ltrace just mmaps the binary and addresses it directly using elf.h)

Here you can see the PLT start address as it's displayed by objdump
from binutils which used libbfd:

objdump -h /usr/bin/printf | fgrep ' .plt'
 10 .plt          000002f0  08048aa8  08048aa8  00000aa8  2**2
----------------------------^^^^^^^^

And objdump -T displays the symbol table:

objdump -T /usr/bin/printf

/usr/bin/printf:     file format elf32-i386

DYNAMIC SYMBOL TABLE:
00000000      DF *UND*  0000008c  GLIBC_2.0   nl_langinfo
...

Only increase the pointer into the PLT on such functions, not 
on locally defined smybols like these:

0804bc84 g    DO .rodata        00000004  Base        _IO_stdin_used
0804dcec g    DO .bss   00000004  GLIBC_2.0   optind




reply via email to

[Prev in Thread] Current Thread [Next in Thread]