jtony@genoa:~/learn/shell$ cat jyj.c
int glb1 = 1;
int glb2 = 2;
int glb3 = 3;
int foo(int a, int b, int c, int test) {
int tmp1 = test ? a : glb1;
int tmp2 = test ? b : glb2;
int tmp3 = test ? c : glb3;
return (tmp1 + tmp2 + tmp3);
}
# BB#0: # %entry
addis r7,
r2, glb1@toc@ha ---> (
what does "addis r7, r2, .glb1@toc@ha" here mean? That just puts the high 16-bits of the TOC offset for glb1 into r7)
addis r8, r2, glb2@toc@ha
addis r9, r2, glb3@toc@ha
cmplwi cr0, r6, 0
lwz r7, glb1@toc@l(r7)
lwz r8, glb2@toc@l(r8)
lwz r12, glb3@toc@l(r9)
bc 12, 2, .LBB0_1
b .LBB0_2
.LBB0_1: # %entry
addi r3, r7, 0
addi r4, r8, 0
(eqivalent to ld r4, 0(r8)) r8 has an address, this instr loads 8 bytes from that address into r4, i.e, r4 <--- *(&glb2 + 0))
addi r5, r12, 0
.LBB0_2: # %entry
add r3, r4, r3
add r3, r3, r5
extsw r3, r3
blr
.long 0
.quad 0
.Lfunc_end0:
.size foo, .Lfunc_end0-.Lfunc_begin0
---------------------------------------------------------------------------------------------------
In the above example assembly, the addis and addi are used several times. These two instructions are often used together to load a 32-bit address to a register. Here are their syntax and usages. Here r2 is the TOC pointer (TOC == Table Of Contents, r2 has the address of the TOC base)
[10:47]
it is a table that stores the locations of globals and constants
2. ADDI - Add Immediate
Syntax: addi rD,rA,SIMM
This command adds a 16-bit signed integer (SIMM) to register rA and puts the result into the register rD (destination).
Example: addi 3,6,4
In this example GPR6 and the value 4 are added and the result is put into GPR3.
As you can see the registers are specified as a number and the
integer is specified as a number. To improve the readability of the code
you can define constants for the registers, e.g.:
.set r0,0; .set r1,1; .set r2,2; .set r3,3; .set r4,4; .set r5,5; .set r6,6; .....
Then the above command can be written as: addi r3,r6,4
You can also use the addi command as a move instruction:
addi 3,0,4
This sets GPR3 to the value 4. If the second parameter is a zero here this does not mean a GPR0 but the value zero.
3.
ADDIS - Add Immediate Shifted
Syntax: addis rD,rA,SIMM
This command is used to add a 16-bit immediate value to the upper
16 bits of a 32bit register. It adds a 16-bit signed integer (SIMM) to
register rA, then shifts left register rA by 16 bits and then puts the
result into the register rD (destination). The lower 16 bits are cleared
by this command. So to fill a 32 bit register with an immediate 32-bit
value you first have to use addis to fill the upper 16 bits and then
addi to fill the lower 16 bits. Otherwise the lower 16 bits would be
cleared again by the addis command.
Example: addis 3,3,4
In this example GPR3 and the value 4 are added, then GPR3 is
shifted 16 bits to the left and the result is put into GPR3. This will
then contain 0x00040000 in hexadecimal. If you then execute an addi
3,3,4 command GPR3 will contain 0x00040004 in hexadecimal.
To move a pointer to an address of a variable or function into a
register there are the @ha/@h and @l modifiers available. If you append
these to the variable name you get the lower (@l) 16 bit of the absolute
32-bit address of the variable and with @ha you get the higher 16 bit
of the absolute 32-bit address.
Example:
- addis 3,0,hello@ha
- addi 3,0,hello@l
With these two instructions the absolute 32-bit address of the string variable hello is moved into the GPR 3 register.