From cee76805bac8f0060fcfeae765da05cfe9557c7e Mon Sep 17 00:00:00 2001 From: aadaa_fgtaa <aadaa_fgtaa@pm.me> Date: Sun, 11 Jun 2023 21:54:43 +0200 Subject: [PATCH] Optimise ELF linker (#23464) - cache last elements of `relTable`, `relaTable` and `symbolTables` in `ocInit_ELF` - cache shndx table in ObjectCode - run `checkProddableBlock` only with debug rts (cherry picked from commit b3e1436f968c0c36a27ea0339ee2554970b329fe) --- rts/Linker.c | 4 +++ rts/LinkerInternals.h | 18 +++++++++++++ rts/linker/Elf.c | 62 +++++++++++++++++++++++++++++-------------- 3 files changed, 64 insertions(+), 20 deletions(-) diff --git a/rts/Linker.c b/rts/Linker.c index 152f6f9281c..59e2ff9397a 100644 --- a/rts/Linker.c +++ b/rts/Linker.c @@ -1379,6 +1379,10 @@ mkOc( ObjectType type, pathchar *path, char *image, int imageSize, oc->rx_m32 = m32_allocator_new(true); #endif +#if defined(OBJFORMAT_ELF) && defined(SHN_XINDEX) + oc->shndx_table = SHNDX_TABLE_UNINIT; +#endif + oc->nc_ranges = NULL; oc->dlopen_handle = NULL; diff --git a/rts/LinkerInternals.h b/rts/LinkerInternals.h index 6797095d1ee..271611a249d 100644 --- a/rts/LinkerInternals.h +++ b/rts/LinkerInternals.h @@ -360,6 +360,15 @@ struct _ObjectCode { m32_allocator *rw_m32, *rx_m32; #endif +#if defined(OBJFORMAT_ELF) && defined(SHN_XINDEX) + /* Cached address of ELF's shndx table, or SHNDX_TABLE_UNINIT if not + * initialized yet. It would be better to put it info ELF-specific + * ObjectCodeFormatInfo, but unfortunately shndx table is needed in + * ocVerifyImage_ELF which runs before ObjectCodeFormatInfo is + * initialized by ocInit_ELF. */ + Elf_Word *shndx_table; +#endif + /* * The following are only valid if .type == DYNAMIC_OBJECT */ @@ -371,6 +380,15 @@ struct _ObjectCode { NativeCodeRange *nc_ranges; }; +#if defined(OBJFORMAT_ELF) && defined(SHN_XINDEX) +/* We cannot simply use NULL to signal uninitialised shndx_table because NULL + * is valid return value of get_shndx_table. Thus SHNDX_TABLE_UNINIT is defined + * as the address of global variable shndx_table_uninit_label, defined in + * rts/linker/Elf.c, which is definitely unequal to any heap-allocated address */ +extern Elf_Word shndx_table_uninit_label; +#define SHNDX_TABLE_UNINIT (&shndx_table_uninit_label) +#endif + #define OC_INFORMATIVE_FILENAME(OC) \ ( (OC)->archiveMemberName ? \ (OC)->archiveMemberName : \ diff --git a/rts/linker/Elf.c b/rts/linker/Elf.c index 040107c7f14..bab2ca30412 100644 --- a/rts/linker/Elf.c +++ b/rts/linker/Elf.c @@ -132,6 +132,11 @@ */ +#if defined(SHN_XINDEX) +/* global variable which address is used to signal an uninitialised shndx_table */ +Elf_Word shndx_table_uninit_label = 0; +#endif + static Elf_Word elf_shnum(Elf_Ehdr* ehdr) { Elf_Shdr* shdr = (Elf_Shdr*) ((char*)ehdr + ehdr->e_shoff); @@ -154,16 +159,22 @@ static Elf_Word elf_shstrndx(Elf_Ehdr* ehdr) #if defined(SHN_XINDEX) static Elf_Word* -get_shndx_table(Elf_Ehdr* ehdr) +get_shndx_table(ObjectCode* oc) { + if (RTS_LIKELY(oc->shndx_table != SHNDX_TABLE_UNINIT)) { + return oc->shndx_table; + } + Elf_Word i; - char* ehdrC = (char*)ehdr; + char* ehdrC = oc->image; + Elf_Ehdr* ehdr = (Elf_Ehdr*)ehdrC; Elf_Shdr* shdr = (Elf_Shdr*) (ehdrC + ehdr->e_shoff); const Elf_Word shnum = elf_shnum(ehdr); for (i = 0; i < shnum; i++) { if (shdr[i].sh_type == SHT_SYMTAB_SHNDX) { - return (Elf32_Word*)(ehdrC + shdr[i].sh_offset); + oc->shndx_table = (Elf32_Word*)(ehdrC + shdr[i].sh_offset); + return oc->shndx_table; } } return NULL; @@ -193,6 +204,10 @@ ocInit_ELF(ObjectCode * oc) oc->n_sections = elf_shnum(oc->info->elfHeader); + ElfRelocationTable *relTableLast = NULL; + ElfRelocationATable *relaTableLast = NULL; + ElfSymbolTable *symbolTablesLast = NULL; + /* get the symbol table(s) */ for(int i=0; i < oc->n_sections; i++) { if(SHT_REL == oc->info->sectionHeader[i].sh_type) { @@ -210,12 +225,12 @@ ocInit_ELF(ObjectCode * oc) relTab->sectionHeader = &oc->info->sectionHeader[i]; - if(oc->info->relTable == NULL) { + if(relTableLast == NULL) { oc->info->relTable = relTab; + relTableLast = relTab; } else { - ElfRelocationTable * tail = oc->info->relTable; - while(tail->next != NULL) tail = tail->next; - tail->next = relTab; + relTableLast->next = relTab; + relTableLast = relTab; } } else if(SHT_RELA == oc->info->sectionHeader[i].sh_type) { @@ -233,12 +248,12 @@ ocInit_ELF(ObjectCode * oc) relTab->sectionHeader = &oc->info->sectionHeader[i]; - if(oc->info->relaTable == NULL) { + if(relaTableLast == NULL) { oc->info->relaTable = relTab; + relaTableLast = relTab; } else { - ElfRelocationATable * tail = oc->info->relaTable; - while(tail->next != NULL) tail = tail->next; - tail->next = relTab; + relaTableLast->next = relTab; + relaTableLast = relTab; } } else if(SHT_SYMTAB == oc->info->sectionHeader[i].sh_type) { @@ -279,12 +294,12 @@ ocInit_ELF(ObjectCode * oc) } /* append the ElfSymbolTable */ - if(oc->info->symbolTables == NULL) { + if(symbolTablesLast == NULL) { oc->info->symbolTables = symTab; + symbolTablesLast = symTab; } else { - ElfSymbolTable * tail = oc->info->symbolTables; - while(tail->next != NULL) tail = tail->next; - tail->next = symTab; + symbolTablesLast->next = symTab; + symbolTablesLast = symTab; } } } @@ -329,6 +344,9 @@ ocDeinit_ELF(ObjectCode * oc) stgFree(oc->info); oc->info = NULL; +#if defined(SHN_XINDEX) + oc->shndx_table = SHNDX_TABLE_UNINIT; +#endif } } @@ -532,7 +550,7 @@ ocVerifyImage_ELF ( ObjectCode* oc ) IF_DEBUG(linker_verbose,debugBelch(" no normal string tables (potentially, but not necessarily a problem)\n")); } #if defined(SHN_XINDEX) - Elf_Word* shndxTable = get_shndx_table(ehdr); + Elf_Word* shndxTable = get_shndx_table(oc); #endif nsymtabs = 0; IF_DEBUG(linker_verbose,debugBelch( "Symbol tables\n" )); @@ -683,7 +701,7 @@ ocGetNames_ELF ( ObjectCode* oc ) Elf_Shdr* shdr = (Elf_Shdr*) (ehdrC + ehdr->e_shoff); Section * sections; #if defined(SHN_XINDEX) - Elf_Word* shndxTable = get_shndx_table(ehdr); + Elf_Word* shndxTable = get_shndx_table(oc); #endif const Elf_Word shnum = elf_shnum(ehdr); @@ -1251,7 +1269,11 @@ do_Elf_Rel_relocations ( ObjectCode* oc, char* ehdrC, IF_DEBUG(linker_verbose, debugBelch("Reloc: P = %p S = %p A = %p type=%d\n", (void*)P, (void*)S, (void*)A, reloc_type )); +#if defined(DEBUG) checkProddableBlock ( oc, pP, sizeof(Elf_Word) ); +#else + (void) pP; /* suppress unused varialbe warning in non-debug build */ +#endif #if defined(i386_HOST_ARCH) value = S + A; @@ -1555,7 +1577,7 @@ do_Elf_Rela_relocations ( ObjectCode* oc, char* ehdrC, int strtab_shndx = shdr[symtab_shndx].sh_link; int target_shndx = shdr[shnum].sh_info; #if defined(SHN_XINDEX) - Elf_Word* shndx_table = get_shndx_table((Elf_Ehdr*)ehdrC); + Elf_Word* shndx_table = get_shndx_table(oc); #endif #if defined(DEBUG) || defined(powerpc_HOST_ARCH) || defined(x86_64_HOST_ARCH) /* This #if def only serves to avoid unused-var warnings. */ @@ -1657,7 +1679,7 @@ do_Elf_Rela_relocations ( ObjectCode* oc, char* ehdrC, IF_DEBUG(linker_verbose,debugBelch("`%s' resolves to %p\n", symbol, (void*)S)); } -#if defined(DEBUG) || defined(powerpc_HOST_ARCH) || defined(x86_64_HOST_ARCH) +#if defined(DEBUG) IF_DEBUG(linker_verbose,debugBelch("Reloc: P = %p S = %p A = %p\n", (void*)P, (void*)S, (void*)A )); checkProddableBlock(oc, (void*)P, sizeof(Elf_Word)); @@ -1920,7 +1942,7 @@ ocResolve_ELF ( ObjectCode* oc ) const Elf_Word shnum = elf_shnum(ehdr); #if defined(SHN_XINDEX) - Elf_Word* shndxTable = get_shndx_table(ehdr); + Elf_Word* shndxTable = get_shndx_table(oc); #endif /* resolve section symbols -- GitLab