Skip to content
Symbols
step 1/5

Reading — step 1 of 5

Read

~1 min readStatic Loading

Symbols

A symbol is a named entry: function, variable, section.

Symbol entry (64-bit):

struct Symbol {
    uint32_t name;       // offset into strtab
    uint8_t  info;       // bind:4 | type:4
    uint8_t  other;      // visibility
    uint16_t shndx;      // section index, or SHN_UNDEF
    uint64_t value;      // address (or value for absolute)
    uint64_t size;
};

Bind:

  • STB_LOCAL: file-scope.
  • STB_GLOBAL: visible across files.
  • STB_WEAK: like global but yields to STB_GLOBAL.

Type:

  • STT_FUNC: function.
  • STT_OBJECT: data variable.
  • STT_SECTION: section symbol.
  • STT_FILE: source filename.
  • STT_NOTYPE: unspecified.

Visibility:

  • STV_DEFAULT: visible.
  • STV_HIDDEN: not visible to dynamic linker (file-local).
  • STV_PROTECTED: visible but call goes through GOT (no preemption).

Symbols in .o:

  • Defined: have non-zero shndx + value.
  • Undefined: shndx = SHN_UNDEF, value = 0. Linker resolves.

Symbol resolution (linker):

  • Each input .o contributes symbols.
  • Global symbol defined in two files → MULTIPLE_DEFINITION error (unless one is weak).
  • Undefined symbol not found anywhere → UNDEFINED_REFERENCE error.

Symbol versioning:

  • glibc: foo@@GLIBC_2.4 vs foo@GLIBC_2.5.
  • Multiple versions in one .so for ABI compat.
  • Linker picks based on what was at build time.

Mangled names (C++):

  • _ZN3fooEv = foo().
  • Need c++filt or nm -C to demangle.

nm shows symbols. T = text (function), D = data (initialized), B = bss, U = undefined.

Discussion

Ask a question, share an insight, or help someone who’s stuck.

Sign in to post a comment or reply.

Loading…