SGI Techpubs Library

IRIX 6.5  »  Books  »  Developer  »  
MIPS O32 Compiling and Performance Tuning Guide
(document number: 007-2479-001 / published: 1994-11-14)    table of contents  |  additional info  |  download
find in page | jump to first hit | clear highlight

Appendix A. Position-Independent Coding in Assembly Language

Several new assembler directives have been added to support generation of PIC. For more information on PIC, refer to the MIPS ABI Supplement and the PIC coding model it describes. For information on assembly language, refer to the MIPSpro Assembly Language Programmer's Guide.

The assembler generates PIC if either of two things occur:

  • the directive .option pic2 appears in the assembler file

  • the assembler, as, is invoked with the –KPIC argument in the absence of an explicit .option pic0 directive in the file

Unless PIC is being generated, the other options in this section are ignored by the assembler, with the exception of .gpword, which becomes .word. Thus, you may easily use the same assembler file for generating PIC and non-PIC (i.e., non-shared) objects by not placing .option pic0 or .option pic2 in the assembler file and invoking the assembler without –KPIC (for non-shared) or with –KPIC (for PIC).

  • .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 options to toggle between generating PIC or non-PIC.

    Even though –KPIC will be made the default for the high-level language drivers (such as cc, f77, and pc) in future releases, it will not be the default for assembly sources. You must explicitly specify –KPIC for compiling .s files.

  • .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 that the linker sets to 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).

  • .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) operation (but not after a 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.

  • .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 (that is, the gp). local-sym must be local. It is currently used for PIC switch tables.

  • .cpadd reg

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

Examples

This following 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 are:

        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 ABI requires that 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:

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:          ...       # alternate 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 (and less efficiently), 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

.gpword and .cpadd are used together to implement 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, use .cpadd 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.

MIPS O32 Compiling and Performance Tuning Guide
(document number: 007-2479-001 / published: 1994-11-14)    table of contents  |  additional info  |  download

    Front Matter
    About This Guide
    Chapter 1. About the Compiler System
    Chapter 2. Using the Compiler System
    Chapter 3. Dynamic Shared Objects
    Chapter 4. Using the Performance Tools
    Chapter 5. Optimizing Program Performance
    Appendix A. Position-Independent Coding in Assembly Language
    Index


home/search | what's new | help