[PATCH v2 4/6] Readelf for nanoMIPS.
"Tsing" <[email protected]> Fri, 24 Jul 2026 18:30:56 +0800
| Newsgroups | gmane.comp.gnu.binutils |
|---|---|
| Message-ID | <[email protected]> |
From: tsing <[email protected]> binutils/ * readelf.c (guess_is_rela): Add EM_NANOMIPS. (get_machine_name): Likewise. (dump_relocations): Add support for nanomips relocations. (get_machine_flags): Add support for nanomips flags. (is_32bit_abs_reloc): Add R_NANOMIPS_32. (is_32bit_pcrel_reloc): Add R_NANOMIPS_PC32. (is_64bit_abs_reloc): Add R_NANOMIPS_64. (is_16bit_abs_reloc): Add R_NANOMIPS_UNSIGNED_16. (is_none_reloc): Add R_NANOMIPS_NONE. --- binutils/readelf.c | 422 +++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 422 insertions(+) diff --git a/binutils/readelf.c b/binutils/readelf.c index a52fe2b8d63..ec9f5ebb484 100644 --- a/binutils/readelf.c +++ b/binutils/readelf.c @@ -141,6 +141,7 @@ #include "elf/moxie.h" #include "elf/mt.h" #include "elf/msp430.h" +#include "elf/nanomips.h" #include "elf/nds32.h" #include "elf/nfp.h" #include "elf/nios2.h" @@ -1319,6 +1320,7 @@ guess_is_rela (unsigned int e_machine) case EM_MSP430: case EM_MSP430_OLD: case EM_MT: + case EM_NANOMIPS: case EM_NDS32: case EM_NIOS32: case EM_OR1K: @@ -2687,6 +2689,10 @@ dump_relocations (Filedata * filedata, case EM_AMDGPU: rtype = elf_amdgpu_reloc_type (type); break; + + case EM_NANOMIPS: + rtype = elf_nanomips_reloc_type (type); + break; } char *symbol_name = NULL; @@ -3812,6 +3818,7 @@ get_machine_name (unsigned e_machine) case EM_CEVA: return "CEVA Processor Architecture Family"; case EM_CEVA_X2: return "CEVA X2 Processor Family"; case EM_BPF: return "Linux BPF"; + case EM_NANOMIPS: return "nanoMIPS"; case EM_GRAPHCORE_IPU: return "Graphcore Intelligent Processing Unit"; case EM_IMG1: return "Imagination Technologies"; /* 250 */ @@ -5625,6 +5632,38 @@ get_machine_flags (Filedata * filedata, unsigned e_flags, unsigned e_machine) out = decode_MSP430_machine_flags (out, e_flags); break; + case EM_NANOMIPS: + if (e_flags & EF_NANOMIPS_PIC) + strcat (buf, ", pic"); + + if (e_flags & EF_NANOMIPS_32BITMODE) + strcat (buf, ", 32bitmode"); + + switch ((e_flags & EF_NANOMIPS_MACH)) + { + default: strcat (buf, _(", unknown CPU")); break; + } + + switch ((e_flags & EF_NANOMIPS_ABI)) + { + case E_NANOMIPS_ABI_P32: strcat (buf, ", p32"); break; + case E_NANOMIPS_ABI_P64: strcat (buf, ", p64"); break; + case 0: + /* We simply ignore the field in this case to avoid confusion: + MIPS ELF does not specify EF_MIPS_ABI, it is a GNU extension. + This means it is likely to be an o32 file, but not for + sure. */ + break; + default: strcat (buf, _(", unknown ABI")); break; + } + + switch ((e_flags & EF_NANOMIPS_ARCH)) + { + case E_NANOMIPS_ARCH_32R6: strcat (buf, ", nanomips32r6"); break; + case E_NANOMIPS_ARCH_64R6: strcat (buf, ", nanomips64r6"); break; + default: strcat (buf, _(", unknown ISA")); break; + } + case EM_Z80: out = decode_Z80_machine_flags (out, e_flags); break; @@ -16077,6 +16116,35 @@ target_specific_reloc_handling (Filedata *filedata, } break; } + case EM_NANOMIPS: + { + static Elf_Internal_Sym * saved_sym = NULL; + + if (reloc == NULL) + { + saved_sym = NULL; + return true; + } + + if (reloc_type == 3) + { + saved_sym = symtab + sym_index; + bfd_vma value; + + if (sym_index >= num_syms) + error (_("nanomips reloc contains invalid symbol index %lu\n"), + sym_index); + else + { + value = reloc->r_addend - saved_sym->st_value; + reloc++; + reloc->r_addend += value; + return true; + } + break; + } + break; + } } return false; @@ -16210,6 +16278,8 @@ is_32bit_abs_reloc (Filedata * filedata, unsigned int reloc_type) return reloc_type == 1; /* R_MSP430_32 or R_MSP320_ABS32. */ case EM_MT: return reloc_type == 2; /* R_MT_32. */ + case EM_NANOMIPS: + return reloc_type == 1; /* R_NANOMIPS_32. */ case EM_NDS32: return reloc_type == 20; /* R_NDS32_32_RELA. */ case EM_ALTERA_NIOS2: @@ -16332,6 +16402,8 @@ is_32bit_pcrel_reloc (Filedata * filedata, unsigned int reloc_type) return reloc_type == 99; /* R_LARCH_32_PCREL. */ case EM_MICROBLAZE: return reloc_type == 2; /* R_MICROBLAZE_32_PCREL. */ + case EM_NANOMIPS: + return reloc_type == 248; /* R_NANOMIPS_PC32. */ case EM_OR1K: return reloc_type == 9; /* R_OR1K_32_PCREL. */ case EM_PARISC: @@ -16421,6 +16493,8 @@ is_64bit_abs_reloc (Filedata * filedata, unsigned int reloc_type) return reloc_type == 1; /* R_TILEGX_64. */ case EM_MIPS: return reloc_type == 18; /* R_MIPS_64. */ + case EM_NANOMIPS: + return reloc_type == 2; /* R_NANOMIPS_64. */ case EM_KVX: return reloc_type == 3; /* R_KVX_64 */ default: @@ -16534,6 +16608,8 @@ is_16bit_abs_reloc (Filedata * filedata, unsigned int reloc_type) /* Fall through. */ case EM_MSP430_OLD: return reloc_type == 5; /* R_MSP430_16_BYTE. */ + case EM_NANOMIPS: + return reloc_type == 7; /* R_NANOMIPS_UNSIGNED_16 */ case EM_NDS32: return reloc_type == 19; /* R_NDS32_16_RELA. */ case EM_ALTERA_NIOS2: @@ -16818,6 +16894,7 @@ is_none_reloc (Filedata * filedata, unsigned int reloc_type) case EM_X86_64: /* R_X86_64_NONE. */ case EM_Z80: /* R_Z80_NONE. */ case EM_WEBASSEMBLY: /* R_WASM32_NONE. */ + case EM_NANOMIPS: /* R_NANOMIPS_NONE. */ return reloc_type == 0; case EM_AARCH64: @@ -19367,6 +19444,23 @@ display_mips_gnu_attribute (const unsigned char * p, return display_tag_value (tag & 1, p, end); } +static unsigned char * +display_nanomips_gnu_attribute (unsigned char * p, + unsigned int tag, + const unsigned char * const end) +{ + if (tag == Tag_GNU_NANOMIPS_ABI_FP) + { + int val; + + READ_ULEB (val, p, end); + printf (" Tag_GNU_NANOMIPS_ABI_FP: "); + return p; + } + + return display_tag_value (tag & 1, p, end); +} + static const unsigned char * display_tic6x_attribute (const unsigned char * p, const unsigned char * const end) @@ -21826,6 +21920,331 @@ process_got_section_contents (Filedata * filedata) return res; } +static void +print_nanomips_ases (unsigned int mask) +{ + if (mask & NANOMIPS_ASE_MT) + fputs ("\n\tMT ASE", stdout); + if (mask & NANOMIPS_ASE_VIRT) + fputs ("\n\tVZ ASE", stdout); + if ((mask & NANOMIPS_ASE_xNMS) == 0) + fputs ("\n\tnanoMIPS subset", stdout); + else if (mask == 0) + fprintf (stdout, "\n\t%s", _("None")); + else if ((mask & ~NANOMIPS_ASE_MASK) != 0) + fprintf (stdout, "\n\t%s (%x)", _("Unknown"), mask & ~NANOMIPS_ASE_MASK); +} + +static void +print_nanomips_isa_ext (unsigned int isa_ext) +{ + switch (isa_ext) + { + case 0: + fputs (_("None"), stdout); + break; + default: + fprintf (stdout, "%s (%d)", _("Unknown"), isa_ext); + } +} + +static int +get_nanomips_reg_size (int reg_size) +{ + return (get_mips_reg_size (reg_size)); +} + +/* DATA points to the contents of a nanoMIPS GOT that starts at VMA PLTGOT. + Print the Address, Access and Initial fields of an entry at VMA ADDR + and return the VMA of the next entry, or -1 if there was a problem. + Does not read from DATA_END or beyond. */ + +static bfd_vma +print_nanomips_got_entry (unsigned char * data, bfd_vma pltgot, bfd_vma addr, + unsigned char * data_end) +{ + printf (" "); + print_vma (addr, LONG_HEX); + printf (" %8d(gp) ", (int) (addr - pltgot)); + + if (data == NULL) + printf ("%*s", is_32bit_elf ? 8 : 16, _("<unknown>")); + else + { + bfd_vma entry; + unsigned char * from = data + addr - pltgot; + + if (from + (is_32bit_elf ? 4 : 8) > data_end) + { + warn (_("nanoMIPS GOT entry extends beyond the end of available data\n")); + printf ("%*s", is_32bit_elf ? 8 : 16, _("<corrupt>")); + return (bfd_vma) -1; + } + else + { + entry = byte_get (data + addr - pltgot, is_32bit_elf ? 4 : 8); + print_vma (entry, LONG_HEX); + } + } + return addr + (is_32bit_elf ? 4 : 8); +} + +/* Comparison function to sort relocs by increasing offsets. */ + +static /* signed */ int +relcmp (const void *p, const void *q) +{ + Elf_Internal_Rela *sp = (Elf_Internal_Rela *) p; + Elf_Internal_Rela *sq = (Elf_Internal_Rela *) q; + + return (sp->r_offset > sq->r_offset + ? 1 + : (sp->r_offset < sq->r_offset ? -1 : 0)); +} + +/* Pretty-print the nanoMIPS GOT. */ + +static bool +print_nanomips_got (Filedata * filedata) +{ + Elf_Internal_Shdr *sect = NULL; + bfd_vma pltgot = 0; + unsigned char *data_end; + unsigned char *data; + bfd_vma ent = 0; + bfd_vma end; + int addr_size; + int sym_width; + struct { + Elf_Internal_Rela * rels; + unsigned long relsize; + unsigned rindex; + } rtable[3]; + int i; + enum {REL=0, RELA=1, JMPREL=2}; + + /* Clear the relocs. */ + memset (rtable, 0, sizeof (rtable)); + + /* Fetch the GOT. */ + sect = find_section (filedata, ".got"); + + if (sect == NULL) + return true; + + /* This is overly complicated in order to handle dynamic relocations as + either REL or RELA and to handle the case where jump relocations are + embedded within the dynamic relocations section. */ + if (filedata->dynamic_info[DT_REL] != 0) + { + if (!slurp_rel_relocs (filedata, + offset_from_vma (filedata, filedata->dynamic_info[DT_REL], + filedata->dynamic_info[DT_RELENT]), + filedata->dynamic_info[DT_RELSZ], + &rtable[REL].rels, &rtable[REL].relsize)) + return false; + /* Sort for easy lookup. */ + qsort (rtable[REL].rels, rtable[REL].relsize, + sizeof (Elf_Internal_Rela), relcmp); + } + if (filedata->dynamic_info[DT_RELA] != 0) + { + if (!slurp_rel_relocs (filedata, + offset_from_vma (filedata, filedata->dynamic_info[DT_RELA], + filedata->dynamic_info[DT_RELAENT]), + filedata->dynamic_info[DT_RELASZ], + &rtable[RELA].rels, &rtable[RELA].relsize)) + return false; + /* Sort for easy lookup. */ + qsort (rtable[RELA].rels, rtable[RELA].relsize, sizeof (Elf_Internal_Rela), relcmp); + } + if (filedata->dynamic_info[DT_JMPREL] != 0) + { + int rent = ((filedata->dynamic_info[DT_PLTREL] == DT_REL) + ? filedata->dynamic_info[DT_RELENT] : filedata->dynamic_info[DT_RELAENT]); + /* If jump relocations are embedded within regular dynamic relocations, + we don't need to read them again. They have already been read above. */ + if ((filedata->dynamic_info[DT_PLTREL] == DT_REL + && (filedata->dynamic_info[DT_JMPREL] < filedata->dynamic_info[DT_REL] + || filedata->dynamic_info[DT_JMPREL] >= filedata->dynamic_info[DT_REL] + filedata->dynamic_info[DT_RELSZ])) + || (filedata->dynamic_info[DT_PLTREL] == DT_RELA + && (filedata->dynamic_info[DT_JMPREL] < filedata->dynamic_info[DT_RELA] + || filedata->dynamic_info[DT_JMPREL] >= filedata->dynamic_info[DT_RELA] + filedata->dynamic_info[DT_RELASZ]))) + { + if (!slurp_rel_relocs (filedata, + offset_from_vma (filedata, filedata->dynamic_info[DT_JMPREL], rent), + filedata->dynamic_info[DT_PLTRELSZ], + &rtable[JMPREL].rels, &rtable[JMPREL].relsize)) + return false; + /* Sort for easy lookup. */ + qsort (rtable[JMPREL].rels, rtable[JMPREL].relsize, sizeof (Elf_Internal_Rela), relcmp); + } + } + /* Temporary hack. Remove when the linker generate DT_JMPREL. */ + else if (find_section (filedata, ".rel.nanoMIPS.stubs") != NULL) + { + Elf_Internal_Shdr *jumpsect = find_section (filedata, ".rel.nanoMIPS.stubs"); + if (!slurp_rel_relocs (filedata, + offset_from_vma (filedata, jumpsect->sh_addr, + filedata->dynamic_info[DT_RELENT]), + jumpsect->sh_size, + &rtable[JMPREL].rels, &rtable[JMPREL].relsize)) + return false; + } + + pltgot = sect->sh_addr; + + /* Find relocations corresponding to the beginning of the GOT. */ + for (i = REL; i <= JMPREL; i++) + while (rtable[i].rindex < rtable[i].relsize + && rtable[i].rels[rtable[i].rindex].r_offset < pltgot) + rtable[i].rindex++; + + ent = pltgot; + addr_size = (is_32bit_elf ? 4 : 8); + /* Available screen width for symbols is whatever is left over + after everything else, including column-separating whitespaces. */ + sym_width = ((is_32bit_elf ? 80 : 160) - 32 - addr_size * 4); + end = pltgot + sect->sh_size; + + data = (unsigned char *) get_data (NULL, filedata, sect->sh_offset, + end - pltgot, 1, + _("Global Offset Table data")); + data_end = data + (end - pltgot); + + printf (_("\nGOT:\n")); + printf (_(" GP value: ")); + print_vma (ent, LONG_HEX); + printf ("\n\n"); + + /* In a dynamic binary GOT[0] is reserved for the dynamic + loader to store the lazy resolver pointer, however in + a static binary it may well have been omitted and GOT + reduced to a table of addresses. */ + if (data + && data + ent - pltgot + addr_size <= data_end + && byte_get (data + ent - pltgot, addr_size) == 0) + { + printf (_(" Reserved entries:\n")); + printf (_(" %*s %*s %*s Purpose\n"), + (- addr_size * 2) + 1, _("Address"), 12, _("Access"), + (- addr_size * 2) + 1, _("Initial")); + ent = print_nanomips_got_entry (data, pltgot, ent, data_end); + printf (_(" Lazy stub resolver\n")); + if (ent == (bfd_vma) -1) + goto sgot_print_fail; + + if (ent == (bfd_vma) -1) + goto sgot_print_fail; + + /* Check for the MSB of GOT[1] being set, identifying a + GNU object. This entry will be used by some runtime + loaders, to store the module pointer. Otherwise this + is an ordinary local entry. */ + if (data + && data + ent - pltgot + addr_size <= data_end + && (byte_get (data + ent - pltgot, addr_size) + >> (addr_size * 8 - 1)) != 0) + { + printf ("\n"); + ent = print_nanomips_got_entry (data, pltgot, ent, data_end); + printf (_(" Module pointer\n")); + if (ent == (bfd_vma) -1) + goto sgot_print_fail; + } + printf ("\n"); + } + + if (ent < end) + { + printf (_(" Entries:\n")); + printf (_(" %*s %*s %*s %*s Name\n"), + (- addr_size * 2) + 1, _("Address"), 12, _("Access"), + (- addr_size * 2) + 1, _("Value"), -9, _("Type")); + } + + while (ent < end) + { + Elf_Internal_Rela *rel = NULL; + bfd_vma next_ent = print_nanomips_got_entry (data, pltgot, + ent, data_end); + if (next_ent == (bfd_vma) -1) + { + ent = (bfd_vma) -1; + goto sgot_print_fail; + } + + /* Scan all relocations for a match against this GOT slot. */ + for (i = REL; i <= JMPREL; i++) + { + while (rel == NULL && rtable[i].rindex < rtable[i].relsize) + { + if (rtable[i].rels[rtable[i].rindex].r_offset == ent) + rel = &rtable[i].rels[rtable[i].rindex]; + if (rtable[i].rels[rtable[i].rindex].r_offset >= ent) + break; + rtable[i].rindex ++; + } + } + + if (rel != NULL) + { + Elf_Internal_Sym * psym = 0; + + switch (get_reloc_type (filedata, rel->r_info)) + { + case 11: /* R_NANOMIPS_JUMP_SLOT. */ + printf (" %*s ", -10, "Lazy-stub"); break; + case 12: /* R_NANOMIPS_IRELATIVE. */ + printf (" %*s ", -10, "Indirect"); break; + case 10: /* R_NANOMIPS_GLOBAL. */ + case 1: /* R_NANOMIPS_32. */ + case 2: /* R_NANOMIPS_64. */ + printf (" %*s ", -10, "Global"); break; + case 9: /* R_NANOMIPS_RELATIVE. */ + printf (" %*s ", -10, "Local"); break; + default: + break; + } + + if (filedata->dynamic_symbols) + { + psym = (filedata->dynamic_symbols + get_reloc_symindex (rel->r_info)); + + if (valid_dynamic_name (filedata, psym->st_name)) + print_symbol_name (sym_width, get_dynamic_name (filedata, psym->st_name)); + else + printf (_("<corrupt: %14ld>"), psym->st_name); + } + } + + ent = next_ent; + printf ("\n"); + } + printf ("\n"); + + sgot_print_fail: + if (data) + free (data); + + for (i = REL; i <= JMPREL; i++) + if (rtable[i].rels) + free (rtable[i].rels); + + return (ent != (bfd_vma) -1);; +} + + +static bool +process_nanomips_specific (Filedata * filedata) +{ + process_attributes (filedata, NULL, SHT_GNU_ATTRIBUTES, NULL, + display_nanomips_gnu_attribute); + + /* Pretty-print the GOT. */ + return print_nanomips_got (filedata); +} + static bool process_gnu_liblist (Filedata * filedata) { @@ -24759,6 +25178,9 @@ process_arch_specific (Filedata * filedata) display_riscv_attribute, display_generic_attribute); + case EM_NANOMIPS: + return process_nanomips_specific (filedata); + case EM_NDS32: return process_nds32_specific (filedata); -- 2.39.5