Skip to content

Instantly share code, notes, and snippets.

Last active November 3, 2020 04:53
What would you like to do?

These are notes on the bfd API, see more:

The very top-level of GNU Linker source code

  - lang_process()
  - ldwrite()
  - lang_check_relocs
    - bfd_link_check_relocs   - Phase 1, book keeping
  - ldemul_before_allocation  - Phase 2, creating space
  - ldemul_after_allocation
  - bfd_final_link            - Phase 3 and 4, relocate_section and finish

ld/emultempl/elf.em - generates ldemul_* apis - backed by elf bfd backend
  - ldelf_before_allocation()
  - ldelf_after_allocation()

   - bfd_elf_size_dynamic_sections

Implementations of BFD apis

bfd/linker.c - top level
  - bfd_link_check_relocs - calls BFD_SEND (abfd, _bfd_link_check_relocs, (abfd, info)

bfd/elflink.c - Calls into elf implementations
  - _bfd_elf_link_check_relocs

bfd/elf32-or1k.c - elf implementation for openrisc 
or1k_elf_check_relocs               - BFD API, P1 validate reloc, init .rela sections, .got sections

  - or1k_elf_size_dynamic_sections  - BFD API, P2 calculate section sizes
    - allocate_dynrelocs - sreloc (finally alloc space)

bfd/elflink.c - These 4 functions all call into _bfd_elf_link_create_dynamic_sections()
      - _bfd_elf_create_dynamic_sections

  _bfd_elf_create_dynamic_sections    - BFD API, P2 generic code to create sections, .plt, .rela.bss etc

    - bfd_elf_gc_common_finalize_got_offsets - local_got.offsets setup
  - elf_link_input_bfd
    - or1k_elf_relocate_section      - BFD API, P3 main worker writes to sections
  - travers(elf_link_output_extsym) - called 2 times
    - or1k_elf_finish_dynamic_symbol - BFD API, P4 for a symbol write to .plt, .got + .got.rela
  - or1k_elf_finish_dynamic_sections - BFD API, P4 add final things to .plt, etc

$ grep 'elf_link_input_bfd\|elf_link_output_extsym\|finish_dynamic_sections' bfd/elflink.c 

elf_link_output_extsym (struct bfd_hash_entry *bh, void *data)
elf_link_input_bfd (struct elf_final_link_info *flinfo, bfd *input_bfd)
                  if (! elf_link_input_bfd (&flinfo, sub))
  bfd_hash_traverse (&info->hash->table, elf_link_output_extsym, &eoinfo);
  bfd_hash_traverse (&info->hash->table, elf_link_output_extsym, &eoinfo);
      if (! (*bed->elf_backend_finish_dynamic_sections) (abfd, info))

Function Docs

Phase 1 - book keeping (check_relocs)

The or1k_elf_check_relocs function is called during the first phase to validate relocations, returns FALSE if there are issues. It also does some book keeping.

  • abfd - The current elf object file we are working on
  • sec - The current elf section we are working on
  • info - the bfd API
  • relocs - The relocations from the current section
static bfd_boolean                                                                       
or1k_elf_check_relocs (bfd *abfd,                                                        
                       struct bfd_link_info *info,                                       
                       asection *sec,                                                    
                       const Elf_Internal_Rela *relocs)
#define elf_backend_check_relocs        or1k_elf_check_relocs

Phase 2 - creating space (size_dynamic_sections + _bfd_elf_create_dynamic_sections)

The or1k_elf_size_dynamic_sections function iterates over all object files to calculate the size of stuff, it uses:

  • info - the API to bfd provides access to everything, this function uses:
    • or1k_elf_hash_table (info) - called htab a reference to elf_link_hash_table which has sections.
    • htab->root.splt - the plt section
    • htab->root.sgot - the got section
    • htab->root.srelgot - the relgot section (relocations against the got)
    • htab->root.sgotplt - the gotplt section
    • htab->root.dynobj - a special bfd to which sections are created (created in or1k_elf_check_relocs)
    • root.dynamic_sections_created - true if sections like .interp have been created by the linker
    • info->input_bfds - loop over all bfds (elf objects)

Settig up the sizes of the .got section (global offset table) and .plt section (procedure link table) is done by iterating through all symbols with the allocate_dynrelocs interator.

Sub function of or1k_elf_size_dynamic_sections allocate_dynrelocs is used to additionaly set size of .gotplt which sometime later gets combinted with the .got somehow. The allocate_dynrelocs is a visitor function that is used when iterating over each elf_link_hash_entry which represents a symbol.


  allocate_dynrelocs(h) {
     if (h->plt.refcount > 0) {
        .gotplt->size ++;
        .relocations->size ++;
     if (h->got.refcount > 0) {
        .got->size ++;
        .relocations->size ++;
     do something with h->dyn_relocs which I don't understand
     but in the end it doe sreloc->size ++

The sub function of allocate_dynrelocs or1k_set_got_and_rela_sizes is used to increment .got and .rela section sizes per tls symbols.

static bfd_boolean                                                              
or1k_elf_size_dynamic_sections (bfd *output_bfd ATTRIBUTE_UNUSED,               
                                struct bfd_link_info *info)

#define elf_backend_size_dynamic_sections       or1k_elf_size_dynamic_sections
#define elf_backend_create_dynamic_sections     _bfd_elf_create_dynamic_sections

Phase 3 - linking (relocate_section)

For each input section in an input bfd (.o file) figure out where they will exist in the output bfd.

Fill in relocation placeholders in .text sections. Fill out data in .got and .rela sections.

static bfd_boolean                                                              
or1k_elf_relocate_section (bfd *output_bfd,                                     
                           struct bfd_link_info *info,                          
                           bfd *input_bfd,                                      
                           asection *input_section,                             
                           bfd_byte *contents,                                  
                           Elf_Internal_Rela *relocs,                           
                           Elf_Internal_Sym *local_syms,                        
                           asection **local_sections)  
#define elf_backend_relocate_section    or1k_elf_relocate_section

Phase 4 - finishing up (finish_dynamic_symbol + finish_dynamic_sections)

Write to .plt

static bfd_boolean                                                              
or1k_elf_finish_dynamic_sections (bfd *output_bfd,                              
                                  struct bfd_link_info *info) 

static bfd_boolean                                                              
or1k_elf_finish_dynamic_symbol (bfd *output_bfd,                                
                                struct bfd_link_info *info,                     
                                struct elf_link_hash_entry *h,                  
                                Elf_Internal_Sym *sym)

#define elf_backend_finish_dynamic_sections     or1k_elf_finish_dynamic_sections
#define elf_backend_finish_dynamic_symbol       or1k_elf_finish_dynamic_symbol 

Insane things inbetween

These are important but I cant see why they need to be specific to openrisc or anyone writing a new port.

#define elf_backend_copy_indirect_symbol        or1k_elf_copy_indirect_symbol
#define elf_backend_adjust_dynamic_symbol       or1k_elf_adjust_dynamic_symbol  
Copy link

There is a whole article on this now How TLS Works ...

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment