commit 6ba977ed6c7ac6e51350f2093ebe0b90ff89f90c Author: Mark Wielaard Date: Sun Jul 23 23:14:31 2023 +0200 libelf, readelf, elflint: Add RELR support Handle RELR as defined here: https://groups.google.com/g/generic-abi/c/bX460iggiKg/m/YT2RrjpMAwAJ Introduce new ELF_T_RELR Elf_Type and handle it for SHT_RELR. Check various properties in elflint. Print RELR relocations in readelf. Just the entries with -U. Just the addresses with -N. And addresses pluse symbol/offsets by default. * libebl/eblsectiontypename.c (ebl_section_type_name): Add RELR to knownstype. * libelf/elf32_updatenull.c (updatenull_wrlock): Handle sh_entsize for SHT_RELR. * libelf/gelf.h (Gelf_Relr): New typedef for Elf64_Relr. * libelf/gelf_fsize.c (__libelf_type_sizes): Add ELF_T_RELR. * libelf/gelf_xlate.c (__elf_xfctstom): Likewise. * libelf/gelf_xlate.h: Add RELR as FUNDAMENTAL. * libelf/libelf.h (Elf_Type): Add ELF_T_RELR. * libelf/libelfP.h: Define ELF32_FSZ_RELR and ELF64_FSZ_RELR. * src/elflint.c (check_reloc_shdr): Check she_entsize for ELF_T_RELR. (check_relr): New function. (check_dynamic): Handle DT_RELR. (special_sections): Add SHT_RELR. (check_sections): Call check_relr. * src/readelf.c (print_relocs): Also accept a Dwfl_Module. (handle_relocs_relr): New function. (print_dwarf_addr): Make static and declare early. (process_elf_file): Pass dwflmod to print_relocs. (handle_dynamic): Handle DT_RELRSZ and DTRELRENT. Signed-off-by: Mark Wielaard diff --git a/libebl/eblsectiontypename.c b/libebl/eblsectiontypename.c index 2008b95a..ade25d4a 100644 --- a/libebl/eblsectiontypename.c +++ b/libebl/eblsectiontypename.c @@ -61,7 +61,8 @@ ebl_section_type_name (Ebl *ebl, int section, char *buf, size_t len) KNOWNSTYPE (FINI_ARRAY), KNOWNSTYPE (PREINIT_ARRAY), KNOWNSTYPE (GROUP), - KNOWNSTYPE (SYMTAB_SHNDX) + KNOWNSTYPE (SYMTAB_SHNDX), + KNOWNSTYPE (RELR) }; /* Handle standard names. */ diff --git a/libelf/elf32_updatenull.c b/libelf/elf32_updatenull.c index 6c06e5e4..c5d26b00 100644 --- a/libelf/elf32_updatenull.c +++ b/libelf/elf32_updatenull.c @@ -256,6 +256,9 @@ __elfw2(LIBELFBITS,updatenull_wrlock) (Elf *elf, int *change_bop, size_t shnum) case SHT_SUNW_syminfo: sh_entsize = elf_typesize (LIBELFBITS, ELF_T_SYMINFO, 1); break; + case SHT_RELR: + sh_entsize = elf_typesize (LIBELFBITS, ELF_T_RELR, 1); + break; default: break; } diff --git a/libelf/gelf.h b/libelf/gelf.h index 7a3c87aa..f032d7e1 100644 --- a/libelf/gelf.h +++ b/libelf/gelf.h @@ -82,6 +82,9 @@ typedef Elf64_Rel GElf_Rel; /* Relocation table entry with addend (in section of type SHT_RELA). */ typedef Elf64_Rela GElf_Rela; +/* Relative relocation entry (in section of type SHT_RELR). */ +typedef Elf64_Relr Gelf_Relr; + /* Program segment header. */ typedef Elf64_Phdr GElf_Phdr; diff --git a/libelf/gelf_fsize.c b/libelf/gelf_fsize.c index 493d7916..63bcbae5 100644 --- a/libelf/gelf_fsize.c +++ b/libelf/gelf_fsize.c @@ -69,7 +69,8 @@ const size_t __libelf_type_sizes[ELFCLASSNUM - 1][ELF_T_NUM] = [ELF_T_LIB] = sizeof (ElfW2(LIBELFBITS, Ext_Lib)), \ [ELF_T_AUXV] = sizeof (ElfW2(LIBELFBITS, Ext_auxv_t)), \ [ELF_T_CHDR] = sizeof (ElfW2(LIBELFBITS, Ext_Chdr)), \ - [ELF_T_GNUHASH] = ELFW2(LIBELFBITS, FSZ_WORD) + [ELF_T_GNUHASH] = ELFW2(LIBELFBITS, FSZ_WORD), \ + [ELF_T_RELR] = ELFW2(LIBELFBITS, FSZ_RELR) TYPE_SIZES (32) }, [ELFCLASS64 - 1] = { diff --git a/libelf/gelf_xlate.c b/libelf/gelf_xlate.c index d8ad0634..749da1a1 100644 --- a/libelf/gelf_xlate.c +++ b/libelf/gelf_xlate.c @@ -204,7 +204,8 @@ const xfct_t __elf_xfctstom[ELFCLASSNUM - 1][ELF_T_NUM] = [ELF_T_MOVE] = ElfW2(Bits, cvt_Move), \ [ELF_T_LIB] = ElfW2(Bits, cvt_Lib), \ [ELF_T_AUXV] = ElfW2(Bits, cvt_auxv_t), \ - [ELF_T_CHDR] = ElfW2(Bits, cvt_chdr) + [ELF_T_CHDR] = ElfW2(Bits, cvt_chdr), \ + [ELF_T_RELR] = ElfW2(Bits, cvt_Relr) define_xfcts (32), [ELF_T_GNUHASH] = Elf32_cvt_Word }, diff --git a/libelf/gelf_xlate.h b/libelf/gelf_xlate.h index 3c0e4bf6..d5511c34 100644 --- a/libelf/gelf_xlate.h +++ b/libelf/gelf_xlate.h @@ -36,6 +36,7 @@ FUNDAMENTAL (WORD, Word, LIBELFBITS); FUNDAMENTAL (SWORD, Sword, LIBELFBITS); FUNDAMENTAL (XWORD, Xword, LIBELFBITS); FUNDAMENTAL (SXWORD, Sxword, LIBELFBITS); +FUNDAMENTAL (RELR, Relr, LIBELFBITS); /* The structured types. */ TYPE (Ehdr, LIBELFBITS) diff --git a/libelf/libelf.h b/libelf/libelf.h index 2374a48a..2837db72 100644 --- a/libelf/libelf.h +++ b/libelf/libelf.h @@ -124,6 +124,7 @@ typedef enum ELF_T_CHDR, /* Compressed, Elf32_Chdr, Elf64_Chdr, ... */ ELF_T_NHDR8, /* Special GNU Properties note. Same as Nhdr, except padding. */ + ELF_T_RELR, /* Relative relocation entry. */ /* Keep this the last entry. */ ELF_T_NUM } Elf_Type; diff --git a/libelf/libelfP.h b/libelf/libelfP.h index d3c241e5..96476064 100644 --- a/libelf/libelfP.h +++ b/libelf/libelfP.h @@ -63,6 +63,7 @@ #define ELF32_FSZ_SWORD 4 #define ELF32_FSZ_XWORD 8 #define ELF32_FSZ_SXWORD 8 +#define ELF32_FSZ_RELR 4 /* Same for 64 bits objects. */ #define ELF64_FSZ_ADDR 8 @@ -72,6 +73,7 @@ #define ELF64_FSZ_SWORD 4 #define ELF64_FSZ_XWORD 8 #define ELF64_FSZ_SXWORD 8 +#define ELF64_FSZ_RELR 8 /* This is an extension of the ELF_F_* enumeration. The values here are diff --git a/src/elflint.c b/src/elflint.c index dd42dcb4..864de710 100644 --- a/src/elflint.c +++ b/src/elflint.c @@ -1,5 +1,6 @@ /* Pedantic checking of ELF files compliance with gABI/psABI spec. Copyright (C) 2001-2015, 2017, 2018 Red Hat, Inc. + Copyright (C) 2023 Mark J. Wielaard This file is part of elfutils. Written by Ulrich Drepper , 2001. @@ -1291,10 +1292,20 @@ section [%2d] '%s': no relocations for merge-able string sections possible\n"), size_t sh_entsize = gelf_fsize (ebl->elf, reltype, 1, EV_CURRENT); if (shdr->sh_entsize != sh_entsize) - ERROR (_(reltype == ELF_T_RELA ? "\ -section [%2d] '%s': section entry size does not match ElfXX_Rela\n" : "\ -section [%2d] '%s': section entry size does not match ElfXX_Rel\n"), - idx, section_name (ebl, idx)); + { + if (reltype == ELF_T_RELA) + ERROR ("\ +section [%2d] '%s': section entry size does not match ElfXX_Rela\n", + idx, section_name (ebl, idx)); + else if (reltype == ELF_T_REL) + ERROR ("\ +section [%2d] '%s': section entry size does not match ElfXX_Rel\n", + idx, section_name (ebl, idx)); + else + ERROR ("\ +section [%2d] '%s': section entry size does not match ElfXX_Relr\n", + idx, section_name (ebl, idx)); + } /* In preparation of checking whether relocations are text relocations or not we need to determine whether the file is @@ -1590,6 +1601,32 @@ section [%2d] '%s': cannot get relocation %zu: %s\n"), } } +static void +check_relr (Ebl *ebl, GElf_Ehdr *ehdr, GElf_Shdr *shdr, int idx) +{ + Elf_Data *data = elf_getdata (elf_getscn (ebl->elf, idx), NULL); + if (data == NULL) + { + ERROR (_("section [%2d] '%s': cannot get section data\n"), + idx, section_name (ebl, idx)); + return; + } + + /* Check the fields of the section header. */ + GElf_Shdr destshdr_mem; + GElf_Shdr *destshdr = NULL; + struct loaded_segment *loaded = NULL; + check_reloc_shdr (ebl, ehdr, shdr, idx, ELF_T_RELR, &destshdr, + &destshdr_mem, &loaded); + + /* Just throw them away. */ + while (loaded != NULL) + { + struct loaded_segment *old = loaded; + loaded = loaded->next; + free (old); + } +} /* Number of dynamic sections. */ static int ndynamic; @@ -1780,6 +1817,7 @@ section [%2d] '%s': entry %zu: pointer does not match address of section [%2d] ' case DT_PLTGOT: case DT_REL: case DT_RELA: + case DT_RELR: case DT_SYMBOLIC: case DT_SYMTAB: case DT_VERDEF: @@ -3660,6 +3698,7 @@ static const struct { ".plt", 5, SHT_PROGBITS, unused, 0, 0 }, // XXX more tests { ".preinit_array", 15, SHT_PREINIT_ARRAY, exact, SHF_ALLOC | SHF_WRITE, 0 }, { ".rela", 5, SHT_RELA, atleast, 0, SHF_ALLOC | SHF_INFO_LINK }, // XXX more tests + { ".relr", 5, SHT_RELR, atleast, 0, SHF_ALLOC }, // XXX more tests { ".rel", 4, SHT_REL, atleast, 0, SHF_ALLOC | SHF_INFO_LINK }, // XXX more tests { ".rodata", 8, SHT_PROGBITS, atleast, SHF_ALLOC, SHF_MERGE | SHF_STRINGS }, { ".rodata1", 9, SHT_PROGBITS, atleast, SHF_ALLOC, SHF_MERGE | SHF_STRINGS }, @@ -4182,6 +4221,10 @@ section [%2zu] '%s': relocatable files cannot have dynamic symbol tables\n"), check_rel (ebl, ehdr, shdr, cnt); break; + case SHT_RELR: + check_relr (ebl, ehdr, shdr, cnt); + break; + case SHT_DYNAMIC: check_dynamic (ebl, ehdr, shdr, cnt); break; diff --git a/src/readelf.c b/src/readelf.c index eda0ce09..db31ad09 100644 --- a/src/readelf.c +++ b/src/readelf.c @@ -1,5 +1,6 @@ /* Print information from ELF file in human-readable form. Copyright (C) 1999-2018 Red Hat, Inc. + Copyright (C) 2023 Mark J. Wielaard This file is part of elfutils. This file is free software; you can redistribute it and/or modify @@ -302,11 +302,13 @@ static void print_phdr (Ebl *ebl, GElf_Ehdr *ehdr); static void print_scngrp (Ebl *ebl); static void print_dynamic (Ebl *ebl); -static void print_relocs (Ebl *ebl, GElf_Ehdr *ehdr); +static void print_relocs (Ebl *ebl, Dwfl_Module *mod, GElf_Ehdr *ehdr); static void handle_relocs_rel (Ebl *ebl, GElf_Ehdr *ehdr, Elf_Scn *scn, GElf_Shdr *shdr); static void handle_relocs_rela (Ebl *ebl, GElf_Ehdr *ehdr, Elf_Scn *scn, GElf_Shdr *shdr); +static void handle_relocs_relr (Ebl *ebl, Dwfl_Module *mod, Elf_Scn *scn, + GElf_Shdr *shdr); static bool print_symtab (Ebl *ebl, int type); static void handle_symtab (Ebl *ebl, Elf_Scn *scn, GElf_Shdr *shdr); static void print_verinfo (Ebl *ebl); @@ -336,6 +339,8 @@ static void dump_data (Ebl *ebl); static void dump_strings (Ebl *ebl); static void print_strings (Ebl *ebl); static void dump_archive_index (Elf *, const char *); +static void print_dwarf_addr (Dwfl_Module *dwflmod, int address_size, + Dwarf_Addr address, Dwarf_Addr raw); enum dyn_idx { @@ -1052,7 +1057,7 @@ process_elf_file (Dwfl_Module *dwflmod, int fd) if (print_dynamic_table) print_dynamic (ebl); if (print_relocations) - print_relocs (pure_ebl, ehdr); + print_relocs (pure_ebl, dwflmod, ehdr); if (print_histogram) handle_hash (ebl); if (print_symbol_table || print_dynsym_table) @@ -1971,9 +1976,11 @@ handle_dynamic (Ebl *ebl, Elf_Scn *scn, GElf_Shdr *shdr, GElf_Phdr *phdr) case DT_RELASZ: case DT_STRSZ: case DT_RELSZ: + case DT_RELRSZ: case DT_RELAENT: case DT_SYMENT: case DT_RELENT: + case DT_RELRENT: case DT_PLTPADSZ: case DT_MOVEENT: case DT_MOVESZ: @@ -2049,7 +2056,7 @@ print_dynamic (Ebl *ebl) /* Print relocations. */ static void -print_relocs (Ebl *ebl, GElf_Ehdr *ehdr) +print_relocs (Ebl *ebl, Dwfl_Module *mod, GElf_Ehdr *ehdr) { /* Find all relocation sections and handle them. */ Elf_Scn *scn = NULL; @@ -2066,6 +2073,8 @@ print_relocs (Ebl *ebl, GElf_Ehdr *ehdr) handle_relocs_rel (ebl, ehdr, scn, shdr); else if (shdr->sh_type == SHT_RELA) handle_relocs_rela (ebl, ehdr, scn, shdr); + else if (shdr->sh_type == SHT_RELR) + handle_relocs_relr (ebl, mod, scn, shdr); } } } @@ -2454,6 +2463,114 @@ handle_relocs_rela (Ebl *ebl, GElf_Ehdr *ehdr, Elf_Scn *scn, GElf_Shdr *shdr) } } +/* Handle a relocation section. */ +static void +handle_relocs_relr (Ebl *ebl, Dwfl_Module *mod, Elf_Scn *scn, GElf_Shdr *shdr) +{ + int class = gelf_getclass (ebl->elf); + size_t sh_entsize = gelf_fsize (ebl->elf, ELF_T_RELR, 1, EV_CURRENT); + int nentries = shdr->sh_size / sh_entsize; + + /* Get the data of the section. */ + Elf_Data *data = elf_getdata (scn, NULL); + if (data == NULL) + return; + + /* Get the section header string table index. */ + size_t shstrndx; + if (unlikely (elf_getshdrstrndx (ebl->elf, &shstrndx) < 0)) + error_exit (0, _("cannot get section header string table index")); + + /* A .relr.dyn section does not refer to a specific section. */ + printf (ngettext ("\ +\nRelocation section [%2u] '%s' at offset %#0" PRIx64 " contains %d entry:\n", + "\ +\nRelocation section [%2u] '%s' at offset %#0" PRIx64 " contains %d entries:\n", + nentries), + (unsigned int) elf_ndxscn (scn), + elf_strptr (ebl->elf, shstrndx, shdr->sh_name), + shdr->sh_offset, + nentries); + + if (class == ELFCLASS32) + { + uint32_t base = 0; + for (int cnt = 0; cnt < nentries; ++cnt) + { + Elf32_Word *words = data->d_buf; + Elf32_Word entry = words[cnt]; + + /* Just the raw entries? */ + if (print_unresolved_addresses) + printf (" %#010" PRIx32 "%s\n", entry, + (entry & 1) == 0 ? " *" : ""); + else + { + /* A real address, also sets base. */ + if ((entry & 1) == 0) + { + printf (" "); + print_dwarf_addr (mod, 4, entry, entry); + printf (" *\n"); + + base = entry + 4; + } + else + { + /* Untangle address from base and bits. */ + uint32_t addr; + for (addr = base; (entry >>= 1) != 0; addr += 4) + if ((entry & 1) != 0) + { + printf (" "); + print_dwarf_addr (mod, 4, addr, addr); + printf ("\n"); + } + base += 4 * (4 * 8 - 1); + } + } + } + } + else + { + uint64_t base = 0; + for (int cnt = 0; cnt < nentries; ++cnt) + { + Elf64_Xword *xwords = data->d_buf; + Elf64_Xword entry = xwords[cnt]; + + /* Just the raw entries? */ + if (print_unresolved_addresses) + printf (" %#018" PRIx64 "%s\n", entry, + (entry & 1) == 0 ? " *" : ""); + else + { + /* A real address, also sets base. */ + if ((entry & 1) == 0) + { + printf (" "); + print_dwarf_addr (mod, 8, entry, entry); + printf (" *\n"); + + base = entry + 8; + } + else + { + /* Untangle address from base and bits. */ + uint64_t addr; + for (addr = base; (entry >>= 1) != 0; addr += 8) + if ((entry & 1) != 0) + { + printf (" "); + print_dwarf_addr (mod, 8, addr, addr); + printf ("\n"); + } + base += 8 * (8 * 8 - 1); + } + } + } + } +} /* Print the program header. Return true if a symtab is printed, false otherwise. */ @@ -4107,7 +4224,7 @@ get_debug_elf_data (Dwarf *dbg, Ebl *ebl, int idx, Elf_Scn *scn) return elf_getdata (scn, NULL); } -void +static void print_dwarf_addr (Dwfl_Module *dwflmod, int address_size, Dwarf_Addr address, Dwarf_Addr raw) {