Showing posts with label PowerPC. Show all posts
Showing posts with label PowerPC. Show all posts
Monday, 12 June 2017
How to access global variables and TOC
int a = 2;
int b = 3;
int foo(void) {
printf("a+b=%d",a + b);
return 0;
}
foo: # @foo
.Lfunc_begin0:
.Lfunc_gep0:
addis r2, r12, .TOC.-.Lfunc_gep0@ha
addi r2, r2, .TOC.-.Lfunc_gep0@l
.Lfunc_lep0:
.localentry foo, .Lfunc_lep0-.Lfunc_gep0
# BB#0: # %entry
mflr r0
std r0, 16(r1) # save the link register to 16(r1), i.e stackFrame + 16`
stdu r1, -96(r1) # prolog
addis r3, r2, .LC0@toc@ha
addis r4, r2, .LC1@toc@ha
addis r12, r2, .L.str@toc@ha
ld r3, .LC0@toc@l(r3)
ld r4, .LC1@toc@l(r4)
lwz r3, 0(r3)
lwz r4, 0(r4)
add r3, r4, r3
extsw r4, r3
addi r3, r12, .L.str@toc@l
bl printf
nop # may insert tls depending on the where is the callee definition.
li r3, 0
addi r1, r1, 96 # the reverse of the 3rd instr
ld r0, 16(r1) # load the old link reigster address
mtlr r0 # restore the link register value
blr
.long 0
.quad 0
.Lfunc_end0:
.size foo, .Lfunc_end0-.Lfunc_begin0
Thursday, 18 May 2017
BE VS LE data layout (&sldwi)
Say you have a vector int a = {1,2,3,4}, vector int b = {5,6,7,8}
The lay out of a in the memory on a BE machine is pretty simply, just as it is:
Because BE means high word is save in low address ( but it is natural for array access)
Addr0x 0 1 2 3
BE: [1,2,3,4]
On LE it is the opposite (high word is save in high address):
Addr0x 0 1 2 3
LE: [4,3,2,1]
say you have xxsldwi(a,b,3)
On BE: it is just 0 1 2 3 4 5 6 7
[1,2,3,4] [5,6,7,8]
The Result RT = {4,5,6,7}
if you want to use vec_shuffle to implement xxsldwi, you have to pass in
shuffle_vector((vector int)a, (vector int)b, 3,4,5,6), you can simply image BE
is acess from Left to right.
if you do for (int i = 0; i < 4; i++)
{
printf("RT[%d]=%d\n\n",i, RT[i]);
}
it is just :
c[0]=4
c[1]=5
c[2]=6
c[3]=7
But On LE, for the same array a and b,
it is just: 3 2 1 0 7 6 5 4
[4,3,2,1] [8,7,6,5]
The Result RT = [1,8,7,6] in the register
So no matter what, when xxsldwi(a,b,3), the word[3] of A, followed by
word[0], word[1] and word[2] will be put into the result vector register
if you want to use vec_shuffle to implement xxsldwi, you have to pass in
shuffle_vector((vector int)a, (vector int)b,5,6,7,0), you can simply image LE
is acess from right to left.
if you do for (int i = 0; i < 4; i++)
{
printf("RT[%d]=%d\n\n",i, RT[i]);
}
it is just :
c[0]=6
c[1]=7
c[2]=8
c[3]=1
Sunday, 29 January 2017
A quick introduction to simple functions
In order to qualify for the simplified ABI, your function must obey the following rules:
- It must not call any other function.
- It may only modify registers 3 through 12.
- It may only modify condition register fields
cr0,cr1,cr5,cr6, andcr7. - It must not alter the link register, unless it restores it before calling
blrto return.
So let's rewrite our maximum value program as a function, and call it from C.
The parameters we should pass are the pointer to the array as the first parameter (register 3), and the size of the array as the second parameter (register 4). Then, the maximum value will be placed into register 3 for the return value.
Monday, 23 January 2017
Global Varible access using GOT (Global Offset Table)
section:“.bss” contains the uninitialized global data, while .data contains all the initialized
data.
In general, the data segment of the executable contains
initialized global/static variables and the BSS segment contains uninitialized
global/static variables.
The GOT is private to each process, and the process must
have write permissions to it. Conversely the library code is shared and the
process should have only read and execute permissions on the code; it would be
a serious security breach if the process could modify code.
------------------------------------------------------------------------------------------------
jtony@genoa:~/scrum/s7$ cat got.cextern int i;
void test(void)
{
i = 100;
}
------------------------------------------------------------------------------------------------
Above we create a simple shared library which refers to an external symbol. We do not know the address of this symbol at compile time, so we leave it for the dynamic linker to fix up at runtime. But we want our code to remain sharable, in case other processes want to use our code as well.
------------------------------------------------------------------------------------------------
$ clang -nostdlib -shared -o got.so ./got.c
$ readelf --sections ./got.so
Section Headers:
[Nr] Name Type Address Offset
Size EntSize Flags
Link Info Align
[ 0] NULL 0000000000000000 00000000
0000000000000000 0000000000000000 0
0 0
[ 1] .gnu.hash GNU_HASH 0000000000000158 00000158
0000000000000034 0000000000000000 A
2 0 8
…
[ 9] .got
PROGBITS
0000000000020000 00010000
0000000000000010
0000000000000008 WA 0
0 8
[10] .comment PROGBITS 0000000000000000 00010010
00000000000000a5 0000000000000001 MS
0 0 1
------------------------------------------------------------------------------------------------
If we have a look at the readelf output above
we can see that the .got section starts 0x20000
bytes past where library was loaded into memory. Thus if the library were to be loaded into
memory at address 0x6000000000000000 the .got would be at
0x6000000000020000, The disassembly reveals just how we
do this with the .got.
-----------------------------------
objdump --disassemble ./got.so
Disassembly
of section .text:
0000000000000290
<test>:
290:
02 00 4c 3c addis r2,r12,2
294:
70 7d 42 38 addi r2,r2,32112
298:
64 00 60 38 li r3,100
29c:
00 00 00 60 nop
2a4:
00 00 64 90 stw r3,0(r4)
2a8:
20 00 80 4e blr
...
On ppc64le, the
register r2 is known as the Toc pointer and always points to TOC base address.
The symbol .TOC. may be used to
access the GOT or in TOC-relative addressing to other data constructs. The
symbol may be offset by 0x8000 bytes, or another offset, from the start of the
.got section. I think after line 290 – 294 (addis, addi) [need to confirm] , r2 will point to .GOT + 0x8000 (i.e
32768). Then the ld on line 2a0, will
set r4 point to .GOT + (32768 – 32760), i.e. r4 point to .GOT + 8
Table 4: Relocation
-----------------------------------
jtony@genoa:~/scrum/s7$
readelf --relocs ./got.so
Relocation
section '.rela.dyn' at offset 0x270 contains 1 entries:
000000020008 000300000026
R_PPC64_ADDR64 0000000000000000 i + 0
-----------------------------------
The relocation says "replace the value at offset 0x20008
with the memory location that symbol i is
stored at".
We know that the .got starts at
offset 0x20000 from the previous output. We have also seen how the code loads
an address 0x8 past this ( using ld r4,-32760(r2)) giving us an address of 0x20000 + 0x8 =
0x20008 ... the address which the relocation is for!
So before the program begins, the dynamic linker
will have fixed up the relocation to ensure that the value of the memory at
offset 0x20008 is the address of the global variable i!
Sunday, 22 January 2017
TOC section and its relation with GOT
ELF processor-specific supplements normally define a GOT ("Global Offset Table") section used to hold addresses for position independent code. Some ELF processor-specific supplements, including the 32-bit PowerPC Processor Supplement, define a small data section. The same register is sometimes used to address both the GOT and the small data section.
The 64-bit PowerOpen ABI defines a TOC ("Table of Contents") section. The TOC combines the functions of the GOT and the small data section.
This ABI uses the term TOC. The TOC section defined here is intended to be similar to that defined by the 64-bit PowerOpen ABI. The TOC section contains a conventional ELF GOT, and may optionally contain a small data area. The GOT and the small data area may be intermingled in the TOC section.
The TOC section is accessed via the dedicated TOC pointer register, r2. Accesses are normally made using the register indirect with immediate index mode supported by the 64-bit PowerPC processor, which limits a single TOC section to 65,536 bytes, enough for 8,192 GOT entries.
The value of the TOC pointer register is called the TOC base. The TOC base is typically the first address in the TOC plus 0x8000, thus permitting a full 64 Kbyte TOC.
A relocatable object file must have a single TOC section and a single TOC base. However, when the link editor combines relocatable object files to form a single executable or shared object, it may create multiple TOC sections. The link editor is responsible for deciding how to associate TOC sections with object files. Normally the link editor will only create multiple TOC sections if it has more than 65,536 bytes to store in a TOC.
All link editors which support this ABI must support a single TOC section, but support for multiple TOC sections is optional.
Each shared object will have a separate TOC or TOCs.
![]() | Note |
|---|---|
| This ABI does not actually restrict the size of a TOC section. It is permissible to use a larger TOC section, if code uses a different addressing mode to access it. The AIX link editor, in particular, does not support multiple TOC sections, but instead inserts call out code at link time to support larger TOC sections. |
Registers on PowerPC
r0 Volatile register used in function prologs
r1 Stack frame pointer
r2 TOC pointer
r3 Volatile parameter and return value register
r4-r10 Volatile registers used for function parameters
r11 Volatile register used in calls by pointer and as an
environment pointer for languages which require one
r12 Volatile register used for exception handling and glink code
r13 Reserved for use as system thread ID
r14-r31 Nonvolatile registers used for local variables
f0 Volatile scratch register
f1-f4 Volatile floating point parameter and return value registers
f5-f13 Volatile floating point parameter registers
f14-f31 Nonvolatile registers
LR Link register (volatile)
CTR Loop counter register (volatile)
XER Fixed point exception register (volatile)
FPSCR Floating point status and control register (volatile)
CR0-CR1 Volatile condition code register fields
CR2-CR4 Nonvolatile condition code register fields
CR5-CR7 Volatile condition code register fields
On processors with the VMX feature.v0-v1 Volatile scratch registers v2-v13 Volatile vector parameters registers v14-v19 Volatile scratch registers v20-v31 Non-volatile registers vrsave Non-volatile 32-bit registerThe existence of the VMX feature will be indicated in the AT_HWCAP auxiliary vector entry.
Registers r1, r14 through r31, and f14 through f31 are nonvolatile, which means that they preserve their values across function calls. Functions which use those registers must save the value before changing it, restoring it before the function returns. Register r2 is technically nonvolatile, but it is handled specially during function calls as described below: in some cases the calling function must restore its value after a function call.
Registers r0, r3 through r12, f0 through f13, and the special purpose registers LR, CTR, XER, and FPSCR are volatile, which means that they are not preserved across function calls. Furthermore, registers r0, r2, r11, and r12 may be modified by cross-module calls, so a function can not assume that the values of one of these registers is that placed there by the calling function.
The condition code register fields CR0, CR1, CR5, CR6, and CR7 are volatile. The condition code register fields CR2, CR3, and CR4 are nonvolatile; a function which modifies them must save and restore at least those fields of the CR. Languages that require "environment pointers" shall use r11 for that purpose.
The following registers have assigned roles in the standard calling sequence:
- r1
- The stack pointer (stored in r1) shall maintain quadword alignment. It shall always point to the lowest allocated valid stack frame, and grow toward low addresses. The contents of the word at that address always point to the previously allocated stack frame. If required, it can be decremented by the called function. See Section 3.5.13 for additional infromation. As discussed later in this chapter, the lowest valid stack address is 288 bytes less than the value in the stack pointer. The stack pointer must be atomically updated by a single instruction, thus avoiding any timing window in which an interrupt can occur with a partially updated stack.
- r2
- This register holds the TOC base. See Section 3.5.2 for additional information.
- r3 through r10 and f1 through f13
- These sets of volatile registers may be modified across function invocations and shall therefore be presumed by the calling function to be destroyed. They are used for passing parameters to the called function. See Section 3.2.3 for additional information. In addition, registers r3 and f1 through f4 are used to return values from the called function, as described in Section 3.2.4.
- LR (Link Register)
- This register shall contain the address to which a called function normally returns. LR is volatile across function calls.
Ref:
http://refspecs.linuxfoundation.org/ELF/ppc64/PPC-elf64abi-1.7.html
Subscribe to:
Posts (Atom)
