the symbol table
When you give a function or a global variable a name in your code, that name is just for you and the compiler; the running machine deals only in numeric addresses. The symbol table is the little directory inside an object file that bridges the two: it lists the named things (called symbols) that this file is concerned with, and for each one records what is known about it so far. It is the index card catalogue the linker reads to figure out how to connect separate files together.
Each entry pairs a name with information: which section it lives in, its offset within that section, whether it is a function or a data object, whether it is visible to other files (external) or private to this one (local, as static makes it), and crucially whether it is defined here or merely referenced here. A symbol your file defines, such as a function add you wrote, gets an entry pointing at its location in .text. A symbol your file uses but does not define, such as printf, gets an entry marked undefined, a note that says 'someone else must supply this'.
The symbol table is the raw material of linking. The linker reads every object file's symbol table, matches each undefined symbol in one file against a defining symbol in another (or in a library), and writes down the final address so the reference can be patched. If a name is referenced but defined nowhere, you get the 'undefined reference' linker error; if the same name is defined in two files, you get 'multiple definition'. Tools like nm print the symbol table directly, with letters such as T for a defined text symbol and U for an undefined one.
$ nm main.o U add # main uses add, but does not define it (undefined) 0000000000000000 T main # main is defined here, in .text # the linker must find a 'T add' in some other .o or library to satisfy the 'U add'
The symbol table records both what a file defines (T) and what it leaves undefined (U).
A static function or variable is marked local in the symbol table, so it is invisible to other files; two files can each have their own static helper of the same name with no clash.