Dealing with PIC MIPS code
--------------------------

This is yanked from an sgi man page someone had online, and has to do with the
MIPS 32-bit ELF ABI. -- at: http://www.hpcc.nectec.or.th/PCH/man/dso.html

  24) How do I change my assembly language sources to use -KPIC?


     The following refers to the older 32 bit abi using ucode compilers.  For
     n32 and 64 bit abi information, look at the information and pointers in
     the abi(5) manpage.

     Several new assembler directives are added to support generation of PIC.
     You should also get yourself familiar with the MIPS ABI Supplement and
     the PIC coding model it describes.  In addition, files which are to be
     assembled with -KPIC must also be -G 0.  This is normally turned on by
     the driver by default.

     Note that with the exception of (a) and (d), all other directives
     described below will be ignored when -KPIC is not explicitly specified.
     Also, item (d), ".gpword", will be turned into ".word". The result will
     be a NON-PIC version of the same routine.

     a) .option pic2

     This directive forces the assembler to mark the output object file "PIC"
     and activates the following directives.  It overrides the command line
     argument.  Normally, you don't need to specify this directive.  Instead,
     you should use the -KPIC or -non_shared flags to toggle between
     generating PIC or non-PIC.

     Note that even though -KPIC will be made the default for the high-
     language driver (cc/pc/f77) in future releases, it will *NOT* be the
     default for assembly sources.  You will always have to explicitly specify
     -KPIC for compiling .s files.

     b) .cpload reg

     This directive expands into three instructions that sets the gp register
     to the context pointer value for the current function.  The three
     instructions are:
          lui  gp,_gp_disp
          addui     gp,gp,_gp_disp
          addu gp,gp,reg

     _gp_disp is a reserved symbol defined by the linker to be the distance
     between the lui instruction and the context pointer.  This directive is
     required at the beginning of each subroutine that uses the gp register.

     You must add this directive at the beginning of every procedure, with the
     exception of leaf-procedures that do not access any global variables, and
     procedures that are static (i.e., not marked .globl or .extern).

     c) .cprestore offset

     This directive causes the assembler to issue
               sw   gp,offset(sp)
     at the point where it appears.  Additionally, it causes the assembler to
     emit
               lw   gp,offset(sp)

     after every jump-and-link (jal) or branch-and-link (bal) operation,
     thereby restoring the gp register after function calls.  The programmer
     is responsible for allocating the stack space for the gp.  This space
     should be in the saved register area of the stack frame to remain
     consistent with MIPS' calling and debugger conventions.

     d) .gpword local-sym

     This directive is similar to .word except that the relocation entry for
     local-sym has the R_MIPS_GPREL32 type.  After linkage, this results in a
     32-bit value that is the distance between local-sym and the context
     pointer (i.e. the gp).  local-sym must be local.  It is currently used
     for PIC switch tables.

     e) .cpadd reg

     This adds the value of the context pointer (gp) to reg.

     EXAMPLES:
          This is a simplified version of the "hello world" program:
          --------------------------------------------------------------
               .option   pic2
               .data
               .align    2
          $$5:
               .ascii    "hello world\X0A\X00"
               .text
               .align    2
          main:
               .set  noreorder
               .cpload   $25
               .set  reorder
               subu $sp, 40
               sw   $31, 36($sp)
               .cprestore     32
               la   $4, $$5
               jal  printf
               move $2, $0
               lw   $31, 36($sp)
               addu $sp, 40
               j    $31
          ----------------------------------------------------------------
          The actual instructions generated by the assembler will be:

               lui  gp,0      #
               addiu     gp,gp,0        # generated by .cpload
               addu gp,gp,t9  #
               lw   a0,0(gp)  # gp-relative addressing used
               lw   t9,0(gp)  # t9 is used for func. call
               addiu     sp,sp,-40
               sw   ra,36(sp)
               sw   gp,32(sp) # from .cprestore

              jalr  ra,t9          # jal is changed to jalr
               addiu     a0,a0,0
               lw   ra,36(sp)
               lw   gp,32(sp) # activated by .cprestore
               move v0,zero
               jr   ra
               addiu     sp,sp,40
               nop
          ----------------------------------------------------------------

     NOTE:

     The MIPS's ABI required register t9 ($25) be used for indirect function
     call, so .cpload should always use $25.  No reorder mode should also be
     used.  Also, programmers should make sure that t9 is dead before any
     function call.

     If your program uses an indirect jump (jalr), you must also use t9 as the
     jump register.

     If you have an unconditional jump to an external label:
               j  _cerror
         you have to rewrite it into indirect jump via t9, i.e.:
               la t9,_cerror
               j  t9

     If you use branch-and-link (bal) instruction, and if the target procedure
     begins with a .cpload, you have to specify an alternate entry point:

          foo: .set noreorder # callee
               .cpload   $25
               .set reorder
          $$1: ...            # alternative entry point
               ...
               j    $31       # foo returns

          bar: ...            # caller
               ...
               bal  $$1       # by-pass the .cpload
               ...

     This is very important because .cpload assumes register $25 contains the
     address of foo, but in this case $25 is not set up.  Note that since both
     foo and bar reside in the same file, they must have the same value for
     $gp.  So the .cpload instructions can be and must be bypassed.  However,
     since foo can still be called from outside, the .cpload is still
     required.

     Alternatively, if you don't want to have an alternate entry point, you
     can set up register $25 before the bal:
               la   t9,foo
               bal  foo

         but this will be less efficient.

     position-independent jump table (or any table of text addresses).
     Entries of the address table created by .gpword are converted into
     displacement from the context pointer.  To get the correct text address,
     .cpadd should be used to add the value of gp back to them.  Since the gp
     is updated by the run-time linker, the correct text address can be
     reconstructed regardless of the location of the dso.


Clues for a MIPS ELF ld script
------------------------------

OUTPUT_FORMAT(elf32-littlemips)
SECTIONS {
 ENTRY( __start )
 . = 0xbfc00000;
 .text : { *(.text) ; _etext = . ; }
 . = 0xa0004000;
 _gp = .;
 _copystart = SIZEOF(.text) + ADDR(.text) ;
 .data : AT ( SIZEOF(.text) + ADDR(.text) )
	{ _data = . ; *(.data) *(.rdata) *(.mdebug) *(.reginfo) ; _edata = . ; }
 .sdata : AT ( SIZEOF(.data) + SIZEOF(.text) + ADDR(.text) )
	{ _sdata = . ; *(.sdata) ; _esdata = . ; }
 _copyend = SIZEOF(.sdata) + SIZEOF(.data) + SIZEOF(.text) + ADDR(.text) ;
 .bss : AT ( SIZEOF(.sdata) + SIZEOF(.data) + SIZEOF(.text) + ADDR(.text) )
	{ _bss = . ; *(.bss) *(COMMON) ; _ebss = . ; }
 _end = . ;
}

You also need to give gcc the flag -mno-abicalls, otherwise you 
get link errors trying to find _gp_disp.

