The branch main has been updated by andrew:

URL: 
https://cgit.FreeBSD.org/src/commit/?id=d51fa0a9b11db524a8e872c0019e54846a03d8a9

commit d51fa0a9b11db524a8e872c0019e54846a03d8a9
Author:     Andrew Turner <[email protected]>
AuthorDate: 2024-04-17 15:29:29 +0000
Commit:     Andrew Turner <[email protected]>
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);
 

Reply via email to