mirror of
https://github.com/simplex-chat/simplex-chat.git
synced 2026-11-08 16:37:49 +00:00
150 lines
5.9 KiB
Diff
150 lines
5.9 KiB
Diff
--- a/linker/Elf.c
|
|
+++ b/linker/Elf.c
|
|
@@ -796,6 +796,101 @@
|
|
}
|
|
#endif
|
|
-
|
|
+
|
|
+/* A zero st_size means unknown size, as used by GCC's i386 PIC thunks.
|
|
+ * Only local labels and section metadata may accompany that signature.
|
|
+ */
|
|
+static bool
|
|
+isOnlyFunctionDefinition_ELF(ObjectCode *oc, const Elf_Sym *function)
|
|
+{
|
|
+ for (ElfSymbolTable *table = oc->info->symbolTables;
|
|
+ table != NULL; table = table->next) {
|
|
+ for (size_t i = 0; i < table->n_symbols; i++) {
|
|
+ const Elf_Sym *other = table->symbols[i].elf_sym;
|
|
+ if (other == function || other->st_shndx != function->st_shndx) {
|
|
+ continue;
|
|
+ }
|
|
+ if (ELF_ST_BIND(other->st_info) != STB_LOCAL
|
|
+ || (ELF_ST_TYPE(other->st_info) != STT_NOTYPE
|
|
+ && ELF_ST_TYPE(other->st_info) != STT_SECTION)) {
|
|
+ return false;
|
|
+ }
|
|
+ }
|
|
+ }
|
|
+ return true;
|
|
+}
|
|
+
|
|
+/* Recognize only a COMDAT group containing one hidden function section.
|
|
+ * GCC's i386 PIC thunks use this form with a GLOBAL, not WEAK, signature.
|
|
+ * This is deliberately not general multi-section COMDAT selection: retaining
|
|
+ * duplicate initializer, TLS, data, or partial-function sections is unsafe.
|
|
+ */
|
|
+static bool
|
|
+isSingleFunctionComdat_ELF(ObjectCode *oc, const SymbolName *name)
|
|
+{
|
|
+ if (oc == NULL || oc->type != STATIC_OBJECT || oc->info == NULL
|
|
+ || oc->info->elfHeader == NULL || oc->image == NULL
|
|
+ || oc->fileSize <= 0) {
|
|
+ return false;
|
|
+ }
|
|
+
|
|
+ const Elf_Shdr *shdr = oc->info->sectionHeader;
|
|
+ const Elf_Word shnum = elf_shnum(oc->info->elfHeader);
|
|
+ const size_t imageSize = (size_t)oc->fileSize;
|
|
+ for (Elf_Word i = 0; i < shnum; i++) {
|
|
+ const Elf_Shdr *group = &shdr[i];
|
|
+ if (group->sh_type != SHT_GROUP
|
|
+ || group->sh_size != 2 * sizeof(Elf_Word)
|
|
+ || group->sh_offset > imageSize
|
|
+ || group->sh_size > imageSize - group->sh_offset) {
|
|
+ continue;
|
|
+ }
|
|
+ Elf_Word entries[2];
|
|
+ memcpy(entries, oc->image + group->sh_offset, sizeof(entries));
|
|
+ if (entries[0] != GRP_COMDAT || entries[1] == SHN_UNDEF
|
|
+ || entries[1] >= shnum) {
|
|
+ continue;
|
|
+ }
|
|
+ const Elf_Shdr *member = &shdr[entries[1]];
|
|
+ const Elf_Word required = SHF_ALLOC | SHF_EXECINSTR | SHF_GROUP;
|
|
+ if (member->sh_type != SHT_PROGBITS || member->sh_size == 0
|
|
+ || (member->sh_flags & required) != required
|
|
+ || (member->sh_flags & (SHF_WRITE | SHF_TLS)) != 0) {
|
|
+ continue;
|
|
+ }
|
|
+ for (ElfSymbolTable *table = oc->info->symbolTables;
|
|
+ table != NULL; table = table->next) {
|
|
+ if (table->index != group->sh_link
|
|
+ || group->sh_info >= table->n_symbols) {
|
|
+ continue;
|
|
+ }
|
|
+ const ElfSymbol *signature = &table->symbols[group->sh_info];
|
|
+ const Elf_Sym *symbol = signature->elf_sym;
|
|
+ if (signature->name != NULL && strcmp(signature->name, name) == 0
|
|
+ && ELF_ST_BIND(symbol->st_info) == STB_GLOBAL
|
|
+ && ELF_ST_TYPE(symbol->st_info) == STT_FUNC
|
|
+ && ELF_ST_VISIBILITY(symbol->st_other) == STV_HIDDEN
|
|
+ && symbol->st_shndx < SHN_LORESERVE
|
|
+ && symbol->st_shndx == entries[1]
|
|
+ && symbol->st_value == 0
|
|
+ && (symbol->st_size == member->sh_size
|
|
+ || (symbol->st_size == 0
|
|
+ && isOnlyFunctionDefinition_ELF(oc, symbol)))) {
|
|
+ return true;
|
|
+ }
|
|
+ }
|
|
+ }
|
|
+ return false;
|
|
+}
|
|
+
|
|
+bool
|
|
+ocIsComdatDuplicate_ELF(ObjectCode *oc, const SymbolName *name)
|
|
+{
|
|
+ RtsSymbolInfo *existing = lookupStrHashTable(symhash, name);
|
|
+ return existing != NULL && existing->owner != oc
|
|
+ && isSingleFunctionComdat_ELF(oc, name)
|
|
+ && isSingleFunctionComdat_ELF(existing->owner, name);
|
|
+}
|
|
+
|
|
int
|
|
ocGetNames_ELF ( ObjectCode* oc )
|
|
{
|
|
@@ -1234,7 +1329,9 @@
|
|
setWeakSymbol(oc, nm);
|
|
}
|
|
if (!ghciInsertSymbolTable(oc->fileName, symhash,
|
|
- nm, symbol->addr, isWeak, sym_type, symbol->elf_sym->st_size, oc)
|
|
+ nm, symbol->addr,
|
|
+ isWeak || ocIsComdatDuplicate_ELF(oc, nm),
|
|
+ sym_type, symbol->elf_sym->st_size, oc)
|
|
) {
|
|
goto fail;
|
|
}
|
|
--- a/linker/Elf.h
|
|
+++ b/linker/Elf.h
|
|
@@ -10,6 +10,7 @@
|
|
void ocDeinit_ELF ( ObjectCode* oc );
|
|
int ocVerifyImage_ELF ( ObjectCode* oc );
|
|
int ocGetNames_ELF ( ObjectCode* oc );
|
|
+bool ocIsComdatDuplicate_ELF(ObjectCode *oc, const SymbolName *name);
|
|
int ocResolve_ELF ( ObjectCode* oc );
|
|
int ocRunInit_ELF ( ObjectCode* oc );
|
|
int ocRunFini_ELF ( ObjectCode* oc );
|
|
--- a/Linker.c
|
|
+++ b/Linker.c
|
|
@@ -1645,10 +1645,19 @@
|
|
Symbol_t symbol;
|
|
for (x = 0; x < oc->n_symbols; x++) {
|
|
symbol = oc->symbols[x];
|
|
+ bool isWeak = isSymbolWeak(oc, symbol.name);
|
|
+#if defined(OBJFORMAT_ELF)
|
|
+ /* Archive discovery can change the selected owner. Recheck COMDAT
|
|
+ * eligibility now; never persist conditional acceptance as weakness.
|
|
+ */
|
|
+ if (symbol.name != NULL && !isWeak) {
|
|
+ isWeak = ocIsComdatDuplicate_ELF(oc, symbol.name);
|
|
+ }
|
|
+#endif
|
|
if ( symbol.name
|
|
&& !ghciInsertSymbolTable(oc->fileName, symhash, symbol.name,
|
|
symbol.addr,
|
|
- isSymbolWeak(oc, symbol.name),
|
|
+ isWeak,
|
|
symbol.type, 0, oc)) {
|
|
return 0;
|
|
}
|