Support the extended PLT format used when objects have more than 8192
PLT relocations on PPC32.
This commit is contained in:
parent
6f2c1316f0
commit
4f2730f723
@ -47,6 +47,13 @@
|
||||
((u_int32_t)(x) + 0x10000) : (u_int32_t)(x)) >> 16)
|
||||
#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
|
||||
*/
|
||||
@ -313,7 +320,6 @@ reloc_non_plt(Obj_Entry *obj, Obj_Entry *obj_rtld)
|
||||
return (r);
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* Initialise a PLT slot to the resolving trampoline
|
||||
*/
|
||||
@ -321,27 +327,43 @@ static int
|
||||
reloc_plt_object(Obj_Entry *obj, const Elf_Rela *rela)
|
||||
{
|
||||
Elf_Word *where = (Elf_Word *)(obj->relocbase + rela->r_offset);
|
||||
Elf_Addr *pltresolve;
|
||||
Elf_Addr *pltresolve, *pltlongresolve, *jmptab;
|
||||
Elf_Addr distance;
|
||||
int N = obj->pltrelasize / sizeof(Elf_Rela);
|
||||
int reloff;
|
||||
|
||||
reloff = rela - obj->pltrela;
|
||||
|
||||
if ((reloff < 0) || (reloff >= 0x8000)) {
|
||||
if (reloff < 0)
|
||||
return (-1);
|
||||
}
|
||||
|
||||
pltresolve = obj->pltgot + 8;
|
||||
pltlongresolve = obj->pltgot + 5;
|
||||
pltresolve = pltlongresolve + 5;
|
||||
|
||||
distance = (Elf_Addr)pltresolve - (Elf_Addr)(where + 1);
|
||||
|
||||
dbg(" reloc_plt_object: where=%p,pltres=%p,reloff=%x,distance=%x",
|
||||
(void *)where, (void *)pltresolve, reloff, distance);
|
||||
|
||||
/* li r11,reloff */
|
||||
/* b pltresolve */
|
||||
where[0] = 0x39600000 | reloff;
|
||||
where[1] = 0x48000000 | (distance & 0x03fffffc);
|
||||
if (reloff < PLT_EXTENDED_BEGIN) {
|
||||
/* li r11,reloff */
|
||||
/* b pltresolve */
|
||||
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
|
||||
@ -453,25 +475,28 @@ reloc_jmpslot(Elf_Addr *wherep, Elf_Addr target, const Obj_Entry *defobj,
|
||||
int N = obj->pltrelasize / sizeof(Elf_Rela);
|
||||
int reloff = rela - obj->pltrela;
|
||||
|
||||
if ((reloff < 0) || (reloff >= 0x8000)) {
|
||||
if (reloff < 0)
|
||||
return (-1);
|
||||
}
|
||||
|
||||
pltcall = obj->pltgot;
|
||||
|
||||
dbg(" reloc_jmpslot: indir, reloff=%d, N=%d\n",
|
||||
dbg(" reloc_jmpslot: indir, reloff=%x, N=%x\n",
|
||||
reloff, N);
|
||||
|
||||
jmptab = obj->pltgot + 18 + N * 2;
|
||||
jmptab = obj->pltgot + JMPTAB_BASE(N);
|
||||
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 */
|
||||
/* b pltcall # use indirect pltcall routine */
|
||||
wherep[0] = 0x39600000 | reloff;
|
||||
wherep[1] = 0x48000000 | (distance & 0x03fffffc);
|
||||
__syncicache(wherep, 8);
|
||||
distance = (Elf_Addr)pltcall - (Elf_Addr)(wherep + 1);
|
||||
|
||||
/* li r11,reloff */
|
||||
/* b pltcall # use indirect pltcall routine */
|
||||
wherep[0] = 0x39600000 | reloff;
|
||||
wherep[1] = 0x48000000 | (distance & 0x03fffffc);
|
||||
__syncicache(wherep, 8);
|
||||
}
|
||||
}
|
||||
|
||||
return (target);
|
||||
@ -481,13 +506,14 @@ reloc_jmpslot(Elf_Addr *wherep, Elf_Addr target, const Obj_Entry *defobj,
|
||||
/*
|
||||
* Setup the plt glue routines.
|
||||
*/
|
||||
#define PLTCALL_SIZE 20
|
||||
#define PLTRESOLVE_SIZE 24
|
||||
#define PLTCALL_SIZE 20
|
||||
#define PLTLONGRESOLVE_SIZE 20
|
||||
#define PLTRESOLVE_SIZE 24
|
||||
|
||||
void
|
||||
init_pltgot(Obj_Entry *obj)
|
||||
{
|
||||
Elf_Word *pltcall, *pltresolve;
|
||||
Elf_Word *pltcall, *pltresolve, *pltlongresolve;
|
||||
Elf_Word *jmptab;
|
||||
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
|
||||
* 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[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,
|
||||
* insert the absolute address of the _rtld_bind_start routine
|
||||
* 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);
|
||||
pltresolve[0] |= _ppc_ha(_rtld_bind_start);
|
||||
pltresolve[1] |= _ppc_la(_rtld_bind_start);
|
||||
|
@ -57,6 +57,7 @@ void _rtld_bind_start(void);
|
||||
* PLT functions. Not really correct prototypes, but the
|
||||
* symbol values are needed.
|
||||
*/
|
||||
void _rtld_powerpc_pltlongresolve(void);
|
||||
void _rtld_powerpc_pltresolve(void);
|
||||
void _rtld_powerpc_pltcall(void);
|
||||
|
||||
|
@ -163,6 +163,12 @@ _ENTRY(_rtld_bind_start)
|
||||
* The ELF object is shifted into %r11, and _rtld_bind_start is called
|
||||
* 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)
|
||||
lis %r12,0 # lis 12,_rtld_bind_start@ha
|
||||
addi %r12,%r12,0 # addi 12,12,_rtld_bind_start@l
|
||||
|
Loading…
Reference in New Issue
Block a user