Skip to main content

ELF symbols

Function and variable names are called symbols, they must be translated into offsets and addresses at compilation time. The compiler exports symbolic information into the output object, that holds symbols and interfaces to them (local, external).

Linkers and debuggers works with symbols accessing the interfaces and the Symbol Table. Debugging is possible, but harder, without symbols, as in a stripped elf. It's possible to remove symbol tables or its entries


ELF symbol

In an ELF file there is a Symbol Table (max two) as an array of structures called Elf32_Sym or Elf64_Sym

/* Symbol table entry.  */
typedef struct
{
    Elf32_Word      st_name;          /* Symbol name (string tbl index) */
    Elf32_Addr      st_value;         /* Symbol value                   */
    Elf32_Word      st_size;          /* Symbol size                    */
    unsigned char   st_info;          /* Symbol type and binding        */
    unsigned char   st_other;         /* Symbol visibility              */
    Elf32_Section   st_shndx;         /* Section index                  */
} Elf32_Sym;

typedef struct
{
    Elf64_Word     st_name;           /* Symbol name (string tbl index) */
    unsigned char  st_info;           /* Symbol type and binding        */
    unsigned char  st_other;          /* Symbol visibility              */
    Elf64_Section  st_shndx;          /* Section index                  */
    Elf64_Addr     st_value;          /* Symbol value                   */
    Elf64_Xword    st_size;           /* Symbol size                    */
} Elf64_Sym;

st_name

If st_name isn't unitialized the the symbol hasn't a name.

st_info

In st_info there are binding attributes (linkage visibility and behavior when the symbol is externally referenced) Common binding:

  • STB_LOCAL : invisible from outside
  • STB_GLOBAL: visible from outside
  • STB_WEAK : global symbol but it can be redefined

Common types:

  • STT_NOTYPE : type not specified
  • STT_OBJECT : symbol is a data object (variable).
  • STT_FUNC : symbol is a code object (function).
  • STT_SECTION: symbol is a section.

To get these fields a set of bitmasks are used

  • ELF64_ST_BIND(info) ((info) >> 4 )
  • ELF64_ST_TYPE(info) ((info) & 0xf)

st_other

Information about symbol visibility, how a symbol can be accessed after it become part of an object:

  • STV_DEFAULT : default visibility, it is equal to symbol’s binding type
  • STV_PROTECTED: it is visible by other objects, but cannot be preempted
  • STV_HIDDEN : invisible
  • STV_INTERNAL : internal visiblity

Symbol binding refers to an external object referencing a symbol at linking time Symbol visibility refers on the original object and to an external object referencing the symbol of interest, at runtime

Macro to get visibility information:

  • ELF64_ST_VISIBLITY(o) ((o) & 0x3)

st_shndx

Every symbol is associated with a section, st_shndx contains its index in the Section Header Table

Common section type:

  • SHT_UNDEF: section is not present in the object. The symbol is imported
  • SHT_PROGBITS: section is defined in current object
  • SHT_SYMTAB, SHT_DYNSYM: Symbol Table (.symtab, .dynsym)
  • SHT_STRTAB, SHT_DYNSTR: String Table (.strtab, .dynstr)
  • SHT_REL: Relocation Table without explicit addends (.rel.dyn, .rel.plt)
  • SHT_RELA: Relocation Table with explicit addends (.rela.dyn, .rela.plt)
  • SHT_HASH: Hash Table for dynamic symbol resolution (.gnu.hash)
  • SHT_DYNAMIC: section holding Dynamic Linking information (.dynamic)
  • SHT_NOBITS: section takes no space in disk (.bss)

st_value

Symbol value for an entry

  • For ET_REL files this value represents a section offset
  • For ET_EXEC or ET_DYN files this value represents a virtual address If it is equal to 0 and the section pointed by st_shndx has a sh_type equal to SHT_UNDEF, then this symbol is imported (so its value is resolved at runtime by RTLD(ld.so))

st_size

st_size contains symbol's size


String Table

In an ELF are commont two Symbol Tables: .symtab and .dynsym. The .symtab is the global Symbol Table of the object, it has a Sting Table called .strtab (they have the same number of entries).

The .dynsym Symbol Table contains symbols for Dynamic Linking, its strings are in the .dynstr String Table


A stripped binary hasn't .symtab and .strtab, so reversing and debugging is harder, but some symbol can be retrieved by the .dynsym located at DT_SYMTAB entry in the PT_DYNAMIC segment.

Dynamically linked binaries can be stripped but .dynsym and .dynstr cannot be removed


References: