1
0
mirror of https://git.FreeBSD.org/src.git synced 2024-12-29 12:03:03 +00:00

Support the extended PLT format used when objects have more than 8192

PLT relocations on PPC32.
This commit is contained in:
Nathan Whitehorn 2010-02-22 16:49:45 +00:00
parent 6f2c1316f0
commit 4f2730f723
Notes: svn2git 2020-12-20 02:59:44 +00:00
svn path=/head/; revision=204211
3 changed files with 67 additions and 25 deletions

View File

@ -47,6 +47,13 @@
((u_int32_t)(x) + 0x10000) : (u_int32_t)(x)) >> 16) ((u_int32_t)(x) + 0x10000) : (u_int32_t)(x)) >> 16)
#define _ppc_la(x) ((u_int32_t)(x) & 0xffff) #define _ppc_la(x) ((u_int32_t)(x) & 0xffff)
#define min(a,b) (((a) < (b)) ? (a) : (b))
#define max(a,b) (((a) > (b)) ? (a) : (b))
#define PLT_EXTENDED_BEGIN (1 << 13)
#define JMPTAB_BASE(N) (18 + N*2 + ((N > PLT_EXTENDED_BEGIN) ? \
(N - PLT_EXTENDED_BEGIN)*2 : 0))
/* /*
* Process the R_PPC_COPY relocations * Process the R_PPC_COPY relocations
*/ */
@ -313,7 +320,6 @@ reloc_non_plt(Obj_Entry *obj, Obj_Entry *obj_rtld)
return (r); return (r);
} }
/* /*
* Initialise a PLT slot to the resolving trampoline * Initialise a PLT slot to the resolving trampoline
*/ */
@ -321,27 +327,43 @@ static int
reloc_plt_object(Obj_Entry *obj, const Elf_Rela *rela) reloc_plt_object(Obj_Entry *obj, const Elf_Rela *rela)
{ {
Elf_Word *where = (Elf_Word *)(obj->relocbase + rela->r_offset); Elf_Word *where = (Elf_Word *)(obj->relocbase + rela->r_offset);
Elf_Addr *pltresolve; Elf_Addr *pltresolve, *pltlongresolve, *jmptab;
Elf_Addr distance; Elf_Addr distance;
int N = obj->pltrelasize / sizeof(Elf_Rela);
int reloff; int reloff;
reloff = rela - obj->pltrela; reloff = rela - obj->pltrela;
if ((reloff < 0) || (reloff >= 0x8000)) { if (reloff < 0)
return (-1); return (-1);
}
pltresolve = obj->pltgot + 8; pltlongresolve = obj->pltgot + 5;
pltresolve = pltlongresolve + 5;
distance = (Elf_Addr)pltresolve - (Elf_Addr)(where + 1); distance = (Elf_Addr)pltresolve - (Elf_Addr)(where + 1);
dbg(" reloc_plt_object: where=%p,pltres=%p,reloff=%x,distance=%x", dbg(" reloc_plt_object: where=%p,pltres=%p,reloff=%x,distance=%x",
(void *)where, (void *)pltresolve, reloff, distance); (void *)where, (void *)pltresolve, reloff, distance);
/* li r11,reloff */ if (reloff < PLT_EXTENDED_BEGIN) {
/* b pltresolve */ /* li r11,reloff */
where[0] = 0x39600000 | reloff; /* b pltresolve */
where[1] = 0x48000000 | (distance & 0x03fffffc); where[0] = 0x39600000 | reloff;
where[1] = 0x48000000 | (distance & 0x03fffffc);
} else {
jmptab = obj->pltgot + JMPTAB_BASE(N);
jmptab[reloff] = (u_int)pltlongresolve;
/* lis r11,jmptab[reloff]@ha */
/* lwzu r12,jmptab[reloff]@l(r11) */
/* mtctr r12 */
/* bctr */
where[0] = 0x3d600000 | _ppc_ha(&jmptab[reloff]);
where[1] = 0x858b0000 | _ppc_la(&jmptab[reloff]);
where[2] = 0x7d8903a6;
where[3] = 0x4e800420;
}
/* /*
* The icache will be sync'd in init_pltgot, which is called * The icache will be sync'd in init_pltgot, which is called
@ -453,25 +475,28 @@ reloc_jmpslot(Elf_Addr *wherep, Elf_Addr target, const Obj_Entry *defobj,
int N = obj->pltrelasize / sizeof(Elf_Rela); int N = obj->pltrelasize / sizeof(Elf_Rela);
int reloff = rela - obj->pltrela; int reloff = rela - obj->pltrela;
if ((reloff < 0) || (reloff >= 0x8000)) { if (reloff < 0)
return (-1); return (-1);
}
pltcall = obj->pltgot; pltcall = obj->pltgot;
dbg(" reloc_jmpslot: indir, reloff=%d, N=%d\n", dbg(" reloc_jmpslot: indir, reloff=%x, N=%x\n",
reloff, N); reloff, N);
jmptab = obj->pltgot + 18 + N * 2; jmptab = obj->pltgot + JMPTAB_BASE(N);
jmptab[reloff] = target; jmptab[reloff] = target;
distance = (Elf_Addr)pltcall - (Elf_Addr)(wherep + 1); if (reloff < PLT_EXTENDED_BEGIN) {
/* for extended PLT entries, we keep the old code */
/* li r11,reloff */ distance = (Elf_Addr)pltcall - (Elf_Addr)(wherep + 1);
/* b pltcall # use indirect pltcall routine */
wherep[0] = 0x39600000 | reloff; /* li r11,reloff */
wherep[1] = 0x48000000 | (distance & 0x03fffffc); /* b pltcall # use indirect pltcall routine */
__syncicache(wherep, 8); wherep[0] = 0x39600000 | reloff;
wherep[1] = 0x48000000 | (distance & 0x03fffffc);
__syncicache(wherep, 8);
}
} }
return (target); return (target);
@ -481,13 +506,14 @@ reloc_jmpslot(Elf_Addr *wherep, Elf_Addr target, const Obj_Entry *defobj,
/* /*
* Setup the plt glue routines. * Setup the plt glue routines.
*/ */
#define PLTCALL_SIZE 20 #define PLTCALL_SIZE 20
#define PLTRESOLVE_SIZE 24 #define PLTLONGRESOLVE_SIZE 20
#define PLTRESOLVE_SIZE 24
void void
init_pltgot(Obj_Entry *obj) init_pltgot(Obj_Entry *obj)
{ {
Elf_Word *pltcall, *pltresolve; Elf_Word *pltcall, *pltresolve, *pltlongresolve;
Elf_Word *jmptab; Elf_Word *jmptab;
int N = obj->pltrelasize / sizeof(Elf_Rela); int N = obj->pltrelasize / sizeof(Elf_Rela);
@ -524,18 +550,27 @@ init_pltgot(Obj_Entry *obj)
* of the jumptable into the absolute-call assembler code so it * of the jumptable into the absolute-call assembler code so it
* can determine this address. * can determine this address.
*/ */
jmptab = pltcall + 18 + N * 2; jmptab = obj->pltgot + JMPTAB_BASE(N);
pltcall[1] |= _ppc_ha(jmptab); /* addis 11,11,jmptab@ha */ pltcall[1] |= _ppc_ha(jmptab); /* addis 11,11,jmptab@ha */
pltcall[2] |= _ppc_la(jmptab); /* lwz 11,jmptab@l(11) */ pltcall[2] |= _ppc_la(jmptab); /* lwz 11,jmptab@l(11) */
/* /*
* Skip down 32 bytes into the initial reserved area and copy * Skip down 20 bytes into the initial reserved area and copy
* in the standard resolving assembler call. Into this assembler, * in the standard resolving assembler call. Into this assembler,
* insert the absolute address of the _rtld_bind_start routine * insert the absolute address of the _rtld_bind_start routine
* and the address of the relocation object. * and the address of the relocation object.
*
* We place pltlongresolve first, so it can fix up its arguments
* and then fall through to the regular PLT resolver.
*/ */
pltresolve = obj->pltgot + 8; pltlongresolve = obj->pltgot + 5;
memcpy(pltlongresolve, _rtld_powerpc_pltlongresolve,
PLTLONGRESOLVE_SIZE);
pltlongresolve[0] |= _ppc_ha(jmptab); /* lis 12,jmptab@ha */
pltlongresolve[1] |= _ppc_la(jmptab); /* addi 12,12,jmptab@l */
pltresolve = pltlongresolve + PLTLONGRESOLVE_SIZE/sizeof(uint32_t);
memcpy(pltresolve, _rtld_powerpc_pltresolve, PLTRESOLVE_SIZE); memcpy(pltresolve, _rtld_powerpc_pltresolve, PLTRESOLVE_SIZE);
pltresolve[0] |= _ppc_ha(_rtld_bind_start); pltresolve[0] |= _ppc_ha(_rtld_bind_start);
pltresolve[1] |= _ppc_la(_rtld_bind_start); pltresolve[1] |= _ppc_la(_rtld_bind_start);

View File

@ -57,6 +57,7 @@ void _rtld_bind_start(void);
* PLT functions. Not really correct prototypes, but the * PLT functions. Not really correct prototypes, but the
* symbol values are needed. * symbol values are needed.
*/ */
void _rtld_powerpc_pltlongresolve(void);
void _rtld_powerpc_pltresolve(void); void _rtld_powerpc_pltresolve(void);
void _rtld_powerpc_pltcall(void); void _rtld_powerpc_pltcall(void);

View File

@ -163,6 +163,12 @@ _ENTRY(_rtld_bind_start)
* The ELF object is shifted into %r11, and _rtld_bind_start is called * The ELF object is shifted into %r11, and _rtld_bind_start is called
* to complete the binding. * to complete the binding.
*/ */
_ENTRY(_rtld_powerpc_pltlongresolve)
lis %r12,0 # lis 12,jmptab@ha
addi %r12,%r12,0 # addi 12,12,jmptab@l
subf %r11,%r12,%r11 # reloff
li %r12,2
srw %r11,%r11,%r12 # index = reloff/sizeof(Elf_Addr)
_ENTRY(_rtld_powerpc_pltresolve) _ENTRY(_rtld_powerpc_pltresolve)
lis %r12,0 # lis 12,_rtld_bind_start@ha lis %r12,0 # lis 12,_rtld_bind_start@ha
addi %r12,%r12,0 # addi 12,12,_rtld_bind_start@l addi %r12,%r12,0 # addi 12,12,_rtld_bind_start@l