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:
parent
6f2c1316f0
commit
4f2730f723
Notes:
svn2git
2020-12-20 02:59:44 +00:00
svn path=/head/; revision=204211
@ -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);
|
||||||
|
@ -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);
|
||||||
|
|
||||||
|
@ -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
|
||||||
|
Loading…
Reference in New Issue
Block a user