From: Robert Pengelly Date: Sat, 3 May 2025 07:03:13 +0000 (+0100) Subject: Bug fixes X-Git-Url: https://git.candlhat.org/?a=commitdiff_plain;h=c782bead89dfc9b7a51ecc5f7fc9391a0803dd7b;p=slink.git Bug fixes --- diff --git a/coff.c b/coff.c index c4cbff0..89aa544 100644 --- a/coff.c +++ b/coff.c @@ -70,6 +70,12 @@ static void translate_relocation (struct reloc_entry *reloc, struct coff_relocat reloc->howto = &reloc_howtos[RELOC_TYPE_PC32]; break; + + default: + + /* There is no point in continuing, the object is broken. */ + report_at (program_name, 0, REPORT_FATAL_ERROR, "invalid relocation type 0x%04hx (origin object '%s')", array_to_integer (input->Type, 2), part->of->filename); + exit (EXIT_FAILURE); } @@ -187,6 +193,7 @@ static unsigned long translate_Characteristics_to_section_flags (unsigned long C #define IMAGE_SYM_DEBUG -2 #define IMAGE_SYM_UNDEFINED 0 +#define IMAGE_SYM_ABSOLUTE 1 #define IMAGE_SYM_CLASS_EXTERNAL 2 void read_coff_object (const char *filename, unsigned char *data, unsigned long data_size) { @@ -210,7 +217,9 @@ void read_coff_object (const char *filename, unsigned char *data, unsigned long unsigned long i; struct section_part *bss_part = 0; - long bss_section_number; + struct section *bss_section = 0; + + long bss_section_number = 0; if ((pos - data + sizeof (*coff_hdr) > data_size) || pos < data) { @@ -240,15 +249,7 @@ void read_coff_object (const char *filename, unsigned char *data, unsigned long for (i = 0; i < no_sections; i++) { - section_hdr = (struct coff_section_table_entry *) ((unsigned char *) data + sizeof (struct coff_header) + sizeof (struct coff_section_table_entry) * i); - - if ((array_to_integer (section_hdr->Characteristics, 4) & IMAGE_SCN_LNK_REMOVE)) { - - part_p_array[i + 1] = 0; - continue; - - } - + section_hdr = (struct coff_section_table_entry *) (pos = (unsigned char *) data + sizeof (struct coff_header) + sizeof (struct coff_section_table_entry) * i); section_name = xstrndup (section_hdr->Name, 8); if (section_name[0] == '/') { @@ -270,6 +271,15 @@ void read_coff_object (const char *filename, unsigned char *data, unsigned long *p++ = '\0'; } + if (array_to_integer (section_hdr->Characteristics, 4) & IMAGE_SCN_LNK_REMOVE) { + + part_p_array[i + 1] = 0; + + free (section_name); + continue; + + } + section = section_find_or_make (section_name); section->flags = translate_Characteristics_to_section_flags (array_to_integer (section_hdr->Characteristics, 4)); @@ -277,7 +287,12 @@ void read_coff_object (const char *filename, unsigned char *data, unsigned long section->is_bss = 1; } - subsection = (p ? subsection_find_or_make (section, p) : 0); + if (p) { + subsection = subsection_find_or_make (section, p); + } else { + subsection = 0; + } + free (section_name); part = section_part_new (section, of); @@ -293,6 +308,13 @@ void read_coff_object (const char *filename, unsigned char *data, unsigned long } + if (section->is_bss) { + + bss_section_number = i + 1; + bss_section = section; + + } + if (array_to_integer (section_hdr->PointerToRelocations, 4) && array_to_integer (section_hdr->NumberOfRelocations, 2)) { unsigned long j, no_relocs; @@ -337,7 +359,7 @@ void read_coff_object (const char *filename, unsigned char *data, unsigned long struct symbol_table_entry *coff_symbol; struct symbol *symbol = of->symbol_arr + i; - int section_no, no_sections; + short section_no, no_sections; coff_symbol = (struct symbol_table_entry *) ((unsigned char *) data + array_to_integer (coff_hdr->PointerToSymbolTable, 4) + sizeof (struct symbol_table_entry) * i); if (memcmp (coff_symbol->Name, "\0\0\0\0", 4) == 0) { @@ -357,37 +379,52 @@ void read_coff_object (const char *filename, unsigned char *data, unsigned long symbol->name = xstrndup ((char *) coff_symbol->Name, 8); } + section_no = array_to_integer (coff_symbol->SectionNumber, 2); + symbol->value = array_to_integer (coff_symbol->value, 4); - symbol->section_number = array_to_integer (coff_symbol->SectionNumber, 2); + symbol->size = 0; + symbol->section_number = section_no; - section_no = array_to_integer (coff_symbol->SectionNumber, 2); no_sections = array_to_integer (coff_hdr->NumberOfSections, 2); - if (symbol->section_number == IMAGE_SYM_UNDEFINED) { + if (section_no == IMAGE_SYM_UNDEFINED) { if (symbol->value) { - if (!bss_part) { + struct symbol *old_symbol = symbol_find (symbol->name); + + if (!old_symbol || symbol_is_undefined (old_symbol)) { - struct section *section = section_find_or_make (".bss"); + if (bss_section) { - section->flags = translate_Characteristics_to_section_flags (IMAGE_SCN_CNT_UNINITIALIZED_DATA | IMAGE_SCN_MEM_READ | IMAGE_SCN_MEM_WRITE); - section->is_bss = 1; + bss_section = section_find_or_make (".bss"); + + bss_section->flags = translate_Characteristics_to_section_flags (IMAGE_SCN_CNT_UNINITIALIZED_DATA | IMAGE_SCN_MEM_READ | IMAGE_SCN_MEM_WRITE); + bss_section->is_bss = 1; + + bss_section_number = array_to_integer (coff_hdr->NumberOfSections, 2) ? array_to_integer (coff_hdr->NumberOfSections, 2) : 1; - bss_section_number = array_to_integer (coff_hdr->NumberOfSections, 2) ? array_to_integer (coff_hdr->NumberOfSections, 2) : 1; + } - bss_part = section_part_new (section, of); - bss_part->content_size = 0; + bss_part = section_part_new (bss_section, of); + section_append_section_part (bss_section, bss_part); - section_append_section_part (section, bss_part); + bss_part->content_size = symbol->size - symbol->value; + + symbol->part = bss_part; + symbol->value = 0; + symbol->section_number = bss_section_number; - } + } else { - bss_part->content_size += symbol->value; - symbol->part = bss_part; + if (symbol->value > old_symbol->size) { + old_symbol->part->content_size = old_symbol->size = symbol->value; + } + + symbol->value = 0; + symbol->part = 0; - symbol->value = bss_part->content_size - symbol->value; - symbol->section_number = bss_section_number; + } } else { symbol->part = 0; @@ -395,8 +432,11 @@ void read_coff_object (const char *filename, unsigned char *data, unsigned long } else if (section_no > 0 && section_no <= no_sections) { symbol->part = part_p_array[section_no]; - } else if (section_no == IMAGE_SYM_UNDEFINED || section_no == IMAGE_SYM_DEBUG) { + } else if (section_no == IMAGE_SYM_ABSOLUTE || section_no == IMAGE_SYM_DEBUG) { + + symbol->section_number = section_no; symbol->part = 0; + } else if (section_no > no_sections) { report_at (program_name, 0, REPORT_ERROR, "%s: invalid symbol SectionNumber: %hi", filename, section_no); @@ -409,22 +449,24 @@ void read_coff_object (const char *filename, unsigned char *data, unsigned long } - symbol->section_number = section_no; - - if (coff_symbol->StorageClass == IMAGE_SYM_CLASS_EXTERNAL) { + if (coff_symbol->StorageClass == IMAGE_SYM_CLASS_EXTERNAL || section_no == IMAGE_SYM_UNDEFINED) { symbol_record_external_symbol (symbol); } if (coff_symbol->NumberOfAuxSymbols) { - for (i++; coff_symbol->NumberOfAuxSymbols; coff_symbol->NumberOfAuxSymbols--) { + unsigned long j; - symbol = of->symbol_arr + i; + for (j = 0; j < coff_symbol->NumberOfAuxSymbols; j++) { + + symbol = of->symbol_arr + i + 1 + j; memset (symbol, 0, sizeof (*symbol)); symbol->auxiliary = 1; } + + i += coff_symbol->NumberOfAuxSymbols; } diff --git a/ld.c b/ld.c index c678120..3204900 100644 --- a/ld.c +++ b/ld.c @@ -95,15 +95,62 @@ struct offset_name_table { #define ALREADY_READ "Already read" +static void read_archive_memeber (unsigned char *pos, const char *filename) { + + struct ar_header *hdr = (struct ar_header *) pos; + + char *temp, *name; + unsigned long data_size; + + if (memcmp (pos, ALREADY_READ, sizeof (ALREADY_READ)) == 0) { + return; + } + + hdr = (struct ar_header *) pos; + + temp = xstrndup (hdr->name, sizeof (hdr->name)); + strip_trailing_spaces (temp); + + if (temp) { + + unsigned long member_name_len = strlen (temp); + + if (member_name_len && temp[member_name_len - 1] == '/' && temp[0] != '/') { + temp[member_name_len - 1] = '\0'; + } + + } + + name = xmalloc (strlen (filename) + 1 + strlen (temp) + 1 + 1); + sprintf (name, "%s(%s)", filename, temp); + + free (temp); + + temp = xstrndup (hdr->size, sizeof (hdr->size)); + strip_trailing_spaces (temp); + + data_size = strtoul (temp, NULL, 10); + free (temp); + + read_object_file (name, pos + sizeof (*hdr), data_size); + free (name); + + memcpy (pos, ALREADY_READ, sizeof (ALREADY_READ)); + +} + static void read_archive (const char *filename, unsigned char *data) { unsigned char *pos = data + 8; - struct ar_header *hdr = (struct ar_header *) pos; + struct ar_header *hdr = (struct ar_header *) pos; struct offset_name_table *offset_name_table; - char *name, *temp, *string_table_pos; - unsigned long no_symbols, data_size, i; + char *string_table_pos, *name; + unsigned long no_symbols, i; + + unsigned long start_header_object_offset = 0; + unsigned long end_header_object_offset = 0; name = xstrndup (hdr->name, sizeof (hdr->name)); strip_trailing_spaces (name); @@ -129,11 +176,25 @@ static void read_archive (const char *filename, unsigned char *data) { for (i = 0; i < no_symbols; i++) { offset_name_table[i].offset = byte_array_to_integer (pos, 4, 1); - pos += 4; - offset_name_table[i].name = (char *) string_table_pos; + string_table_pos += strlen (offset_name_table[i].name) + 1; + pos += 4; + + } + + for (i = 0; i < no_symbols && (!start_header_object_offset || !end_header_object_offset); i++) { + if (strncmp (offset_name_table[i].name, "__head_", 7) == 0) { + start_header_object_offset = offset_name_table[i].offset; + } else if (strlen (offset_name_table[i].name) > 6 && strcmp (offset_name_table[i].name + strlen (offset_name_table[i].name) - 6, "_iname") == 0) { + end_header_object_offset = offset_name_table[i].offset; + } + + } + + if (start_header_object_offset) { + read_archive_memeber (data + start_header_object_offset, filename); } while (1) { @@ -147,42 +208,11 @@ static void read_archive (const char *filename, unsigned char *data) { continue; } - pos = data + offset_name_table[i].offset; - - if (memcmp (pos, ALREADY_READ, sizeof (ALREADY_READ)) == 0) { + if (offset_name_table[i].offset == start_header_object_offset || offset_name_table[i].offset == end_header_object_offset) { continue; } - hdr = (struct ar_header *) pos; - - temp = xstrndup (hdr->name, sizeof (hdr->name)); - strip_trailing_spaces (temp); - - if (temp) { - - unsigned long member_name_len = strlen (temp); - - if (member_name_len && temp[member_name_len - 1] == '/' && temp[0] != '/') { - temp[member_name_len - 1] = '\0'; - } - - } - - name = xmalloc (strlen (filename) + 1 + strlen (temp) + 1 + 1); - sprintf (name, "%s(%s)", filename, temp); - - free (temp); - - temp = xstrndup (hdr->size, sizeof (hdr->size)); - strip_trailing_spaces (temp); - - data_size = strtoul (temp, NULL, 10); - free (temp); - - read_object_file (name, pos + sizeof (*hdr), data_size); - free (name); - - memcpy (pos, ALREADY_READ, sizeof (ALREADY_READ)); + read_archive_memeber (data + offset_name_table[i].offset, filename); change = 1; } @@ -193,6 +223,10 @@ static void read_archive (const char *filename, unsigned char *data) { } + if (end_header_object_offset) { + read_archive_memeber (data + end_header_object_offset, filename); + } + free (offset_name_table); } @@ -275,8 +309,6 @@ int main (int argc, char **argv) { } - sections_destroy_empty_before_collapse (); - if (state->format == LD_FORMAT_I386_COFF) { coff_before_link (); } else if (state->format == LD_FORMAT_I386_PE) { diff --git a/link.c b/link.c index 7958454..3c4dc83 100644 --- a/link.c +++ b/link.c @@ -16,19 +16,19 @@ struct reloc_howto reloc_howtos[RELOC_TYPE_END] = { - { 0, 0, 0, 0, 0, "RELOC_TYPE_IGNORED", 0, 0 }, + { 0, 0, 0, 0, 0, "RELOC_TYPE_IGNORED", 0, 0 }, - { 8, 0, 0, 0, 0, "RELOC_TYPE_64", 0, 0 }, - { 8, 1, 0, 0, 0, "RELOC_TYPE_PC64", 0, 0 }, + { 8, 0, 0, 0, 0, "RELOC_TYPE_64", 0, 0 }, + { 4, 0, 0, 0, 0, "RELOC_TYPE_32", 0, 0 }, + { 2, 0, 0, 0, 0, "RELOC_TYPE_16", 0, 0 }, + { 1, 0, 0, 0, 0, "RELOC_TYPE_8", 0, 0 }, - { 4, 0, 0, 0, 0, "RELOC_TYPE_32", 0, 0 }, - { 4, 1, 0, 0, 0, "RELOC_TYPE_PC32", 0, 0 }, + { 8, 1, 0, 0, 0, "RELOC_TYPE_PC64", 0, 0 }, + { 4, 1, 0, 0, 0, "RELOC_TYPE_PC32", 0, 0 }, + { 2, 1, 0, 0, 0, "RELOC_TYPE_PC16", 0, 0 }, + { 1, 1, 0, 0, 0, "RELOC_TYPE_PC8", 0, 0 }, - { 2, 0, 0, 0, 0, "RELOC_TYPE_16", 0, 0 }, - { 2, 1, 0, 0, 0, "RELOC_TYPE_PC16", 0, 0 }, - - { 1, 0, 0, 0, 0, "RELOC_TYPE_8", 0, 0 }, - { 1, 1, 0, 0, 0, "RELOC_TYPE_PC8", 0, 0 } + { 4, 0, 1, 0, 0, "RELOC_TYPE_32_NO_BASE", 0, 0 } }; diff --git a/pe.c b/pe.c index 0efc358..59c8740 100644 --- a/pe.c +++ b/pe.c @@ -664,27 +664,19 @@ void pe_before_link (void) { part = section_part_new (section, object_file_make (FAKE_LD_FILENAME, 0)); - part->content_size = sizeof (struct pe_import_directory_table); - part->content = xmalloc (part->content_size); - + part->content = xmalloc (part->content_size = sizeof (struct pe_import_directory_table)); subsection_append_section_part (subsection, part); if (!(subsection = subsection_find (section, "5"))) { return; } - iat_first_part = subsection->first_part; - - if (!iat_first_part) { + if (!(iat_first_part = subsection->first_part)) { return; } - for (part = iat_first_part; ; part = part->next) { - - if (!part->next) { - break; - } - + for (part = iat_first_part; part->next; part = part->next) { + ; } iat_last_part = part; @@ -904,10 +896,10 @@ void pe_write (const char *filename) { case 12: /* IMPORT Address Table. */ - if ((section = section_find (".idata"))) { + if ((section = section_find (".idata")) && iat_first_part) { write741_to_byte_array (idd->VirtualAddress, iat_first_part->rva); - write741_to_byte_array (idd->Size, iat_first_part->rva + iat_last_part->content_size); + write741_to_byte_array (idd->Size, iat_last_part->rva + iat_last_part->content_size - iat_first_part->rva); } diff --git a/reloc.h b/reloc.h index f5e6462..5385dc3 100644 --- a/reloc.h +++ b/reloc.h @@ -9,15 +9,13 @@ enum { RELOC_TYPE_IGNORED, RELOC_TYPE_64, - RELOC_TYPE_PC64, - RELOC_TYPE_32, - RELOC_TYPE_PC32, - RELOC_TYPE_16, - RELOC_TYPE_PC16, - RELOC_TYPE_8, + + RELOC_TYPE_PC64, + RELOC_TYPE_PC32, + RELOC_TYPE_PC16, RELOC_TYPE_PC8, RELOC_TYPE_32_NO_BASE, diff --git a/section.c b/section.c index 2c9dcbf..2c986d9 100644 --- a/section.c +++ b/section.c @@ -14,14 +14,13 @@ static struct section **last_section_p = &all_sections; static struct section *discarded_sections = 0; -struct object_file *object_file_make (const char *filename, unsigned long symbol_cnt) { +struct object_file *object_file_make (const char *filename, unsigned long symbol_count) { struct object_file *of = xmalloc (sizeof (*of)); - of->filename = xstrdup (filename); - of->symbol_arr = symbol_cnt ? xmalloc (sizeof (*of->symbol_arr) * symbol_cnt) : 0; - of->symbol_cnt = symbol_cnt; + of->symbol_arr = symbol_count ? xmalloc (sizeof (*of->symbol_arr) * symbol_count) : 0; + of->symbol_cnt = symbol_count; *last_object_file_p = of; last_object_file_p = &of->next; @@ -89,8 +88,8 @@ void section_append_section_part (struct section *section, struct section_part * void sections_destroy_empty_before_collapse (void) { struct section *section, **next_p; - struct section_part *part; + struct subsection *subsection; for (next_p = &all_sections, section = *next_p; section; section = *next_p) { @@ -140,12 +139,8 @@ void section_write (struct section *section, unsigned char *memory) { for (part = section->first_part; part; part = part->next) { - if (part->content_size > 0) { - - memcpy (memory, part->content, part->content_size); - memory += part->content_size; - - } + memcpy (memory, part->content, part->content_size); + memory += part->content_size; } @@ -197,9 +192,9 @@ struct subsection *subsection_find_or_make (struct section *section, const char subsection = xmalloc (sizeof (*subsection)); subsection->name = xstrdup (name); - subsection->next = *next_p; subsection->last_part_p = &subsection->first_part; + subsection->next = *next_p; *next_p = subsection; }