gcclinkersymbolselfsymbol-table

Undefined reference to symbol in hand-written ELF file


I have hand-written an ELF32 object file that I would like to link via. gcc but I get an undefined reference when I try to use my function/label. I have it defined in a test C file as extern yet this does not change anything.

This object file contains the following assembly:

00000000 <func>:
   0:   31 c0                   xor    %eax,%eax
   2:   40                      inc    %eax
   3:   b3 2a                   mov    $0x2a,%bl
   5:   cd 80                   int    $0x80

What you see here is the output from objdump -S test.o which shows that objdump is very much capable of finding my .text section.

My readelf output is:

ELF Header:
  Magic:   7f 45 4c 46 01 01 01 00 00 00 00 00 00 00 00 00 
  Class:                             ELF32
  Data:                              2's complement, little endian
  Version:                           1 (current)
  OS/ABI:                            UNIX - System V
  ABI Version:                       0
  Type:                              REL (Relocatable file)
  Machine:                           Intel 80386
  Version:                           0x1
  Entry point address:               0x0
  Start of program headers:          0 (bytes into file)
  Start of section headers:          128 (bytes into file)
  Flags:                             0x0
  Size of this header:               52 (bytes)
  Size of program headers:           0 (bytes)
  Number of program headers:         0
  Size of section headers:           40 (bytes)
  Number of section headers:         5
  Section header string table index: 1

Section Headers:
  [Nr] Name              Type            Addr     Off    Size   ES Flg Lk Inf Al
  [ 0]                   NULL            00000000 000000 000000 00      0   0  0
  [ 1] .shstrtab         STRTAB          00000000 000034 000021 00      0   0  1
  [ 2] .text             PROGBITS        00000000 000060 000007 00  AX  0   0 16
  [ 3] .strtab           STRTAB          00000000 000070 00000d 00      0   0  1
  [ 4] .symtab           SYMTAB          00000000 000150 000040 10      3   4  4

Symbol table '.symtab' contains 4 entries:
   Num:    Value  Size Type    Bind   Vis      Ndx Name
     0: 00000000     0 NOTYPE  LOCAL  DEFAULT  UND 
     1: 00000000     0 FILE    LOCAL  DEFAULT  ABS test.S
     2: 00000000     0 SECTION LOCAL  DEFAULT    2 
     3: 00000000     0 NOTYPE  GLOBAL DEFAULT    2 func

Which furthermore shows I have a valid symbol table and sections.

My question is, what are the exact conditions for an undefined reference to occur? What have I done incorrectly here that could lead to such an error? Is alignment for every section imperative? I've mostly done that already.

I have my symbol set to global, it is found by these two ELF analysis programs yet GCC still fails to recognise the symbol...

Here is the dump of the ELF file:

00000000: 7f45 4c46 0101 0100 0000 0000 0000 0000  .ELF............
00000010: 0100 0300 0100 0000 0000 0000 0000 0000  ................
00000020: 8000 0000 0000 0000 3400 0000 0000 2800  ........4.....(.
00000030: 0500 0100 002e 7368 7374 7274 6162 002e  ......shstrtab..
00000040: 7465 7874 002e 7374 7274 6162 002e 7379  text..strtab..sy
00000050: 6d74 6162 0000 0000 0000 0000 0000 0000  mtab............
00000060: 31c0 40b3 2acd 8000 0000 0000 0000 0000  1.@.*...........
00000070: 0066 756e 6300 7465 7374 2e53 0000 0000  .func.test.S....
00000080: 0000 0000 0000 0000 0000 0000 0000 0000  ................
00000090: 0000 0000 0000 0000 0000 0000 0000 0000  ................
000000a0: 0000 0000 0000 0000 0100 0000 0300 0000  ................
000000b0: 0000 0000 0000 0000 3400 0000 2100 0000  ........4...!...
000000c0: 0000 0000 0000 0000 0100 0000 0000 0000  ................
000000d0: 0b00 0000 0100 0000 0600 0000 0000 0000  ................
000000e0: 6000 0000 0700 0000 0000 0000 0000 0000  `...............
000000f0: 1000 0000 0000 0000 1100 0000 0300 0000  ................
00000100: 0000 0000 0000 0000 7000 0000 0d00 0000  ........p.......
00000110: 0000 0000 0000 0000 0100 0000 0000 0000  ................
00000120: 1900 0000 0200 0000 0000 0000 0000 0000  ................
00000130: 5001 0000 4000 0000 0300 0000 0400 0000  P...@...........
00000140: 0400 0000 1000 0000 0000 0000 0000 0000  ................
00000150: 0000 0000 0000 0000 0000 0000 0000 0000  ................
00000160: 0600 0000 0000 0000 0000 0000 0400 f1ff  ................
00000170: 0000 0000 0000 0000 0000 0000 0300 0200  ................
00000180: 0100 0000 0000 0000 0000 0000 1000 0200  ................

I've tried already to change the function name, NOTYPE to FUNC and giving the symbol a size, yet nothing fixes the issue. The layout of the symbol table is exactly as my NASM-generated file gives me.

Edit: The file that I am trying to link with my ELF is giving the error:

/usr/bin/ld: foo.o: in function `main':
foo.c:(.text+0x18): undefined reference to `func'
collect2: error: ld returned 1 exit status

from running gcc -m32 foo.o test.o

Source code:

extern void func();

int
main(int argc,
     char **argv)
{
    func();
    return 0;
}

And symbol table of this file after gcc -m32 -c foo.c -o foo.o:

Symbol table '.symtab' contains 15 entries:
   Num:    Value  Size Type    Bind   Vis      Ndx Name
     0: 00000000     0 NOTYPE  LOCAL  DEFAULT  UND 
     1: 00000000     0 FILE    LOCAL  DEFAULT  ABS foo.c
     2: 00000000     0 SECTION LOCAL  DEFAULT    2 
     3: 00000000     0 SECTION LOCAL  DEFAULT    4 
     4: 00000000     0 SECTION LOCAL  DEFAULT    5 
     5: 00000000     0 SECTION LOCAL  DEFAULT    6 
     6: 00000000     0 SECTION LOCAL  DEFAULT    8 
     7: 00000000     0 SECTION LOCAL  DEFAULT    9 
     8: 00000000     0 SECTION LOCAL  DEFAULT   10 
     9: 00000000     0 SECTION LOCAL  DEFAULT    7 
    10: 00000000     0 SECTION LOCAL  DEFAULT    1 
    11: 00000000    38 FUNC    GLOBAL DEFAULT    2 main
    12: 00000000     0 FUNC    GLOBAL HIDDEN     6 __x86.get_pc_thunk.ax
    13: 00000000     0 NOTYPE  GLOBAL DEFAULT  UND _GLOBAL_OFFSET_TABLE_
    14: 00000000     0 NOTYPE  GLOBAL DEFAULT  UND func

Solution

  • The error is best understood by using lld to perform the link:

    ld.lld -m elf_i386  -e main main.o test.o
    ld.lld: error: test.o: non-local symbol (3) found at index < .symtab's sh_info (4)
    

    From the Solaris Linker docs:

    In each symbol table, all symbols with STB_LOCAL binding precede the weak and global symbols. As "Sections" describes, a symbol table section's sh_info section header member holds the symbol table index for the first non-local symbol.

    You must set .symtabs .sh_info to 3, and then your test.o will work.