GPUTILS Relocatable Object HowTo

Craig Franklin

May 3, 2004

1. Introduction

This is a quick description of how to use gputils to generate relocatable objects and how to link those objects to generate an executable. This document is very brief. It is no substitute for the Microchip document.

This information will be incorporated into the gputils manual at some point in the future.

2. What are relocatable objects?

They are files which contain machine code, symbols, and relocation information. The relocation information allows the file to be placed "anywhere" in memory. gputils uses Common Object File Format (COFF). A good book describing COFF is "Understanding and Using COFF" by Gircys. It is out of print, but you can still buy used copies. gputils users shouldn't need the book, but the developers might.

3. How are they used?

The code is assembled into a COFF. After all the code is compiled, the coff are input into the linker. Symbols are resolved, addresses are assigned, and the machine code is patched with the new addresses. The output from the linker is an absolute executable object.

4. Why relocatable objects?

Most development tools create then link relocatable objects to generate an executable. The exception is some tools for microcontrollers. The applications are relatively small so creating one big file isn't impractical.

Using relocatable objects does have advantages:

  1. Files can have local name spaces. The user chooses what symbols are global.
  2. Code can be written without regard to addresses. This makes it easier to write and reuse.
  3. The objects can be archived to create a library, which also simplifies reuse.
  4. Recompiling a project can be faster, because you only compile the portions that have changed.

For PICs, it has one big disadvantage. The bank and page control is a challenge.

5. Generating objects

You are interested in data memory and program memory. In absolute code, you have orgs to assign the start address of program memory and cblock to generate a block of data memory. In relocatable code, program memory is created using the code directive and uninitialized data memory using udata.

Take a look at the following code segment:

	processor 16f877
	include "p16f877.inc"

	udata
mem1	res	1
mem2	res	2
mem3	res	1
; symbols from other modules

	extern	_main

	code
_init
	banksel	mem1
	movlw	0
	movwf	mem1
	movwf	mem2
	movwf	mem2 + 1
	movwf	mem3
	pagesel	_main
	goto	_main
; global symbols in this module
	global	mem1
	global	mem2
	global	_init
	end

4 bytes of uninitialized data are reserved. A code segment to initialize the data starts at symbol _init. Once complete the code branches to _main. Mem1 and mem2 are global file registers. mem3 is static, which is a waste considering it is only initialized and never used.

This file would be assembled by gpasm:

gpasm -c init.asm
gpasm would output a COFF, init.o.

You can assign the section address in the assembler by adding an address to the section directive (udata or code). This is not recomended. You don't want to assign the address at assembly time, that would defeat the purpose.

	code	0x100
_init
	banksel	mem1
	movlw	0
	movwf	mem1
	movwf	mem2
	movwf	mem2 + 1
	movwf	mem3
	pagesel	_main
	goto	_main

Multiple sections can exist in the same file, but they must have different names. The section name proceeds the section directive. If no name is provided a default name is used.

	code
_init
	banksel	mem1
	movlw	0
	movwf	mem1
	movwf	mem2
	movwf	mem2 + 1
	movwf	mem3
	pagesel	_main
	goto	_main

mycode	code
	banksel	mem1
	incf	mem1, f

Other types of sections exist, it is beyond the scope of this document to describe them all. See the document in the intro for a more detailed description.

6. Viewing objects

gpvo is a tool for viewing objects. If you are interested in seeing how things work, use it.

gpvo init.o | less

7. Linking objects

So you have assembled several objects and now you need to make a COD file for simulation and a hex file for programming. gplink takes care of this.

gplink only requires the objects and a linker script to build the required output files. A set of scripts are included in /usr/share/gputils/lkr. These scripts were generated by Microchip. They were intended to cutomized by the user, but for many applications they can work as is.

Commanding:

gplink -m -c -s /usr/share/gputils/lkr/16f877.lkr main.o init.o isr.o

Will result in a map file (-m) to be output. This file contains the final addresses assigned to the data and program memory. An executable coff (-c) that is good for reference and simulation in MPLAB. Also a set of output files a.hex and a.cod. The default base filename is "a". It is best to specify your own output name using "-o".

In the future the path to the scripts will be added, just like the path to the headers for gpasm. For now, use the full path or copy the file to your working directory.

8. Simulating the executable

Gplink outputs a COD file that is compatible with gpsim. Gpsim will generate a few new warnings. One will be about not finding a list file. Others may be generated about not using gpasm. These warnings can be ignored. They will be fixed in a future release of gpsim.

9. Creating Libraries

If you have a collection of objects they can be combined into one archive. The archive is a convient way to link an application against a common library. The tool is gplib. It is very easy to use.

gplib -c math.a mult.o add.o sub.o exp.o

Creates a new archive math.a. The name is arbitary. It could be called "math.lib" or "math". gputils doesn't use file extensions to determine file types.

Then when you link the application add math.a to the list of objects

gplink -m -c -s /usr/share/gputils/lkr/16f877.lkr main.o init.o isr.o math.a

gplink will only extract those archive members that are required to resolve external references. So the application won't necessarily contain the code of all the archive members.

10. Makefiles

Here is one of the Makefiles I have been working with. It can be a template for you:

SCRIPT = 16f877.lkr
OBJECTS = main.o startup.o isr.o i2c.o
OUTPUT = example.hex

all:		$(OUTPUT)

$(OUTPUT):	$(OBJECTS) $(SCRIPT)
	gplink --map -c -s $(SCRIPT) -o $(OUTPUT) $(OBJECTS)

%.o:		%.asm
	gpasm -c $<

clean:
	rm -f *.o *.lst *.map *.hex

i2c.o:		i2c.asm common.inc

isr.o:		isr.asm common.inc

main.o:		main.asm common.inc

startup.o:	startup.asm common.inc

11. The Future

There are many features that are planned. Linker optimizations, assembler extensions for high level languages. ...

I will try to keep this document updated. Please send me your comments and questions.