For duplicate strings, elf_add_string() just blindly adds duplicates.

That can be a problem for arm64 which often uses two consecutive
instructions (and corresponding relocations) to put an address into a
register, like:

  d8:   90000001        adrp    x1, 0 <meminfo_proc_show>       d8: 
R_AARCH64_ADR_PREL_PG_HI21  .rodata.meminfo_proc_show.str1.8
  dc:   91000021        add     x1, x1, #0x0    dc: R_AARCH64_ADD_ABS_LO12_NC   
.rodata.meminfo_proc_show.str1.8

Referencing two different string addresses in the adrp+add pair can
result in a corrupt string addresses.  Detect such consecutive reuses
and force them to use the same string.

Signed-off-by: Josh Poimboeuf <[email protected]>
---
 tools/objtool/elf.c | 9 ++++++++-
 1 file changed, 8 insertions(+), 1 deletion(-)

diff --git a/tools/objtool/elf.c b/tools/objtool/elf.c
index 3da90686350d..52ef991115fc 100644
--- a/tools/objtool/elf.c
+++ b/tools/objtool/elf.c
@@ -1321,6 +1321,8 @@ struct elf *elf_create_file(GElf_Ehdr *ehdr, const char 
*name)
 
 unsigned int elf_add_string(struct elf *elf, struct section *strtab, const 
char *str)
 {
+       static unsigned int last_off;
+       static const char *last_str;
        unsigned int offset;
 
        if (!strtab)
@@ -1329,17 +1331,22 @@ unsigned int elf_add_string(struct elf *elf, struct 
section *strtab, const char
                ERROR("can't find .strtab section");
                return -1;
        }
-
        if (!strtab->sh.sh_addralign) {
                ERROR("'%s': invalid sh_addralign", strtab->name);
                return -1;
        }
 
+       if (last_str && !strcmp(last_str, str))
+               return last_off;
+
        offset = ALIGN(strtab->sh.sh_size, strtab->sh.sh_addralign);
 
        if (!elf_add_data(elf, strtab, str, strlen(str) + 1))
                return -1;
 
+       last_str = str;
+       last_off = offset;
+
        return offset;
 }
 
-- 
2.53.0


Reply via email to