From: Robert Pengelly Date: Wed, 30 Apr 2025 21:30:28 +0000 (+0100) Subject: Added COFF object support and bug fixes X-Git-Url: https://git.candlhat.org/?a=commitdiff_plain;h=2a895b06b458f6ba7f5b144e1174f74162f9c028;p=slink.git Added COFF object support and bug fixes --- diff --git a/coff.c b/coff.c index daae198..c4cbff0 100644 --- a/coff.c +++ b/coff.c @@ -17,6 +17,424 @@ #include "section.h" #include "write7x.h" +struct string_table_header { + unsigned char StringTableSize[4]; +}; + +struct symbol_table_entry { + + unsigned char Name[8]; + unsigned char value[4]; + + unsigned char SectionNumber[2]; + unsigned char Type[2]; + + unsigned char StorageClass; + unsigned char NumberOfAuxSymbols; + +}; + +static void translate_relocation (struct reloc_entry *reloc, struct coff_relocation_entry *input, struct section_part *part) { + + reloc->symbol = part->of->symbol_arr + array_to_integer (input->SymbolTableIndex, 4); + reloc->offset = array_to_integer (input->VirtualAddress, 4); + + switch (array_to_integer (input->Type, 2)) { + + case IMAGE_REL_I386_ABSOLUTE: + + reloc->howto = &reloc_howtos[RELOC_TYPE_IGNORED]; + break; + + case IMAGE_REL_I386_DIR16: + + reloc->howto = &reloc_howtos[RELOC_TYPE_16]; + break; + + case IMAGE_REL_I386_DIR32: + + reloc->howto = &reloc_howtos[RELOC_TYPE_32]; + break; + + case IMAGE_REL_I386_DIR32NB: + + reloc->howto = &reloc_howtos[RELOC_TYPE_32_NO_BASE]; + break; + + case IMAGE_REL_I386_REL16: + + reloc->howto = &reloc_howtos[RELOC_TYPE_PC16]; + break; + + case IMAGE_REL_I386_REL32: + + reloc->howto = &reloc_howtos[RELOC_TYPE_PC32]; + break; + + } + +} + +static unsigned long translate_Characteristics_to_alignment (unsigned long Characteristics) { + + unsigned long alignment = 1; + Characteristics &= IMAGE_SCN_ALIGN_8192BYTES; + + if (Characteristics == IMAGE_SCN_ALIGN_1BYTES) { + alignment = 1; + } + + if (Characteristics == IMAGE_SCN_ALIGN_2BYTES) { + alignment = 2; + } + + if (Characteristics == IMAGE_SCN_ALIGN_4BYTES) { + alignment = 4; + } + + if (Characteristics == IMAGE_SCN_ALIGN_8BYTES) { + alignment = 8; + } + + if (Characteristics == IMAGE_SCN_ALIGN_16BYTES) { + alignment = 16; + } + + if (Characteristics == IMAGE_SCN_ALIGN_32BYTES) { + alignment = 32; + } + + if (Characteristics == IMAGE_SCN_ALIGN_64BYTES) { + alignment = 64; + } + + if (Characteristics == IMAGE_SCN_ALIGN_128BYTES) { + alignment = 128; + } + + if (Characteristics == IMAGE_SCN_ALIGN_256BYTES) { + alignment = 256; + } + + if (Characteristics == IMAGE_SCN_ALIGN_512BYTES) { + alignment = 512; + } + + if (Characteristics == IMAGE_SCN_ALIGN_1024BYTES) { + alignment = 1024; + } + + if (Characteristics == IMAGE_SCN_ALIGN_2048BYTES) { + alignment = 2048; + } + + if (Characteristics == IMAGE_SCN_ALIGN_4096BYTES) { + alignment = 4096; + } + + if (Characteristics == IMAGE_SCN_ALIGN_8192BYTES) { + alignment = 8192; + } + + return alignment; + +} + +static unsigned long translate_Characteristics_to_section_flags (unsigned long Characteristics) { + + unsigned long flags = 0; + + if (!(Characteristics & IMAGE_SCN_MEM_WRITE)) { + flags |= SECTION_FLAG_READONLY; + } + + if (Characteristics & (IMAGE_SCN_CNT_CODE | IMAGE_SCN_MEM_EXECUTE)) { + flags |= SECTION_FLAG_CODE; + } + + if (Characteristics & IMAGE_SCN_CNT_INITIALIZED_DATA) { + flags |= SECTION_FLAG_DATA; + } + + if (Characteristics & IMAGE_SCN_TYPE_NOLOAD) { + flags |= SECTION_FLAG_NEVER_LOAD; + } + + if (Characteristics & IMAGE_SCN_LNK_INFO) { + flags |= SECTION_FLAG_DEBUGGING; + } + + if (Characteristics & IMAGE_SCN_LNK_REMOVE) { + flags |= SECTION_FLAG_EXCLUDE; + } + + if (!(Characteristics & IMAGE_SCN_MEM_READ)) { + flags |= SECTION_FLAG_NOREAD; + } + + if (Characteristics & IMAGE_SCN_MEM_SHARED) { + flags |= SECTION_FLAG_SHARED; + } + + if (Characteristics & IMAGE_SCN_CNT_UNINITIALIZED_DATA) { + flags |= SECTION_FLAG_ALLOC; + } + + return flags; + +} + +#define IMAGE_SYM_DEBUG -2 + +#define IMAGE_SYM_UNDEFINED 0 +#define IMAGE_SYM_CLASS_EXTERNAL 2 + +void read_coff_object (const char *filename, unsigned char *data, unsigned long data_size) { + + struct coff_header *coff_hdr; + struct coff_relocation_entry *reloc_info; + + struct coff_section_table_entry *section_hdr; + struct string_table_header *string_table_hdr; + + struct section_part **part_p_array, *part; + struct object_file *of; + + struct section *section; + struct subsection *subsection; + + char *string_table = 0, *section_name, *p; + unsigned long string_table_size, no_sections, no_syms; + + unsigned char *pos = (unsigned char *) data; + unsigned long i; + + struct section_part *bss_part = 0; + long bss_section_number; + + if ((pos - data + sizeof (*coff_hdr) > data_size) || pos < data) { + + report_at (program_name, 0, REPORT_FATAL_ERROR, "%s: corrupted input file", filename); + return; + + } + + coff_hdr = (struct coff_header *) data; + + pos = (unsigned char *) data + array_to_integer (coff_hdr->PointerToSymbolTable, 4) + sizeof (struct symbol_table_entry) * array_to_integer (coff_hdr->NumberOfSymbols, 4); + string_table_hdr = (struct string_table_header *) pos; + + if ((string_table_size = array_to_integer (string_table_hdr->StringTableSize, 4)) < 4) { + + report_at (program_name, 0, REPORT_ERROR, "%s: invalid string table size: %lu", filename, string_table_size); + return; + + } + + string_table = (char *) pos; + + part_p_array = xmalloc (sizeof (*part_p_array) * (array_to_integer (coff_hdr->NumberOfSections, 2) + 1)); + of = object_file_make (filename, array_to_integer (coff_hdr->NumberOfSymbols, 4)); + + no_sections = array_to_integer (coff_hdr->NumberOfSections, 2); + + 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_name = xstrndup (section_hdr->Name, 8); + + if (section_name[0] == '/') { + + unsigned long offset = strtoul (section_name + 1, NULL, 10); + + if (offset < array_to_integer (string_table_hdr->StringTableSize, 4)) { + + free (section_name); + section_name = xstrdup (string_table + offset); + + } else { + report_at (program_name, 0, REPORT_ERROR, "%s: invalid offset into string table", filename); + } + + } + + if ((p = strchr (section_name, '$'))) { + *p++ = '\0'; + } + + section = section_find_or_make (section_name); + section->flags = translate_Characteristics_to_section_flags (array_to_integer (section_hdr->Characteristics, 4)); + + if (array_to_integer (section_hdr->PointerToRawData, 4) == 0 && array_to_integer (section_hdr->SizeOfRawData, 4)) { + section->is_bss = 1; + } + + subsection = (p ? subsection_find_or_make (section, p) : 0); + free (section_name); + + part = section_part_new (section, of); + part->alignment = translate_Characteristics_to_alignment (array_to_integer (section_hdr->Characteristics, 4)); + part->content_size = array_to_integer (section_hdr->SizeOfRawData, 4); + + if (array_to_integer (section_hdr->PointerToRawData, 4)) { + + pos = (unsigned char *) data + array_to_integer (section_hdr->PointerToRawData, 4); + + part->content = xmalloc (part->content_size); + memcpy (part->content, pos, part->content_size); + + } + + if (array_to_integer (section_hdr->PointerToRelocations, 4) && array_to_integer (section_hdr->NumberOfRelocations, 2)) { + + unsigned long j, no_relocs; + + if (!array_to_integer (section_hdr->PointerToRawData, 4)) { + + report_at (program_name, 0, REPORT_FATAL_ERROR, "%s: section '%s' is BSS but has relocations", filename, section->name); + exit (EXIT_FAILURE); + + } + + pos = (unsigned char *) data + array_to_integer (section_hdr->PointerToRelocations, 4); + + part->reloc_arr = xmalloc (sizeof (struct reloc_entry) * array_to_integer (section_hdr->NumberOfRelocations, 2)); + part->reloc_cnt = array_to_integer (section_hdr->NumberOfRelocations, 2); + + no_relocs = array_to_integer (section_hdr->NumberOfRelocations, 2); + + for (j = 0; j < no_relocs; j++) { + + reloc_info = (struct coff_relocation_entry *) (pos + (sizeof (*reloc_info) * j)); + translate_relocation (part->reloc_arr + j, reloc_info, part); + + } + + } + + if (subsection) { + subsection_append_section_part (subsection, part); + } else { + section_append_section_part (section, part); + } + + part_p_array[i + 1] = part; + + } + + no_syms = array_to_integer (coff_hdr->NumberOfSymbols, 4); + + for (i = 0; i < no_syms; i++) { + + struct symbol_table_entry *coff_symbol; + struct symbol *symbol = of->symbol_arr + i; + + int 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) { + + unsigned long offset = array_to_integer (coff_symbol->Name + 4, 4); + + if (offset < array_to_integer (string_table_hdr->StringTableSize, 4)) { + symbol->name = xstrdup (string_table + offset); + } else { + + report_at (program_name, 0, REPORT_FATAL_ERROR, "%s: invalid offset into string table", filename); + exit (EXIT_FAILURE); + + } + + } else { + symbol->name = xstrndup ((char *) coff_symbol->Name, 8); + } + + symbol->value = array_to_integer (coff_symbol->value, 4); + symbol->section_number = array_to_integer (coff_symbol->SectionNumber, 2); + + 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 (symbol->value) { + + if (!bss_part) { + + struct section *section = section_find_or_make (".bss"); + + 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_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; + + section_append_section_part (section, bss_part); + + } + + bss_part->content_size += symbol->value; + symbol->part = bss_part; + + symbol->value = bss_part->content_size - symbol->value; + symbol->section_number = bss_section_number; + + } else { + symbol->part = 0; + } + + } 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) { + symbol->part = 0; + } else if (section_no > no_sections) { + + report_at (program_name, 0, REPORT_ERROR, "%s: invalid symbol SectionNumber: %hi", filename, section_no); + symbol->part = 0; + + } else { + + report_at (__FILE__, __LINE__, REPORT_INTERNAL_ERROR, "+++not yet supported symbol SectionNumber: %hi", section_no); + exit (EXIT_FAILURE); + + } + + symbol->section_number = section_no; + + if (coff_symbol->StorageClass == IMAGE_SYM_CLASS_EXTERNAL) { + symbol_record_external_symbol (symbol); + } + + if (coff_symbol->NumberOfAuxSymbols) { + + for (i++; coff_symbol->NumberOfAuxSymbols; coff_symbol->NumberOfAuxSymbols--) { + + symbol = of->symbol_arr + i; + + memset (symbol, 0, sizeof (*symbol)); + symbol->auxiliary = 1; + + } + + } + + } + + free (part_p_array); + +} + + struct exclude_symbol { char *name; diff --git a/coff.h b/coff.h index 1c826ae..8aa5fc0 100644 --- a/coff.h +++ b/coff.h @@ -71,7 +71,20 @@ struct coff_section_table_entry { #define IMAGE_SCN_CNT_UNINITIALIZED_DATA 0x00000080 #define IMAGE_SCN_LNK_INFO 0x00000200 #define IMAGE_SCN_LNK_REMOVE 0x00000800 +#define IMAGE_SCN_ALIGN_1BYTES 0x00100000 +#define IMAGE_SCN_ALIGN_2BYTES 0x00200000 #define IMAGE_SCN_ALIGN_4BYTES 0x00300000 +#define IMAGE_SCN_ALIGN_8BYTES 0x00400000 +#define IMAGE_SCN_ALIGN_16BYTES 0x00500000 +#define IMAGE_SCN_ALIGN_32BYTES 0x00600000 +#define IMAGE_SCN_ALIGN_64BYTES 0x00700000 +#define IMAGE_SCN_ALIGN_128BYTES 0x00800000 +#define IMAGE_SCN_ALIGN_256BYTES 0x00900000 +#define IMAGE_SCN_ALIGN_512BYTES 0x00A00000 +#define IMAGE_SCN_ALIGN_1024BYTES 0x00B00000 +#define IMAGE_SCN_ALIGN_2048BYTES 0x00C00000 +#define IMAGE_SCN_ALIGN_4096BYTES 0x00D00000 +#define IMAGE_SCN_ALIGN_8192BYTES 0x00E00000 #define IMAGE_SCN_MEM_SHARED 0x10000000 #define IMAGE_SCN_MEM_EXECUTE 0x20000000 #define IMAGE_SCN_MEM_READ 0x40000000 @@ -93,6 +106,8 @@ struct coff_relocation_entry { #define IMAGE_REL_I386_DIR32NB 0x0007 #define IMAGE_REL_I386_REL32 0x0014 +void read_coff_object (const char *filename, unsigned char *data, unsigned long data_size); + void coff_after_link (void); void coff_before_link (void); diff --git a/ld.c b/ld.c index 9c3d68e..c678120 100644 --- a/ld.c +++ b/ld.c @@ -69,12 +69,15 @@ static int read_file_into_memory (const char *filename, unsigned char **memory_p static void read_object_file (const char *filename, unsigned char *data, unsigned long data_size) { + /*report_at (program_name, 0, REPORT_ERROR, "%s: signature: %#x:%#x", filename, data[0], data[1]);*/ /*printf ("reading: %s\n", filename);*/ if (data[0] == 0x01 && data[1] == 0x03) { read_elks_object (filename, data, data_size); } else if (data[0] == 0x07 && data[1] == 0x01) { read_aout_object (filename, data, data_size); + } else if (data[0] == 0x4C && data[1] == 0x01) { + read_coff_object (filename, data, data_size); } else if (data[0] == RECORD_TYPE_THEADR) { read_omf_object (filename, data, data_size); } else { @@ -155,6 +158,16 @@ static void read_archive (const char *filename, unsigned char *data) { 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); @@ -262,6 +275,8 @@ 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/omf.c b/omf.c index cb3cdf1..8d89562 100644 --- a/omf.c +++ b/omf.c @@ -16,6 +16,7 @@ static void estimate (void *data, unsigned long data_size, const char *filename, unsigned long *num_segments_p, unsigned long *num_extdefs_p, unsigned long *num_pubdefs_p, unsigned long *num_lnames_p) { unsigned char *pos = (unsigned char *) data; + unsigned char base_segment_index; unsigned char record_type; unsigned short record_len; @@ -80,20 +81,31 @@ static void estimate (void *data, unsigned long data_size, const char *filename, } else if (record_type == RECORD_TYPE_PUBDEF) { - pubdef_name_end = (pubdef_name = pos) + record_len - 3; + unsigned long prefix = 1; + unsigned long suffix = 2 + 1; + + pubdef_name_end = pos + record_len - 1; if (big_fields) { + suffix += 2; + } - report_at (program_name, 0, REPORT_INTERNAL_ERROR, "%s: big fields not supported for record %#x", filename, record_type); - exit (EXIT_FAILURE); + base_segment_index = pos[1]; + + if (!base_segment_index) { + + report_at (program_name, 0, REPORT_WARNING, "%s: PUBDEF Base Frame is not supported", filename); + prefix += 2; } + pubdef_name = pos + 2; + while (pubdef_name != pubdef_name_end) { - pubdef_name_len = pubdef_name[2]; + pubdef_name_len = pubdef_name[prefix - 1]; - if (pubdef_name + 2 + 1 + pubdef_name_len + 1 > pubdef_name_end) { + if (pubdef_name + prefix + pubdef_name_len + suffix > pubdef_name_end) { report_at (program_name, 0, REPORT_FATAL_ERROR, "%s: incorrect pubdef string length", filename); exit (EXIT_FAILURE); @@ -101,7 +113,7 @@ static void estimate (void *data, unsigned long data_size, const char *filename, } num_pubdefs++; - pubdef_name = pubdef_name + 2 + 1 + pubdef_name_len + 1; + pubdef_name = pubdef_name + prefix + pubdef_name_len + suffix; } @@ -249,30 +261,45 @@ void read_omf_object (const char *filename, unsigned char *data, unsigned long d } else if (record_type == RECORD_TYPE_PUBDEF) { - pubdef_name_end = (pubdef_name = pos) + record_len - 3; - base_segment_index = pubdef_name[1]; + unsigned long prefix = 1; + unsigned long suffix = 2 + 1; - while (pubdef_name != pubdef_name_end) { + pubdef_name_end = pos + record_len - 1; - pubdef_name_len = pubdef_name[2]; - - public_offset = array_to_integer (pubdef_name + 3 + pubdef_name_len, 2); - symbol = of->symbol_arr + i_extdefs++; - - if (base_segment_index >= i_segments || !base_segment_index) { + if (big_fields) { + suffix += 2; + } - report_at (program_name, 0, REPORT_FATAL_ERROR, "%s: invalid base segment index %d", filename, base_segment_index); - exit (EXIT_FAILURE); + base_segment_index = pos[1]; + + if (!base_segment_index) { + + report_at (program_name, 0, REPORT_WARNING, "%s: PUBDEF Base Frame is not supported", filename); + prefix += 2; + + } + + pubdef_name = pos + 2; + + while (pubdef_name != pubdef_name_end) { + + pubdef_name_len = pubdef_name[prefix - 1]; + if (big_fields) { + public_offset = array_to_integer (pubdef_name + prefix + pubdef_name_len, 4); + } else { + public_offset = array_to_integer (pubdef_name + prefix + pubdef_name_len, 2); } - symbol->name = xstrndup ((char *) pubdef_name + 3, pubdef_name_len); + symbol = of->symbol_arr + i_pubdefs++; + + symbol->name = xstrndup ((char *) pubdef_name + prefix, pubdef_name_len); symbol->value = public_offset; symbol->part = part_p_array[base_segment_index]; symbol->section_number = base_segment_index; symbol_record_external_symbol (symbol); - pubdef_name = pubdef_name + 2 + 1 + pubdef_name_len + 1; + pubdef_name = pubdef_name + prefix + pubdef_name_len + suffix; } @@ -298,13 +325,6 @@ void read_omf_object (const char *filename, unsigned char *data, unsigned long d unsigned long segment_len; - if (!(attributes & SEGMENT_ATTR_P)) { - - report_at (program_name, 0, REPORT_FATAL_ERROR, "%s: OMF USE16 segments are not supported", filename); - exit (EXIT_FAILURE); - - } - if ((attributes >> 5) == 0) { report_at (program_name, 0, REPORT_FATAL_ERROR, "%s: OMF absolute segments are not supported", filename); @@ -321,19 +341,21 @@ void read_omf_object (const char *filename, unsigned char *data, unsigned long d } else { - report_at (__FILE__, __LINE__, REPORT_INTERNAL_ERROR, "%s: non big fields not supported for record %#x", filename, record_type); - exit (EXIT_FAILURE); + segment_len = array_to_integer (pos + 1, 2); + + segment_name_index = pos[3]; + class_name_index = pos[4]; } - if (segment_name_index >= i_lnames || !segment_name_index) { + if (segment_name_index >= i_lnames || !segment_name_index) { report_at (program_name, 0, REPORT_FATAL_ERROR, "%s: invalid segment name index", filename); exit (EXIT_FAILURE); } - if (class_name_index >= i_lnames || !class_name_index) { + if (class_name_index >= i_lnames || !class_name_index) { report_at (program_name, 0, REPORT_FATAL_ERROR, "%s: invalid class name index", filename); exit (EXIT_FAILURE); @@ -415,13 +437,6 @@ void read_omf_object (const char *filename, unsigned char *data, unsigned long d } - if (!big_fields) { - - report_at (__FILE__, __LINE__, REPORT_INTERNAL_ERROR, "%s: non big field not supported for record %#x", filename, record_type); - exit (EXIT_FAILURE); - - } - while (subrec != end) { if (subrec[0] & 0x80) { @@ -432,16 +447,19 @@ void read_omf_object (const char *filename, unsigned char *data, unsigned long d unsigned char fixdat, frame_method, target_method; unsigned short data_record_offset, target_datum; - if (subrec[0] & 0x40) { - - report_at (__FILE__, __LINE__, REPORT_INTERNAL_ERROR, "%s: only self-relative OMF fixups are supported", filename); - exit (EXIT_FAILURE); + unsigned char loc; + int bits; - } + /*seg_reloc = subrec[0] & 0x40;*/ + loc = subrec[0] >> 2; - if (((subrec[0] >> 2) & 0x0f) != 9) { + if ((loc & 0x0F) == 1) { + bits = 16; + } else if ((loc & 0x0F) == 9) { + bits = 32; + } else { - report_at (__FILE__, __LINE__, REPORT_INTERNAL_ERROR, "%s: only 32-bit offset OMF fixups are supported", filename); + report_at (__FILE__, __LINE__, REPORT_INTERNAL_ERROR, "%s: only 16-bit/32-bit offset OMF fixups are supported", filename); exit (EXIT_FAILURE); } @@ -521,7 +539,12 @@ void read_omf_object (const char *filename, unsigned char *data, unsigned long d reloc->offset = data_record_offset; reloc->addend = 0; - reloc->howto = &reloc_howtos[RELOC_TYPE_PC32]; + + if (bits == 16) { + reloc->howto = &reloc_howtos[RELOC_TYPE_PC16]; + } else { + reloc->howto = &reloc_howtos[RELOC_TYPE_PC32]; + } subrec += 4; @@ -546,12 +569,14 @@ void read_omf_object (const char *filename, unsigned char *data, unsigned long d if (big_fields) { offset = array_to_integer (pos + 1, 4); + size = record_len - 6; data_bytes = pos + 5; } else { offset = array_to_integer (pos + 1, 2); + size = record_len - 4; data_bytes = pos + 3; diff --git a/omf.h b/omf.h index b8bfef3..292f16b 100644 --- a/omf.h +++ b/omf.h @@ -15,10 +15,10 @@ #define RECORD_TYPE_FIXUPP 0x9C #define RECORD_TYPE_LEDATA 0xA0 -#define SEGMENT_ATTR_P 0x1 +#define SEGMENT_ATTR_P 0x01 -#define METHOD_T2_EXTDEF 2 -#define METHOD_F5 5 +#define METHOD_T2_EXTDEF 0x02 +#define METHOD_F5 0x05 void read_omf_object (const char *filename, unsigned char *data, unsigned long data_size); diff --git a/pe.c b/pe.c index 16bbc1a..0efc358 100644 --- a/pe.c +++ b/pe.c @@ -363,6 +363,10 @@ static void generate_base_relocation_block (struct section *reloc_section, struc continue; } + if (part->rva + relocs[i].offset < array_to_integer (ibr_hdr_p->RVAOfBlock, 4)) { + continue; + } + rel_word = (part->rva + relocs[i].offset - array_to_integer (ibr_hdr_p->RVAOfBlock, 4)) & 0xfff; rel_word |= base_relocation_type << 12; @@ -699,6 +703,7 @@ void pe_write (const char *filename) { struct pe_optional_header *opthdr; struct section *section; + unsigned long size_of_optional_header; if (!(fp = fopen (filename, "wb"))) { @@ -721,9 +726,10 @@ void pe_write (const char *filename) { write_sections (data); doshdr = (struct msdos_header *) data; - pehdr = (struct pe_header *) ((char *) doshdr + sizeof (*doshdr) + sizeof (dos_stub)); + pehdr = (struct pe_header *) ((char *) doshdr + sizeof (*doshdr) + sizeof (dos_stub)); opthdr = (struct pe_optional_header *) ((char *) pehdr + sizeof (*pehdr)); + pos = (unsigned char *) opthdr + sizeof (*opthdr); doshdr->e_magic[0] = 'M'; @@ -749,7 +755,10 @@ void pe_write (const char *filename) { write721_to_byte_array (pehdr->Machine, IMAGE_FILE_MACHINE_I386); write721_to_byte_array (pehdr->NumberOfSections, section_count ()); write741_to_byte_array (pehdr->TimeDateStamp, time (0)); - write721_to_byte_array (pehdr->SizeOfOptionalHeader, sizeof (*opthdr)); + + size_of_optional_header = sizeof (*opthdr); + size_of_optional_header += NUMBER_OF_DATA_DIRECTORIES * sizeof (struct pe_image_data_directory); + write721_to_byte_array (pehdr->SizeOfOptionalHeader, size_of_optional_header); { @@ -796,12 +805,24 @@ void pe_write (const char *filename) { if (last_section) { write741_to_byte_array (opthdr->SizeOfImage, ALIGN (last_section->rva + last_section->total_size, section_alignment)); } else { - write741_to_byte_array (opthdr->SizeOfImage, state->size_of_headers); + write741_to_byte_array (opthdr->SizeOfImage, ALIGN (state->size_of_headers, section_alignment)); } write741_to_byte_array (opthdr->SizeOfHeaders, state->size_of_headers); write721_to_byte_array (opthdr->Subsystem, subsystem); + { + + unsigned short characteristics = IMAGE_DLLCHARACTERISTICS_NX_COMPAT; + + if (can_be_relocated) { + characteristics |= IMAGE_DLLCHARACTERISTICS_DYNAMIC_BASE; + } + + write721_to_byte_array (opthdr->DllCharacteristics, characteristics); + + } + { struct section *bss_section; @@ -833,6 +854,74 @@ void pe_write (const char *filename) { write741_to_byte_array (opthdr->NumberOfRvaAndSizes, NUMBER_OF_DATA_DIRECTORIES); + { + + struct pe_image_data_directory *idd; + int i; + + for (i = 0; i < NUMBER_OF_DATA_DIRECTORIES; i++) { + + idd = (struct pe_image_data_directory *) pos; + + switch (i) { + + case 0: + + /* EXPORT Table. */ + if ((section = section_find (".edata"))) { + + write741_to_byte_array (idd->VirtualAddress, section->rva); + write741_to_byte_array (idd->Size, section->total_size); + + } + + break; + + case 1: + + /* IMPORT Table. */ + if ((section = section_find (".idata"))) { + + write741_to_byte_array (idd->VirtualAddress, section->rva); + write741_to_byte_array (idd->Size, section->total_size); + + } + + break; + + case 5: + + /* BASE RELOCATION Table. */ + if ((section = section_find (".reloc"))) { + + write741_to_byte_array (idd->VirtualAddress, section->rva); + write741_to_byte_array (idd->Size, section->total_size); + + } + + break; + + case 12: + + /* IMPORT Address Table. */ + if ((section = section_find (".idata"))) { + + 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); + + } + + break; + + } + + pos += sizeof (*idd); + + } + + } + + for (section = all_sections; section; section = section->next) { struct pe_section_table_entry *hdr = section->object_dependent_data; diff --git a/pe.h b/pe.h index f209942..758acdb 100644 --- a/pe.h +++ b/pe.h @@ -44,6 +44,9 @@ struct msdos_header { #define IMAGE_SUBSYSTEM_XBOX 14 #define IMAGE_SUBSYSTEM_WINDOWS_BOOT_APPILCATION 16 +#define IMAGE_DLLCHARACTERISTICS_DYNAMIC_BASE 0x0040 +#define IMAGE_DLLCHARACTERISTICS_NX_COMPAT 0x0100 + struct pe_header { unsigned char Signature[4]; @@ -112,10 +115,6 @@ struct pe_optional_header { unsigned char LoaderFlags[4]; unsigned char NumberOfRvaAndSizes[4]; - - - /*unsigned char Reserved[128];*/ - unsigned char Reserved[32 * 4]; }; diff --git a/reloc.h b/reloc.h index a4bb555..f5e6462 100644 --- a/reloc.h +++ b/reloc.h @@ -20,6 +20,7 @@ enum { RELOC_TYPE_8, RELOC_TYPE_PC8, + RELOC_TYPE_32_NO_BASE, RELOC_TYPE_END }; diff --git a/section.c b/section.c index c4e2c32..2c9dcbf 100644 --- a/section.c +++ b/section.c @@ -180,6 +180,34 @@ struct subsection *subsection_find (struct section *section, const char *name) { } +struct subsection *subsection_find_or_make (struct section *section, const char *name) { + + struct subsection *subsection, **next_p; + + for (subsection = *(next_p = §ion->all_subsections); subsection; subsection = *(next_p = &subsection->next)) { + + if (strcmp (name, subsection->name) <= 0) { + break; + } + + } + + if (!subsection || strcmp (name, subsection->name) != 0) { + + subsection = xmalloc (sizeof (*subsection)); + + subsection->name = xstrdup (name); + subsection->next = *next_p; + subsection->last_part_p = &subsection->first_part; + + *next_p = subsection; + + } + + return subsection; + +} + void subsection_append_section_part (struct subsection *subsection, struct section_part *part) { *subsection->last_part_p = part; diff --git a/section.h b/section.h index 0f0686b..1c4f469 100644 --- a/section.h +++ b/section.h @@ -99,6 +99,8 @@ void section_write (struct section *section, unsigned char *memory); int section_count (void); struct subsection *subsection_find (struct section *section, const char *name); +struct subsection *subsection_find_or_make (struct section *section, const char *name); + void subsection_append_section_part (struct subsection *subsection, struct section_part *part); #endif /* _SECTION_H */