Handle relocations for newer non-PIC MIPS ABI.
Newer binutils supports extensions to the MIPS ABI for non-PIC code that is used when compiling O32 binaries with clang 5 (but not used for N64 oddly enough). These extensions require support for R_MIPS_COPY relocations as well as a second PLT GOT using R_MIPS_JUMP_SLOT relocations. For R_MIPS_COPY, use the same approach as on other architectures where fixups are deferred to the MD do_copy_relocations. The additional PLT GOT for jump slots is located in a .got.plt section which is identified by a DT_MIPS_PLTGOT dynamic entry. This GOT also requires fixups for the first two GOT entries just as the normal GOT. However, the entry point for this second GOT uses a different calling convention. Rather than passing an offset into the GOT, it passes an offset into the .rel.plt section. This requires a second entry point (_rtld_pltbind_start) which calls the normal _rtld_bind() rather than _mips_rtld_bind(). This also means providing a real version of reloc_jmpslot() which is used by _rtld_bind(). In addition, add real implementions of reloc_plt() and reloc_jmpslots() which walk .rel.plt handling R_MIPS_JUMP_SLOT relocations. Reviewed by: kib Sponsored by: DARPA / AFRL Differential Revision: https://reviews.freebsd.org/D12326
This commit is contained in:
parent
08d1c5b152
commit
b4e9a36bf7
Notes:
svn2git
2020-12-20 02:59:44 +00:00
svn path=/head/; revision=323501
@ -67,29 +67,6 @@ __FBSDID("$FreeBSD$");
|
|||||||
#define GOT1_RESERVED_FOR_RTLD(got) ((got)[1] & GOT1_MASK)
|
#define GOT1_RESERVED_FOR_RTLD(got) ((got)[1] & GOT1_MASK)
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
void
|
|
||||||
init_pltgot(Obj_Entry *obj)
|
|
||||||
{
|
|
||||||
if (obj->pltgot != NULL) {
|
|
||||||
obj->pltgot[0] = (Elf_Addr) &_rtld_bind_start;
|
|
||||||
if (GOT1_RESERVED_FOR_RTLD(obj->pltgot))
|
|
||||||
obj->pltgot[1] = (Elf_Addr) obj | GOT1_MASK;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
int
|
|
||||||
do_copy_relocations(Obj_Entry *dstobj)
|
|
||||||
{
|
|
||||||
/* Do nothing */
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
void _rtld_relocate_nonplt_self(Elf_Dyn *, Elf_Addr);
|
|
||||||
|
|
||||||
/*
|
|
||||||
* It is possible for the compiler to emit relocations for unaligned data.
|
|
||||||
* We handle this situation with these inlines.
|
|
||||||
*/
|
|
||||||
#ifdef __mips_n64
|
#ifdef __mips_n64
|
||||||
/*
|
/*
|
||||||
* ELF64 MIPS encodes the relocs uniquely. The first 32-bits of info contain
|
* ELF64 MIPS encodes the relocs uniquely. The first 32-bits of info contain
|
||||||
@ -110,6 +87,86 @@ void _rtld_relocate_nonplt_self(Elf_Dyn *, Elf_Addr);
|
|||||||
#define Elf_Sxword Elf32_Sword
|
#define Elf_Sxword Elf32_Sword
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
void _rtld_pltbind_start(void);
|
||||||
|
|
||||||
|
void
|
||||||
|
init_pltgot(Obj_Entry *obj)
|
||||||
|
{
|
||||||
|
|
||||||
|
if (obj->pltgot != NULL) {
|
||||||
|
obj->pltgot[0] = (Elf_Addr) &_rtld_bind_start;
|
||||||
|
if (GOT1_RESERVED_FOR_RTLD(obj->pltgot))
|
||||||
|
obj->pltgot[1] = (Elf_Addr) obj | GOT1_MASK;
|
||||||
|
}
|
||||||
|
if (obj->mips_pltgot != NULL) {
|
||||||
|
obj->mips_pltgot[0] = (Elf_Addr) &_rtld_pltbind_start;
|
||||||
|
obj->mips_pltgot[1] = (Elf_Addr) obj;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
int
|
||||||
|
do_copy_relocations(Obj_Entry *dstobj)
|
||||||
|
{
|
||||||
|
const Obj_Entry *srcobj, *defobj;
|
||||||
|
const Elf_Rel *rellim;
|
||||||
|
const Elf_Rel *rel;
|
||||||
|
const Elf_Sym *srcsym;
|
||||||
|
const Elf_Sym *dstsym;
|
||||||
|
const void *srcaddr;
|
||||||
|
const char *name;
|
||||||
|
void *dstaddr;
|
||||||
|
SymLook req;
|
||||||
|
size_t size;
|
||||||
|
int res;
|
||||||
|
|
||||||
|
/*
|
||||||
|
* COPY relocs are invalid outside of the main program
|
||||||
|
*/
|
||||||
|
assert(dstobj->mainprog);
|
||||||
|
|
||||||
|
rellim = (const Elf_Rel *)((caddr_t)dstobj->rel + dstobj->relsize);
|
||||||
|
for (rel = dstobj->rel; rel < rellim; rel++) {
|
||||||
|
if (ELF_R_TYPE(rel->r_info) != R_MIPS_COPY)
|
||||||
|
continue;
|
||||||
|
|
||||||
|
dstaddr = (void *)(dstobj->relocbase + rel->r_offset);
|
||||||
|
dstsym = dstobj->symtab + ELF_R_SYM(rel->r_info);
|
||||||
|
name = dstobj->strtab + dstsym->st_name;
|
||||||
|
size = dstsym->st_size;
|
||||||
|
|
||||||
|
symlook_init(&req, name);
|
||||||
|
req.ventry = fetch_ventry(dstobj, ELF_R_SYM(rel->r_info));
|
||||||
|
req.flags = SYMLOOK_EARLY;
|
||||||
|
|
||||||
|
for (srcobj = globallist_next(dstobj); srcobj != NULL;
|
||||||
|
srcobj = globallist_next(srcobj)) {
|
||||||
|
res = symlook_obj(&req, srcobj);
|
||||||
|
if (res == 0) {
|
||||||
|
srcsym = req.sym_out;
|
||||||
|
defobj = req.defobj_out;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (srcobj == NULL) {
|
||||||
|
_rtld_error(
|
||||||
|
"Undefined symbol \"%s\" referenced from COPY relocation in %s",
|
||||||
|
name, dstobj->path);
|
||||||
|
return (-1);
|
||||||
|
}
|
||||||
|
|
||||||
|
srcaddr = (const void *)(defobj->relocbase + srcsym->st_value);
|
||||||
|
memcpy(dstaddr, srcaddr, size);
|
||||||
|
}
|
||||||
|
|
||||||
|
return (0);
|
||||||
|
}
|
||||||
|
|
||||||
|
void _rtld_relocate_nonplt_self(Elf_Dyn *, Elf_Addr);
|
||||||
|
|
||||||
|
/*
|
||||||
|
* It is possible for the compiler to emit relocations for unaligned data.
|
||||||
|
* We handle this situation with these inlines.
|
||||||
|
*/
|
||||||
static __inline Elf_Sxword
|
static __inline Elf_Sxword
|
||||||
load_ptr(void *where, size_t len)
|
load_ptr(void *where, size_t len)
|
||||||
{
|
{
|
||||||
@ -475,6 +532,20 @@ reloc_non_plt(Obj_Entry *obj, Obj_Entry *obj_rtld, int flags,
|
|||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
case R_TYPE(COPY):
|
||||||
|
/*
|
||||||
|
* These are deferred until all other relocations have
|
||||||
|
* been done. All we do here is make sure that the
|
||||||
|
* COPY relocation is not in a shared library. They
|
||||||
|
* are allowed only in executable files.
|
||||||
|
*/
|
||||||
|
if (!obj->mainprog) {
|
||||||
|
_rtld_error("%s: Unexpected R_MIPS_COPY "
|
||||||
|
"relocation in shared library", obj->path);
|
||||||
|
return (-1);
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
|
||||||
#ifdef __mips_n64
|
#ifdef __mips_n64
|
||||||
case R_TYPE(TLS_DTPMOD64):
|
case R_TYPE(TLS_DTPMOD64):
|
||||||
#else
|
#else
|
||||||
@ -581,23 +652,25 @@ reloc_non_plt(Obj_Entry *obj, Obj_Entry *obj_rtld, int flags,
|
|||||||
int
|
int
|
||||||
reloc_plt(Obj_Entry *obj)
|
reloc_plt(Obj_Entry *obj)
|
||||||
{
|
{
|
||||||
#if 0
|
|
||||||
const Elf_Rel *rellim;
|
const Elf_Rel *rellim;
|
||||||
const Elf_Rel *rel;
|
const Elf_Rel *rel;
|
||||||
|
|
||||||
dbg("reloc_plt obj:%p pltrel:%p sz:%s", obj, obj->pltrel, (int)obj->pltrelsize);
|
rellim = (const Elf_Rel *)((char *)obj->pltrel + obj->pltrelsize);
|
||||||
dbg("gottable %p num syms:%s", obj->pltgot, obj->symtabno );
|
for (rel = obj->pltrel; rel < rellim; rel++) {
|
||||||
dbg("*****************************************************");
|
|
||||||
rellim = (const Elf_Rel *)((char *)obj->pltrel +
|
|
||||||
obj->pltrelsize);
|
|
||||||
for (rel = obj->pltrel; rel < rellim; rel++) {
|
|
||||||
Elf_Addr *where;
|
Elf_Addr *where;
|
||||||
where = (Elf_Addr *)(obj->relocbase + rel->r_offset);
|
|
||||||
*where += (Elf_Addr )obj->relocbase;
|
switch (ELF_R_TYPE(rel->r_info)) {
|
||||||
|
case R_MIPS_JUMP_SLOT:
|
||||||
|
where = (Elf_Addr *)(obj->relocbase + rel->r_offset);
|
||||||
|
*where += (Elf_Addr )obj->relocbase;
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
_rtld_error("Unknown relocation type %u in PLT",
|
||||||
|
(unsigned int)ELF_R_TYPE(rel->r_info));
|
||||||
|
return (-1);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#endif
|
|
||||||
/* PLT fixups were done above in the GOT relocation. */
|
|
||||||
return (0);
|
return (0);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -607,8 +680,33 @@ reloc_plt(Obj_Entry *obj)
|
|||||||
int
|
int
|
||||||
reloc_jmpslots(Obj_Entry *obj, int flags, RtldLockState *lockstate)
|
reloc_jmpslots(Obj_Entry *obj, int flags, RtldLockState *lockstate)
|
||||||
{
|
{
|
||||||
/* Do nothing */
|
const Obj_Entry *defobj;
|
||||||
obj->jmpslots_done = true;
|
const Elf_Rel *rellim;
|
||||||
|
const Elf_Rel *rel;
|
||||||
|
const Elf_Sym *def;
|
||||||
|
|
||||||
|
rellim = (const Elf_Rel *)((char *)obj->pltrel + obj->pltrelsize);
|
||||||
|
for (rel = obj->pltrel; rel < rellim; rel++) {
|
||||||
|
Elf_Addr *where;
|
||||||
|
|
||||||
|
switch (ELF_R_TYPE(rel->r_info)) {
|
||||||
|
case R_MIPS_JUMP_SLOT:
|
||||||
|
def = find_symdef(ELF_R_SYM(rel->r_info), obj,
|
||||||
|
&defobj, SYMLOOK_IN_PLT | flags, NULL, lockstate);
|
||||||
|
if (def == NULL) {
|
||||||
|
dbg("reloc_jmpslots: sym not found");
|
||||||
|
return (-1);
|
||||||
|
}
|
||||||
|
|
||||||
|
where = (Elf_Addr *)(obj->relocbase + rel->r_offset);
|
||||||
|
*where = (Elf_Addr)(defobj->relocbase + def->st_value);
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
_rtld_error("Unknown relocation type %u in PLT",
|
||||||
|
(unsigned int)ELF_R_TYPE(rel->r_info));
|
||||||
|
return (-1);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
return (0);
|
return (0);
|
||||||
}
|
}
|
||||||
@ -635,9 +733,11 @@ reloc_jmpslot(Elf_Addr *where, Elf_Addr target, const Obj_Entry *defobj,
|
|||||||
const Obj_Entry *obj, const Elf_Rel *rel)
|
const Obj_Entry *obj, const Elf_Rel *rel)
|
||||||
{
|
{
|
||||||
|
|
||||||
/* Do nothing */
|
assert(ELF_R_TYPE(rel->r_info) == R_MIPS_JUMP_SLOT);
|
||||||
|
|
||||||
return target;
|
if (*where != target && !ld_bind_not)
|
||||||
|
*where = target;
|
||||||
|
return (target);
|
||||||
}
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
|
@ -100,6 +100,9 @@ END(rtld_start)
|
|||||||
#define XCALLFRAME_A4 (0*SZREG)
|
#define XCALLFRAME_A4 (0*SZREG)
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Trampoline for "old" PLT stubs which use .got entries.
|
||||||
|
*/
|
||||||
.globl _rtld_bind_start
|
.globl _rtld_bind_start
|
||||||
.ent _rtld_bind_start
|
.ent _rtld_bind_start
|
||||||
_rtld_bind_start:
|
_rtld_bind_start:
|
||||||
@ -188,3 +191,94 @@ _rtld_bind_start:
|
|||||||
nop
|
nop
|
||||||
.cfi_endproc
|
.cfi_endproc
|
||||||
END(_rtld_bind_start)
|
END(_rtld_bind_start)
|
||||||
|
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Trampoline for PLT stubs using .pltrel entries and .got.plt.
|
||||||
|
*/
|
||||||
|
.globl _rtld_pltbind_start
|
||||||
|
.ent _rtld_pltbind_start
|
||||||
|
_rtld_pltbind_start:
|
||||||
|
.frame sp, XCALLFRAME_SIZ, $15
|
||||||
|
.cfi_startproc simple
|
||||||
|
.cfi_register ra, $15
|
||||||
|
#if defined(__mips_o32)
|
||||||
|
move v1, gp /* save pointer to .got.plt */
|
||||||
|
#else
|
||||||
|
move v1, t2 /* save pointer to .got.plt */
|
||||||
|
#endif
|
||||||
|
#if defined(__mips_o32) || defined(__mips_o64)
|
||||||
|
PTR_ADDU t9, 8 /* modify T9 to point at .cpload */
|
||||||
|
#endif
|
||||||
|
SETUP_GP
|
||||||
|
PTR_SUBU sp, XCALLFRAME_SIZ /* save arguments and sp value in stack */
|
||||||
|
.cfi_def_cfa sp, XCALLFRAME_SIZ
|
||||||
|
SETUP_GP64(XCALLFRAME_GP, _rtld_pltbind_start)
|
||||||
|
SAVE_GP(XCALLFRAME_GP)
|
||||||
|
#if defined(__mips_n32) || defined(__mips_n64)
|
||||||
|
REG_S a4, XCALLFRAME_A4(sp)
|
||||||
|
.cfi_rel_offset a4, XCALLFRAME_A4
|
||||||
|
REG_S a5, XCALLFRAME_A5(sp)
|
||||||
|
.cfi_rel_offset a5, XCALLFRAME_A5
|
||||||
|
REG_S a6, XCALLFRAME_A6(sp)
|
||||||
|
.cfi_rel_offset a6, XCALLFRAME_A6
|
||||||
|
REG_S a7, XCALLFRAME_A7(sp)
|
||||||
|
.cfi_rel_offset a7, XCALLFRAME_A7
|
||||||
|
#endif
|
||||||
|
REG_S a0, XCALLFRAME_A0(sp)
|
||||||
|
.cfi_rel_offset a0, XCALLFRAME_A0
|
||||||
|
REG_S a1, XCALLFRAME_A1(sp)
|
||||||
|
.cfi_rel_offset a1, XCALLFRAME_A1
|
||||||
|
REG_S a2, XCALLFRAME_A2(sp)
|
||||||
|
.cfi_rel_offset a2, XCALLFRAME_A2
|
||||||
|
REG_S a3, XCALLFRAME_A3(sp)
|
||||||
|
.cfi_rel_offset a3, XCALLFRAME_A3
|
||||||
|
REG_S $15, XCALLFRAME_RA(sp) /* ra is in t7/t3 */
|
||||||
|
.cfi_rel_offset ra, XCALLFRAME_RA
|
||||||
|
REG_S s0, XCALLFRAME_S0(sp)
|
||||||
|
.cfi_rel_offset s0, XCALLFRAME_S0
|
||||||
|
move s0, sp
|
||||||
|
|
||||||
|
move a0, v1 /* .got.plt */
|
||||||
|
#if defined(__mips_n64)
|
||||||
|
ld a0, 8(a0) /* object = .got.plt[1] */
|
||||||
|
sll a1, t8, 4 /* PLT entry index to .rel.plt offset */
|
||||||
|
#else
|
||||||
|
lw a0, 4(a0) /* object = .got.plt[1] */
|
||||||
|
sll a1, t8, 3 /* PLT entry index to .rel.plt offset */
|
||||||
|
#endif
|
||||||
|
|
||||||
|
PTR_LA t9, _C_LABEL(_rtld_bind)
|
||||||
|
jalr t9
|
||||||
|
nop
|
||||||
|
|
||||||
|
move sp, s0
|
||||||
|
REG_L ra, XCALLFRAME_RA(sp)
|
||||||
|
.cfi_restore ra
|
||||||
|
REG_L s0, XCALLFRAME_S0(sp)
|
||||||
|
.cfi_restore s0
|
||||||
|
REG_L a0, XCALLFRAME_A0(sp)
|
||||||
|
.cfi_restore a0
|
||||||
|
REG_L a1, XCALLFRAME_A1(sp)
|
||||||
|
.cfi_restore a1
|
||||||
|
REG_L a2, XCALLFRAME_A2(sp)
|
||||||
|
.cfi_restore a2
|
||||||
|
REG_L a3, XCALLFRAME_A3(sp)
|
||||||
|
.cfi_restore a3
|
||||||
|
#if defined(__mips_n32) || defined(__mips_n64)
|
||||||
|
REG_L a4, XCALLFRAME_A4(sp)
|
||||||
|
.cfi_restore a4
|
||||||
|
REG_L a5, XCALLFRAME_A5(sp)
|
||||||
|
.cfi_restore a5
|
||||||
|
REG_L a6, XCALLFRAME_A6(sp)
|
||||||
|
.cfi_restore a6
|
||||||
|
REG_L a7, XCALLFRAME_A7(sp)
|
||||||
|
.cfi_restore a7
|
||||||
|
#endif
|
||||||
|
RESTORE_GP64
|
||||||
|
PTR_ADDU sp, XCALLFRAME_SIZ
|
||||||
|
move t9, v0
|
||||||
|
jr t9
|
||||||
|
nop
|
||||||
|
.cfi_endproc
|
||||||
|
END(_rtld_pltbind_start)
|
||||||
|
@ -1257,6 +1257,12 @@ digest_dynamic1(Obj_Entry *obj, int early, const Elf_Dyn **dyn_rpath,
|
|||||||
case DT_MIPS_RLD_MAP:
|
case DT_MIPS_RLD_MAP:
|
||||||
*((Elf_Addr *)(dynp->d_un.d_ptr)) = (Elf_Addr) &r_debug;
|
*((Elf_Addr *)(dynp->d_un.d_ptr)) = (Elf_Addr) &r_debug;
|
||||||
break;
|
break;
|
||||||
|
|
||||||
|
case DT_MIPS_PLTGOT:
|
||||||
|
obj->mips_pltgot = (Elf_Addr *) (obj->relocbase +
|
||||||
|
dynp->d_un.d_ptr);
|
||||||
|
break;
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#ifdef __powerpc64__
|
#ifdef __powerpc64__
|
||||||
|
@ -187,6 +187,7 @@ typedef struct Struct_Obj_Entry {
|
|||||||
Elf_Word local_gotno; /* Number of local GOT entries */
|
Elf_Word local_gotno; /* Number of local GOT entries */
|
||||||
Elf_Word symtabno; /* Number of dynamic symbols */
|
Elf_Word symtabno; /* Number of dynamic symbols */
|
||||||
Elf_Word gotsym; /* First dynamic symbol in GOT */
|
Elf_Word gotsym; /* First dynamic symbol in GOT */
|
||||||
|
Elf_Addr *mips_pltgot; /* Second PLT GOT */
|
||||||
#endif
|
#endif
|
||||||
#ifdef __powerpc64__
|
#ifdef __powerpc64__
|
||||||
Elf_Addr glink; /* GLINK PLT call stub section */
|
Elf_Addr glink; /* GLINK PLT call stub section */
|
||||||
|
@ -1059,6 +1059,8 @@ typedef struct {
|
|||||||
#define R_MIPS_CALLLO16 31 /* lower 16 bit GOT entry for function */
|
#define R_MIPS_CALLLO16 31 /* lower 16 bit GOT entry for function */
|
||||||
#define R_MIPS_JALR 37
|
#define R_MIPS_JALR 37
|
||||||
#define R_MIPS_TLS_GD 42
|
#define R_MIPS_TLS_GD 42
|
||||||
|
#define R_MIPS_COPY 126
|
||||||
|
#define R_MIPS_JUMP_SLOT 127
|
||||||
|
|
||||||
#define R_PPC_NONE 0 /* No relocation. */
|
#define R_PPC_NONE 0 /* No relocation. */
|
||||||
#define R_PPC_ADDR32 1
|
#define R_PPC_ADDR32 1
|
||||||
|
Loading…
Reference in New Issue
Block a user