Relocations against STN_UNDEF

Thomas Schwinge thomas@codesourcery.com
Thu Sep 23 15:37:00 GMT 2010


Hello!

The ELF standard says that STN_UNDEF (symbol index zero, the undefined
symbol index) is to be marked as SHN_UNDEF, undefined symbol.  There is
one exception however: during relocations processing, a relocation
against STN_UNDEF shall be treated as a symbol value of zero.

The BFD code makes use of this, for example when it is writing out all
relocations in bfd/elfcode.h:elf_write_relocs:

    [...]
      1000    for (idx = 0; idx < sec->reloc_count; idx++, dst_rela += extsize)
      1001      {
      1002        Elf_Internal_Rela src_rela;
      1003        arelent *ptr;
      1004        asymbol *sym;
      1005        int n;
      1006  
      1007        ptr = sec->orelocation[idx];
      1008        sym = *ptr->sym_ptr_ptr;
      1009        if (sym == last_sym)
      1010          n = last_sym_idx;
      1011        else if (bfd_is_abs_section (sym->section) && sym->value == 0)
      1012          n = STN_UNDEF;
      1013        else
      1014          {
      1015            last_sym = sym;
      1016            n = _bfd_elf_symbol_from_bfd_symbol (abfd, &sym);
    [...]

That is, if the symbol is (internally) listed in the absolute sections
and it has a value of zero, simply a relocation against STN_UNDEF is
emitted.


For example on ARM, the bl instruction does a PC-relative jump, so to
jump to an absolute value of 0x10000, ``bl 0x10000'' has to keep its
relocation until the final linking is done, to be converted to the proper
PC-relative offset.

    $ cat < ~/sgxx/issue8612/bl_ABS.s
            bl 0x10000
    $ "$PWD"_install/bin/*-as -o bl_ABS.o ~/sgxx/issue8612/bl_ABS.s
    $ "$PWD"_install/bin/*-readelf -r bl_ABS.o 
    
    Relocation section '.rel.text' at offset 0x25c contains 1 entries:
     Offset     Info    Type            Sym.Value  Sym. Name
    00000000  0000001c R_ARM_CALL       

This info value translates to relocation type 28 (R_ARM_CALL) against
symbol index zero (STN_UNDEF).

objdump even translates this that it's an ABSolut value, and no longer
STN_UNDEF:

    $ "$PWD"_install/bin/*-objdump -dr bl_ABS.o
    
    bl_ABS.o:     file format elf32-littlearm
    
    
    Disassembly of section .text:
    
    00000000 <.text>:
       0:   eb003ffe        bl      10000 <.text+0x10000>
                            0: R_ARM_CALL   *ABS*

This STN_UNDEF -> *ABS* conversion is done when reading in the
relocations, in bfd/elfcode.h:elf_slurp_reloc_table_from_section:

      1469        if (ELF_R_SYM (rela.r_info) == 0)
      1470          relent->sym_ptr_ptr = bfd_abs_section_ptr->symbol_ptr_ptr;

That is, if the index is zero -- should use STN_UNDEF here instead of the
zero constant, I'd say? -- then this relocation is marked as being in
BFD's absolute section, instead of undefined, as it'd be from the symbol
table.  This is important, as relocations against undefined symbols will
be processed differently from those against absolute values, etc.

However, this function elf_slurp_reloc_table_from_section for reading in
relocations is not being used in case of LD linking an executable -- the
STN_UNDEF symbol remains in BFD's internal undefined section, and linking
thus fails:

    $ "$PWD"_install/bin/*-ld -o bl_ABS bl_ABS.o
    /scratch/thomas/binutils/HEAD_build_arm-none-eabi_install/bin/arm-none-eabi-ld: warning: cannot find entry symbol _start; defaulting to 0000000000008000
    bl_ABS.o:(.text+0x0): undefined reference to `no symbol'

I wonder why we need this code duplicated in (at least) two places; why
do objdump and ld use different code paths for reading in relocations?

Here is a patch to fix this issue for the ld code path.  There are no
regressions with a --target=arm-none-eabi config.  What other testing
should be done, as this is against a generic (not target-dependent) file?

Index: bfd/elflink.c
===================================================================
RCS file: /cvs/src/src/bfd/elflink.c,v
retrieving revision 1.378
diff -u -p -r1.378 elflink.c
--- bfd/elflink.c	9 Sep 2010 09:55:03 -0000	1.378
+++ bfd/elflink.c	11 Sep 2010 07:32:44 -0000
@@ -9135,6 +9135,13 @@ elf_link_input_bfd (struct elf_final_lin
 	return FALSE;
     }
 
+  /* STN_UNDEF is symbol index zero.  During relocations processing it shall
+     resolve to a symbol value of zero.
+
+     For that to happen, we have to make sure that it will be registered with
+     the "absolute" section.  */
+  set_symbol_value (input_bfd, isymbuf, locsymcount, STN_UNDEF, 0);
+
   /* Find local symbol sections and adjust values of symbols in
      SEC_MERGE sections.  Write out those local symbols we know are
      going into the output file.  */

Success with patched BFD:

    $ "$PWD"_install/bin/*-ld -o bl_ABS bl_ABS.o
    /scratch/thomas/binutils/HEAD_build_arm-none-eabi_install/bin/arm-none-eabi-ld: warning: cannot find entry symbol _start; defaulting to 0000000000008000
    $ "$PWD"_install/bin/*-readelf -r bl_ABS
    
    There are no relocations in this file.
    $ "$PWD"_install/bin/*-objdump -dr bl_ABS
    
    bl_ABS:     file format elf32-littlearm
    
    
    Disassembly of section .text:
    
    00008000 <__data_start-0x8004>:
        8000:       eb001ffe        bl      10000 <__bss_end__-0x4>


This was my first encounter with BFD code, and apart from the time I have
now spent on it, I don't know much about how / where it originated, so
I'd like your input on this matter: is my patch the correct one, or
should this issue be solved differently?  Should the two code paths of
reading in relocations be unified, or is there perhaps a reason they're
different?


Regards,
 Thomas
-------------- next part --------------
A non-text attachment was scrubbed...
Name: not available
Type: application/pgp-signature
Size: 197 bytes
Desc: not available
URL: <https://sourceware.org/pipermail/binutils/attachments/20100923/b17b2529/attachment.sig>


More information about the Binutils mailing list