Chapter 3. C Language Features
3.11 Linking Programs
The compiler will automatically invoke the linker unless the compiler has been requested to stop after producing an intermediate file.
The linker will run with options that are obtained from the command-line driver. These options specify the memory of the device and how the psects should be placed in the memory. No linker scripts are used.
The linker options passed to the linker can be adjusted by the user, but this is only required in special circumstances. See Section 2.7.7 “-L-: Adjust Linker Options Directly” for more information.)
The linker creates a map file which details the memory assigned to psects and some objects within the code. The map file is the best place to look for memory information. See Section 5.4 “Map Files” for a detailed explanation of the detailed information in this file.
3.11.1
Replacing Library Modules
HI-TECH C comes with a librarian, LIBR, which allows you to unpack a library file and replace modules with your own modified versions. See Section 6.2 “Librarian”. How- ever, you can easily replace a library module that is linked into your program without having to do this.
If you add to your project a source file which contains the definition for a routine with the same name as a library routine, then the library routine will be replaced by your rou- tine. This works due to the way the compiler scans source and library files.
When trying to resolve a symbol (a function name, or variable name, for example) the compiler first scans all the source modules for the definition. Only if it cannot resolve the symbol in these files does it then search the library files.
If the symbol is defined in both a source file and a library file, the compiler will never actually search the libraries for this symbol and no error will result. This may not be true if a symbol is defined twice in source files and an error may result if there is a conflict in the definitions.
All libraries are written C code, and the p-code libraries that contain these library rou- tines are actually passed to the code generator, not the linker, but both these applica- tions work in the way described above in resolving library symbols.
You cannot replace a C library function with an equivalent written in assembly code using the above method. If this is required, you will need to use the librarian to edit or create a new library file.
3.11.2
Signature Checking
The compiler automatically produces signatures for all functions. A signature is a 16-bit value computed from a combination of the function’s return data type, the number of its parameters and other information affecting the calling sequence for the function. This signature is output in the object code of any function referencing or defining the function.
At link time the linker will report any mismatch of signatures. HI-TECH C is only likely to issue a mismatch error from the linker when the routine is either a precompiled object file or an assembly routine. Other function mismatches are reported by the code
C Language Features
method of determining the correct signature for a function is to write a dummy C func- tion with the same prototype and check the assembly list file using the --ASMLIST
option (see Section 2.7.17 “--ASMLIST: Generate Assembler List Files”).
For example, suppose you have an assembly language routine called _widget which takes two int arguments and returns a char value. The prototype used to call this function from C would be:
extern char widget(int, int);
Where a call to _widget is made in the C code, the signature for a function with two
int arguments and a char return value would be generated. In order to match the cor- rect signature, the source code for widget needs to contain an assembler SIGNAT
directive which defines the same signature value. To determine the correct value, you would write the following code:
char widget(int arg1, int arg2) {
}
The resultant assembler code seen in the assembly list file includes the following line: SIGNAT _widget,8249
The SIGNAT directive tells the assembler to include a record in the .obj file which associates the value 8249 with symbol _widget. The value 8249 is the correct signa- ture for a function with two int arguments and a char return value.
If this directive is copied into the assembly source file which contains the _widget
code, it will associate the correct signature with the function and the linker will be able to check for correct argument passing.
If a C source file contains the declaration: extern char widget(long);
then a different signature will be generated and the linker will report a signature mis-match which will alert you to the possible existence of incompatible calling conventions.
3.11.3
Linker-Defined Symbols
The linker defines some special symbols that can be used to determine where some psects where linked in memory. These symbols can be used in code, if required. The link address of a psect can be obtained from the value of a global symbol with name __Lname where name is the name of the psect. For example, __LbssBANK0 is the low bound of the bssBANK0 psect.
The highest address of a psect (i.e. the link address plus the size) is represented by the symbol __Hname.
If the psect has different load and link addresses, the load start address is represented by the symbol __Bname.
Not all psects are assigned these symbols, in particular those that are not placed in memory by a -P linker option (not driver option). See Section 5.2.18 “-Pspec”. Psect names may change from one device to another.