Instructions
|
Stack FrameExample when using frame pointer and two local variables:
my_sub: ; Adds 1 to first argument ; Prologue stwu r1,-16(r1) ; "push" mflr r0 ; r0 = link register stw r0,20(r1) ; Save link register ; Body of subroutine: addi r3, r3, 1 ; Epilogue lwz r0,20(r1) mtlr r0 addi r1, r1, 16 ; "pop" blr |
||||||||||||||||||||||||||||||||||||||||||||||||||||||||
Constants, Registers, MemoryConstants can just be written normally. Weirdness: if a constant is more than 16 bits long, you can't load it in one instruction: you need to break it into two parts.Use the "i" (immediate) form of the instruction if you want to put in a constant, or use "li" to load the constant into a register. All memory access is via the load and store routines--you *can't* just get to a random memory location from any instruction. lis 4,msg@ha # load top 16 bits of &msg |
Registersr1 is the stack pointerReturn value in r3 First 8 integer arguments are in r3 through r10; remainder on stack. Free for use (no save needed): r0, and r3 through r12 Must be saved: r13 through r31 |
||||||||||||||||||||||||||||||||||||||||||||||||||||||||
Floating PointLoad and store from memory with lfs/lfd (load float single/double) stfs, stfd.Arithmetic instructions start with "f", like "fadd", "fmul", "fmadd", "fdiv". There are both single- and double-precision versions, with the single-precision versions ending in "s" (like fadds), but they both use the same register set. Weird instructions: "fres" (computes approximate 1.0/x); "frsqrte" (1.0/sqrt(x), approximate). |
Floating Point RegistersRegisters are all 64-bit doubles.Floating point args are in f1-f13 f0-f13 are free for any use f14-f31 must be saved Return value goes in f1 |
||||||||||||||||||||||||||||||||||||||||||||||||||||||||
Common ErrorsError: operand out of range (123 not between 0 and 31)You passed in some constant (here 123); the assembler expected a register. Error: operand out of range (100000 not between -32768 and 32767) You passed in a constant that was too big. Use "li" and "addis" to stick the constant together from 16-bit pieces (or just choose another constant!) |
li r3,100Add two integers:
blr
li r7,3
li r9,10
add r3,r7,r9
blr
Compare integers, and branch. This is nearly identical to the
x86 version.
li r4, 10Load the two 16-bit halves of a 32-bit constant. Note most Linux/IBM machines use "@ha" and "@l" suffixes instead of the OS X "ha16" and "lo16" functions.
li r5, 100
cmp 0,0, r4,r5 ; compare r4 and r5. Put result into condition register 0
blt is_less
li r3,4
blr
is_less:
li r3,5
blr
lis r3,ha16(0xdeadbeef)
addi r3,r3,lo16(0xdeadbeef)
blr
Load a constant from read-only memory:
lis r5,ha16(myStuff)Store a constant to writeable memory:
addi r5,r5,lo16(myStuff)
lwz r3,0(r5)
blr
myStuff:
.long 1234
lis r5,ha16(myStuff)Call a function: the hard part is saving the link register, so we can get back.
addi r5,r5,lo16(myStuff)
stw r3, 0(r5)
blr
.data
myStuff:
.long 1234
stwu r1,-16(r1); prologueIt's a little easier to call functions if you don't ever come back. Here "b function" branches away to the function, never to return.
mflr r0
stw r0,20(r1)
li r3,1234
bl _print_int
lwz r0,20(r1) ; epilogue
mtlr r0
addi r1, r1, 16
blr
lis r3,ha16(myFloats) ; first argument: pointer to floatsHere we do a little floating point arithmetic before printing the value. r3 is doing double duty: used by us first, then used as a function parameter.
addi r3,r3,lo16(myFloats)
li r4,1 ; number of floats to print
b _farray_print ; tail call to print (returns directly to main)
.data
myFloats:
.long 0x3F9DF3B6 ; float 1.234 as an int, from: return *(int *)&someFloat
lis r3,ha16(myFloats) ; first argument: pointer to floats
addi r3,r3,lo16(myFloats)
lfs f1,0(r3) ; load the float
fadd f1,f1,f1 ; add it to itself
stfs f1,0(r3) ; store back to memory
li r4,1 ; number of floats to print
b _farray_print ; tail call to print (returns directly to main)
.data
myFloats:
.long 0x3F9DF3B6 ; float 1.234 as an int, from: return *(int *)&someFloat