git: d51fa0a9b11d - main - rtld: Add support for arm64 variant pcs
- Go to: [ bottom of page ] [ top of archives ] [ this month ]
Date: Fri, 17 May 2024 10:21:51 UTC
The branch main has been updated by andrew: URL: https://cgit.FreeBSD.org/src/commit/?id=d51fa0a9b11db524a8e872c0019e54846a03d8a9 commit d51fa0a9b11db524a8e872c0019e54846a03d8a9 Author: Andrew Turner <andrew@FreeBSD.org> AuthorDate: 2024-04-17 15:29:29 +0000 Commit: Andrew Turner <andrew@FreeBSD.org> CommitDate: 2024-05-17 09:37:23 +0000 rtld: Add support for arm64 variant pcs The aarch64 ELF spec has support for a variant of the normal procedure call standard that doesn't follow the normal register convention, e.g. using more registers as arguments, or different register state is preserved. Add support to rtld to handle this. As we don't know which registers need to be preserved disable lazy binding for these functions. Reviewed by: kib Sponsored by: Arm Ltd Differential Revision: https://reviews.freebsd.org/D44869 --- libexec/rtld-elf/aarch64/reloc.c | 50 +++++++++++++++++++++++++++++++-- libexec/rtld-elf/aarch64/rtld_machdep.h | 6 ++-- 2 files changed, 51 insertions(+), 5 deletions(-) diff --git a/libexec/rtld-elf/aarch64/reloc.c b/libexec/rtld-elf/aarch64/reloc.c index d73982e26b76..78e2e2b1aaae 100644 --- a/libexec/rtld-elf/aarch64/reloc.c +++ b/libexec/rtld-elf/aarch64/reloc.c @@ -54,6 +54,17 @@ void *_rtld_tlsdesc_dynamic(void *); void _exit(int); +bool +arch_digest_dynamic(struct Struct_Obj_Entry *obj, const Elf_Dyn *dynp) +{ + if (dynp->d_tag == DT_AARCH64_VARIANT_PCS) { + obj->variant_pcs = true; + return (true); + } + + return (false); +} + bool arch_digest_note(struct Struct_Obj_Entry *obj __unused, const Elf_Note *note) { @@ -228,19 +239,54 @@ reloc_tlsdesc(const Obj_Entry *obj, const Elf_Rela *rela, Elf_Addr *where, int reloc_plt(Obj_Entry *obj, int flags, RtldLockState *lockstate) { + const Obj_Entry *defobj; const Elf_Rela *relalim; const Elf_Rela *rela; + const Elf_Sym *def, *sym; + bool lazy; relalim = (const Elf_Rela *)((const char *)obj->pltrela + obj->pltrelasize); for (rela = obj->pltrela; rela < relalim; rela++) { - Elf_Addr *where; + Elf_Addr *where, target; where = (Elf_Addr *)(obj->relocbase + rela->r_offset); switch(ELF_R_TYPE(rela->r_info)) { case R_AARCH64_JUMP_SLOT: - *where += (Elf_Addr)obj->relocbase; + lazy = true; + if (obj->variant_pcs) { + sym = &obj->symtab[ELF_R_SYM(rela->r_info)]; + /* + * Variant PCS functions don't follow the + * standard register convention. Because of + * this we can't use lazy relocation and + * need to set the target address. + */ + if ((sym->st_other & STO_AARCH64_VARIANT_PCS) != + 0) + lazy = false; + } + if (lazy) { + *where += (Elf_Addr)obj->relocbase; + } else { + def = find_symdef(ELF_R_SYM(rela->r_info), obj, + &defobj, SYMLOOK_IN_PLT | flags, NULL, + lockstate); + if (def == NULL) + return (-1); + if (ELF_ST_TYPE(def->st_info) == STT_GNU_IFUNC){ + obj->gnu_ifunc = true; + continue; + } + target = (Elf_Addr)(defobj->relocbase + + def->st_value); + /* + * Ignore ld_bind_not as it requires lazy + * binding + */ + *where = target; + } break; case R_AARCH64_TLSDESC: reloc_tlsdesc(obj, rela, where, SYMLOOK_IN_PLT | flags, diff --git a/libexec/rtld-elf/aarch64/rtld_machdep.h b/libexec/rtld-elf/aarch64/rtld_machdep.h index 347ef5f381fe..3cc1339fcad4 100644 --- a/libexec/rtld-elf/aarch64/rtld_machdep.h +++ b/libexec/rtld-elf/aarch64/rtld_machdep.h @@ -37,7 +37,8 @@ struct Struct_Obj_Entry; -#define MD_OBJ_ENTRY +#define MD_OBJ_ENTRY \ + bool variant_pcs : 1; /* Object has a variant pcs function */ /* Return the address of the .dynamic section in the dynamic linker. */ #define rtld_dynamic(obj) \ @@ -47,8 +48,7 @@ struct Struct_Obj_Entry; (const Elf_Dyn *)_dynamic_addr; \ }) -/* No arch-specific dynamic tags */ -#define arch_digest_dynamic(obj, dynp) false +bool arch_digest_dynamic(struct Struct_Obj_Entry *obj, const Elf_Dyn *dynp); bool arch_digest_note(struct Struct_Obj_Entry *obj, const Elf_Note *note);