Assemblers and high-level language compilers do not produce a complete program that is ready to run. Instead, a linker program (sometimes called a linkage editor) is provided as part of the system software. The principal tasks of the linker require that it be able to perform three functions:
Like most assemblers and compilers, a linker may require at least two passes through all the object files. On the first pass, symbols are gathered into a composite symbol table for the entire program. If any external symbols still lack values at the end of this first pass, one or more system libraries are consulted. The production of an executable program may be aborted if any symbols remain unresolved. A linker also tabulates the total lengths of the code and data sections i.e., the maximum value that the location counter for each section had reached. After the first pass, the linker arranges the code and data sections end to end into a linear sequence, perhaps alphabetically or perhaps in an order requested by the programmer. Only then can final addresses for all symbols be established. On the second pass, space for the executable image file is allocated on disk. This file is then treated as a giant array. As the linker rereads all the object files, it stores each item at the correct address. Some linkers offer the potential to initialize data elements to a value such as zero, but cautious programmers never depend on such behavior. Map filesSome linkers can produce map files, which convey a human-readable tabulation of what is stored where. Some linkers may sort symbols by name or by value. The gcc and ecc commands use the options -W or -Qoption to convey requests to specific software components of their respective programming environments. If we want the linker component to produce a map file, we should use a command line of the form L> gcc -Wl,-M=prog.lis ... L> ecc Qoption,ld,-M=prog.map ... where no spaces can occur within the entire -W or -Qoption construct. Figure 3-3 shows excerpts from a map file for SQUARES produced by gcc. Figure 3-3 Information from a link map for SQUARES (gcc)Memory Configuration Name Origin Length Attributes *default* 0x0000000000000000 0xffffffffffffffff Linker script and memory map LOAD /usr/lib/crt1.o LOAD /usr/lib/crti.o LOAD /usr/local/lib/gcc-lib/ia64-unknown-linux/3.0/crtbegin.o LOAD /tmp/ccTiVqfc.o LOAD /usr/local/lib/gcc-lib/ia64-unknown-linux/3.0/libgcc.a LOAD /usr/lib/libc.so START GROUP LOAD /lib/libc.so.6.1 LOAD /usr/lib/libc_nonshared.a END GROUP LOAD /usr/local/lib/gcc-lib/ia64-unknown-linux/3.0/libgcc.a LOAD /usr/local/lib/gcc-lib/ia64-unknown-linux/3.0/crtend.o LOAD /usr/lib/crtn.o 0x40000000000001c8 .=(0x4000000000000000+SIZEOF_HEADERS) [bulk of the content omitted here] OUTPUT(bin/squares elf64-ia64-little) The nm command shows a list of symbols for an executable file. Figure 3-4 shows sample nm output for SQUARES. We see that the GNU linker put main in the text section of SQUARES at address 0x4000000000000520 and began allocating spaces for the three computed data values at 0x6000000000000760. Notice that the relative addresses, done versus main and sq3 versus sq1, are what we would have expected based upon the listing file from the assembler (Figure 3-2). We shall use this information in the discussion of the symbolic debugger. |