Go to the first, previous, next, last section, table of contents.

Symbol information in symbol tables

This section examines more closely the format of symbol table entries and how stab assembler directives map to them. It also describes what transformations the assembler and linker make on data from stabs.

Each time the assembler encounters a stab in its input file it puts each field of the stab into corresponding fields in a symbol table entry of its output file. If the stab contains a string field, the symbol table entry for that stab points to a string table entry containing the string data from the stab. Assembler labels become relocatable addresses. Symbol table entries in a.out have the format:

struct internal_nlist {
  unsigned long n_strx;         /* index into string table of name */
  unsigned char n_type;         /* type of symbol */
  unsigned char n_other;        /* misc info (usually empty) */
  unsigned short n_desc;        /* description field */
  bfd_vma n_value;              /* value of symbol */

For .stabs directives, the n_strx field holds the character offset from the start of the string table to the string table entry containing the "string" field. For other classes of stabs (.stabn and .stabd) this field is null.

Symbol table entries with n_type fields containing a value greater or equal to 0x20 originated as stabs generated by the compiler (with one random exception). Those with n_type values less than 0x20 were placed in the symbol table of the executable by the assembler or the linker.

The linker concatenates object files and does fixups of externally defined symbols. You can see the transformations made on stab data by the assembler and linker by examining the symbol table after each pass of the build, first the assemble and then the link.

To do this use nm with the -ap options. This dumps the symbol table, including debugging information, unsorted. For stab entries the columns are: value, other, desc, type, string. For assembler and linker symbols, the columns are: value, type, string.

There are a few important things to notice about symbol tables. Where the value field of a stab contains a frame pointer offset, or a register number, that value is unchanged by the rest of the build.

Where the value field of a stab contains an assembly language label, it is transformed by each build step. The assembler turns it into a relocatable address and the linker turns it into an absolute address. This source line defines a static variable at file scope:

3  static int s_g_repeat

The following stab describes the symbol.

26 .stabs "s_g_repeat:S1",38,0,0,_s_g_repeat

The assembler transforms the stab into this symbol table entry in the `.o' file. The location is expressed as a data segment offset.

21 00000084 - 00 0000 STSYM s_g_repeat:S1

in the symbol table entry from the executable, the linker has made the relocatable address absolute.

22 0000e00c - 00 0000 STSYM s_g_repeat:S1

Stabs for global variables do not contain location information. In this case the debugger finds location information in the assembler or linker symbol table entry describing the variable. The source line:

1 char g_foo = 'c';

generates the stab:

21 .stabs "g_foo:G2",32,0,0,0

The variable is represented by the following two symbol table entries in the object file. The first one originated as a stab. The second one is an external symbol. The upper case D signifies that the n_type field of the symbol table contains 7, N_DATA with local linkage (see Table B). The value field following the file's line number is empty for the stab entry. For the linker symbol it contains the rellocatable address corresponding to the variable.

19 00000000 - 00 0000  GSYM g_foo:G2
20 00000080 D _g_foo

These entries as transformed by the linker. The linker symbol table entry now holds an absolute address.

21 00000000 - 00 0000  GSYM g_foo:G2
215 0000e008 D _g_foo

Go to the first, previous, next, last section, table of contents.