diff --git a/src/coff/coff_lib_writer.c b/src/coff/coff_lib_writer.c index aaf590e0..aeb9a3d2 100644 --- a/src/coff/coff_lib_writer.c +++ b/src/coff/coff_lib_writer.c @@ -5,8 +5,8 @@ internal COFF_LibWriterSymbolNode * coff_lib_writer_symbol_list_push(Arena *arena, COFF_LibWriterSymbolList *list, COFF_LibWriterSymbol symbol) { COFF_LibWriterSymbolNode *node = push_array_no_zero(arena, COFF_LibWriterSymbolNode, 1); - node->next = 0; - node->data = symbol; + node->next = 0; + node->data = symbol; SLLQueuePush(list->first, list->last, node); list->count += 1; return node; @@ -16,8 +16,8 @@ internal COFF_LibWriterMemberNode * coff_lib_writer_member_list_push(Arena *arena, COFF_LibWriterMemberList *list, COFF_LibWriterMember member) { COFF_LibWriterMemberNode *node = push_array_no_zero(arena, COFF_LibWriterMemberNode, 1); - node->next = 0; - node->data = member; + node->next = 0; + node->data = member; SLLQueuePush(list->first, list->last, node); list->count += 1; return node; @@ -29,8 +29,7 @@ coff_lib_writer_symbol_array_from_list(Arena *arena, COFF_LibWriterSymbolList li COFF_LibWriterSymbol *arr = push_array_no_zero(arena, COFF_LibWriterSymbol, list.count + 2); COFF_LibWriterSymbol *ptr = arr + 1; for (COFF_LibWriterSymbolNode *i = list.first; i != 0; i = i->next, ptr += 1) { - ptr->name = push_str8_copy(arena, i->data.name); - ptr->member_idx = i->data.member_idx; + *ptr = i->data; } MemoryZeroStruct(&arr[0]); MemoryZeroStruct(&arr[list.count+1]); @@ -58,17 +57,30 @@ coff_lib_writer_symbol_name_compar(const void *raw_a, const void *raw_b) } internal int -coff_lib_writer_symbol_is_before(void *raw_a, void *raw_b) +coff_lib_writer_symbol_is_before_name(void *raw_a, void *raw_b) { - int compar = coff_lib_writer_symbol_name_compar(raw_a, raw_b); - return compar < 0; + return coff_lib_writer_symbol_name_compar(raw_a, raw_b) < 0; +} + +internal int +coff_lib_writer_symbol_is_before_member_idx(void *raw_a, void *raw_b) +{ + COFF_LibWriterSymbol *a = raw_a, *b = raw_b; + return a->member_idx < b->member_idx; } internal void -coff_lib_writer_symbol_array_sort(COFF_LibWriterSymbol *arr, U64 count) +coff_lib_writer_symbol_array_sort_on_name(COFF_LibWriterSymbol *arr, U64 count) { Assert(count >= 2); - radsort(arr + 1, count - 2, coff_lib_writer_symbol_is_before); + radsort(arr + 1, count - 2, coff_lib_writer_symbol_is_before_name); +} + +internal void +coff_lib_writer_symbol_array_sort_on_member_idx(COFF_LibWriterSymbol *arr, U64 count) +{ + Assert(count >= 2); + radsort(arr + 1, count - 2, coff_lib_writer_symbol_is_before_member_idx); } internal COFF_LibWriter * @@ -93,36 +105,21 @@ coff_lib_writer_push_obj(COFF_LibWriter *writer, String8 obj_path, String8 obj_d U64 member_idx = writer->member_list.count; // push obj member - COFF_LibWriterMember member = {0}; - member.name = obj_path; - member.data = obj_data; - coff_lib_writer_member_list_push(writer->arena, &writer->member_list, member); + COFF_LibWriterMember member = { .name = obj_path, .data = obj_data }; + COFF_LibWriterMemberNode *member_node = coff_lib_writer_member_list_push(writer->arena, &writer->member_list, member); // push external symbols - { - COFF_FileHeaderInfo obj_header = coff_file_header_info_from_data(obj_data); - String8 string_table = str8_substr(obj_data, obj_header.string_table_range); - String8 symbol_table = str8_substr(obj_data, obj_header.symbol_table_range); - - COFF_ParsedSymbol symbol; - for (U64 symbol_idx = 0; symbol_idx < obj_header.symbol_count; symbol_idx += (1 + symbol.aux_symbol_count)) { - void *symbol_ptr; - if (obj_header.is_big_obj) { - symbol_ptr = &((COFF_Symbol32 *)symbol_table.str)[symbol_idx]; - symbol = coff_parse_symbol32(string_table, symbol_ptr); - } else { - symbol_ptr = &((COFF_Symbol16 *)symbol_table.str)[symbol_idx]; - symbol = coff_parse_symbol16(string_table, symbol_ptr); - } - - COFF_SymbolValueInterpType interp = coff_interp_symbol(symbol.section_number, symbol.value, symbol.storage_class); - if (interp == COFF_SymbolValueInterp_Regular || interp == COFF_SymbolValueInterp_Common || interp == COFF_SymbolValueInterp_Abs) { - if (symbol.storage_class == COFF_SymStorageClass_External) { - COFF_LibWriterSymbol lib_symbol = {0}; - lib_symbol.name = symbol.name; - lib_symbol.member_idx = member_idx; - coff_lib_writer_symbol_list_push(writer->arena, &writer->symbol_list, lib_symbol); - } + COFF_FileHeaderInfo obj_header = coff_file_header_info_from_data(obj_data); + String8 string_table = str8_substr(obj_data, obj_header.string_table_range); + String8 symbol_table = str8_substr(obj_data, obj_header.symbol_table_range); + COFF_ParsedSymbol symbol; + for (U64 symbol_idx = 0; symbol_idx < obj_header.symbol_count; symbol_idx += (1 + symbol.aux_symbol_count)) { + symbol = coff_parse_symbol(obj_header, string_table, symbol_table, symbol_idx); + COFF_SymbolValueInterpType interp = coff_interp_from_parsed_symbol(symbol); + if (interp == COFF_SymbolValueInterp_Regular || interp == COFF_SymbolValueInterp_Common || interp == COFF_SymbolValueInterp_Abs) { + if (symbol.storage_class == COFF_SymStorageClass_External) { + COFF_LibWriterSymbol lib_symbol = { .name = symbol.name, .member_idx = member_idx }; + coff_lib_writer_symbol_list_push(writer->arena, &writer->symbol_list, lib_symbol); } } } @@ -133,30 +130,29 @@ coff_lib_writer_push_obj(COFF_LibWriter *writer, String8 obj_path, String8 obj_d internal void coff_lib_writer_push_import(COFF_LibWriter *lib_writer, COFF_MachineType machine, COFF_TimeStamp time_stamp, String8 dll_name, COFF_ImportByType import_by, String8 name, U16 hint_or_ordinal, COFF_ImportType import_type) { - // push import member U64 member_idx = lib_writer->member_list.count; - COFF_LibWriterMember member = {0}; - member.name = dll_name; - member.data = coff_make_import_header(lib_writer->arena, machine, time_stamp, dll_name, import_by, name, hint_or_ordinal, import_type); - coff_lib_writer_member_list_push(lib_writer->arena, &lib_writer->member_list, member); + + String8 member_data = coff_make_import_header(lib_writer->arena, machine, time_stamp, dll_name, import_by, name, hint_or_ordinal, import_type); + COFF_LibWriterMember member = { .name = dll_name, .data = member_data }; + COFF_LibWriterMemberNode *member_node = coff_lib_writer_member_list_push(lib_writer->arena, &lib_writer->member_list, member); if (name.size) { switch (import_type) { case COFF_ImportHeader_Code: { COFF_LibWriterSymbol thunk_symbol = {0}; - thunk_symbol.name = push_str8_copy(lib_writer->arena, name); - thunk_symbol.member_idx = member_idx; + thunk_symbol.name = push_str8_copy(lib_writer->arena, name); + thunk_symbol.member_idx = member_idx; coff_lib_writer_symbol_list_push(lib_writer->arena, &lib_writer->symbol_list, thunk_symbol); COFF_LibWriterSymbol imp_symbol = {0}; - imp_symbol.name = push_str8f(lib_writer->arena, "__imp_%S", name); - imp_symbol.member_idx = member_idx; + imp_symbol.name = push_str8f(lib_writer->arena, "__imp_%S", name); + imp_symbol.member_idx = member_idx; coff_lib_writer_symbol_list_push(lib_writer->arena, &lib_writer->symbol_list, imp_symbol); } break; case COFF_ImportHeader_Data: { COFF_LibWriterSymbol imp_symbol = {0}; - imp_symbol.name = push_str8f(lib_writer->arena, "__imp_%S", name); - imp_symbol.member_idx = member_idx; + imp_symbol.name = push_str8f(lib_writer->arena, "__imp_%S", name); + imp_symbol.member_idx = member_idx; coff_lib_writer_symbol_list_push(lib_writer->arena, &lib_writer->symbol_list, imp_symbol); } break; case COFF_ImportHeader_Const: { NotImplemented; } break; @@ -170,29 +166,17 @@ coff_lib_writer_serialize(Arena *arena, COFF_LibWriter *lib_writer, COFF_TimeSta { Temp scratch = scratch_begin(&arena, 1); - // symbol & member lists -> arrays - U64 symbols_count; - COFF_LibWriterSymbol *symbols; - U64 member_count; - COFF_LibWriterMember *member_array; - { - U64 symbols_count_with_null = lib_writer->symbol_list.count + 2; - COFF_LibWriterSymbol *symbols_with_null = coff_lib_writer_symbol_array_from_list(scratch.arena, lib_writer->symbol_list); - coff_lib_writer_symbol_array_sort(symbols_with_null, symbols_count_with_null); - symbols_count = symbols_count_with_null - 2; - symbols = symbols_with_null + 1; - - member_count = lib_writer->member_list.count; - member_array = coff_lib_writer_member_array_from_list(scratch.arena, lib_writer->member_list); - } + // member lists -> arrays + U64 member_count = lib_writer->member_list.count; + COFF_LibWriterMember *member_array = coff_lib_writer_member_array_from_list(scratch.arena, lib_writer->member_list); // serialize members - U64 *member_offsets = push_array_no_zero(scratch.arena, U64, member_count); - String8List long_names_list = {0}; - String8List member_data_list = {0}; + U64 *member_offsets = push_array_no_zero(scratch.arena, U64, member_count); + String8List long_names_list = {0}; + String8List member_data_list = {0}; { HashTable *name_ht = hash_table_init(scratch.arena, 1024); - for (U64 member_idx = 0; member_idx < member_count; member_idx += 1) { + for EachIndex(member_idx, member_count) { COFF_LibWriterMember *member = &member_array[member_idx]; // make member name @@ -227,7 +211,7 @@ coff_lib_writer_serialize(Arena *arena, COFF_LibWriter *lib_writer, COFF_TimeSta } } - // long names member + // write long names member if (long_names_list.total_size) { String8 header = coff_make_lib_member_header(scratch.arena, str8_lit("//"), time_stamp, 0, 0, mode, long_names_list.total_size); String8 data = str8_list_join(scratch.arena, &long_names_list, 0); @@ -243,26 +227,16 @@ coff_lib_writer_serialize(Arena *arena, COFF_LibWriter *lib_writer, COFF_TimeSta // compute size for symbol string table U32 name_buffer_size = 0; - for (COFF_LibWriterSymbol *ptr = &symbols[0], *opl = ptr + symbols_count; ptr < opl; ptr += 1) { - name_buffer_size += ptr->name.size; + for (COFF_LibWriterSymbolNode *node = lib_writer->symbol_list.first; node != 0; node = node->next) { + name_buffer_size += node->data.name.size; name_buffer_size += 1; // null } - - // write symbol name buffer - U8 *name_buffer = push_array_no_zero(scratch.arena, U8, name_buffer_size); - { - U64 name_cursor = 0; - for (COFF_LibWriterSymbol *ptr = &symbols[0], *opl = ptr + symbols_count; ptr < opl; ptr += 1) { - MemoryCopy(name_buffer + name_cursor, ptr->name.str, ptr->name.size); - name_buffer[name_cursor + ptr->name.size] = '\0'; - name_cursor += ptr->name.size + 1; - } - } - + + // compute members base offset U64 members_base_offset; { - U64 sizeof_first_header = sizeof(COFF_ArchiveMemberHeader) + sizeof(U32) + sizeof(U32) * symbols_count + name_buffer_size; - U64 sizeof_second_header = sizeof(COFF_ArchiveMemberHeader) + sizeof(U32) + sizeof(U32) * member_count + sizeof(U32) + sizeof(U16) * symbols_count + name_buffer_size; + U64 sizeof_first_header = sizeof(COFF_ArchiveMemberHeader) + sizeof(U32) + sizeof(U32) * lib_writer->symbol_list.count + name_buffer_size; + U64 sizeof_second_header = sizeof(COFF_ArchiveMemberHeader) + sizeof(U32) + sizeof(U32) * member_count + sizeof(U32) + sizeof(U16) * lib_writer->symbol_list.count + name_buffer_size; U64 sizeof_long_names = sizeof(COFF_ArchiveMemberHeader) + long_names_list.total_size; sizeof_first_header = AlignPow2(sizeof_first_header, COFF_Archive_MemberAlign); @@ -279,8 +253,31 @@ coff_lib_writer_serialize(Arena *arena, COFF_LibWriter *lib_writer, COFF_TimeSta } } - // second linker member + // write second linker member if (emit_second_member) { + U64 symbols_count; + COFF_LibWriterSymbol *symbols; + { + U64 symbols_count_with_null = lib_writer->symbol_list.count + 2; + COFF_LibWriterSymbol *symbols_with_null = coff_lib_writer_symbol_array_from_list(scratch.arena, lib_writer->symbol_list); + coff_lib_writer_symbol_array_sort_on_name(symbols_with_null, symbols_count_with_null); + + symbols_count = symbols_count_with_null - 2; + symbols = symbols_with_null + 1; + } + + // write symbol name buffer + U8 *name_buffer = push_array_no_zero(scratch.arena, U8, name_buffer_size); + { + U64 name_cursor = 0; + for EachIndex(symbol_idx, symbols_count) { + COFF_LibWriterSymbol *symbol = &symbols[symbol_idx]; + MemoryCopy(name_buffer + name_cursor, symbol->name.str, symbol->name.size); + name_buffer[name_cursor + symbol->name.size] = '\0'; + name_cursor += symbol->name.size + 1; + } + } + U32 member_count32 = safe_cast_u32(member_count); U32 symbol_count32 = safe_cast_u32(symbols_count); @@ -288,14 +285,14 @@ coff_lib_writer_serialize(Arena *arena, COFF_LibWriter *lib_writer, COFF_TimeSta U16 *member_idx16_arr = push_array_no_zero(scratch.arena, U16, symbols_count); // write member offset array - for (U64 member_idx = 0; member_idx < member_count; member_idx += 1) { + for EachIndex(member_idx, member_count) { U64 member_offset = members_base_offset + member_offsets[member_idx]; U32 member_off32 = safe_cast_u32(member_offset); member_off32_arr[member_idx] = member_off32; } // write member offset indices for each symbol - for (U64 symbol_idx = 0; symbol_idx < symbols_count; symbol_idx += 1) { + for EachIndex(symbol_idx, symbols_count) { // member offset indices are 1-based U64 member_idx = symbols[symbol_idx].member_idx + 1; U16 member_idx16 = safe_cast_u16(member_idx); @@ -323,12 +320,35 @@ coff_lib_writer_serialize(Arena *arena, COFF_LibWriter *lib_writer, COFF_TimeSta str8_list_push_front(scratch.arena, &member_data_list, member_header); } - // first linker member (obsolete, but kept for compatability reasons) + // write first linker member (obsolete, but kept for compatability reasons) { + U64 symbols_count; + COFF_LibWriterSymbol *symbols; + { + U64 symbols_count_with_null = lib_writer->symbol_list.count + 2; + COFF_LibWriterSymbol *symbols_with_null = coff_lib_writer_symbol_array_from_list(scratch.arena, lib_writer->symbol_list); + coff_lib_writer_symbol_array_sort_on_member_idx(symbols_with_null, symbols_count_with_null); + + symbols_count = symbols_count_with_null - 2; + symbols = symbols_with_null + 1; + } + + // write symbol name buffer + U8 *name_buffer = push_array_no_zero(scratch.arena, U8, name_buffer_size); + { + U64 name_cursor = 0; + for EachIndex(symbol_idx, symbols_count) { + COFF_LibWriterSymbol *symbol = &symbols[symbol_idx]; + MemoryCopy(name_buffer + name_cursor, symbol->name.str, symbol->name.size); + name_buffer[name_cursor + symbol->name.size] = '\0'; + name_cursor += symbol->name.size + 1; + } + } + U32 symbol_count_be = from_be_u32(symbols_count); U32 *member_off32_arr = push_array_no_zero(scratch.arena, U32, symbols_count); - for (U64 symbol_idx = 0; symbol_idx < symbols_count; symbol_idx += 1) { + for EachIndex(symbol_idx, symbols_count) { COFF_LibWriterSymbol *symbol = &symbols[symbol_idx]; // write big endian member offset diff --git a/src/coff/coff_lib_writer.h b/src/coff/coff_lib_writer.h index 2c501409..ab9dfc99 100644 --- a/src/coff/coff_lib_writer.h +++ b/src/coff/coff_lib_writer.h @@ -57,7 +57,8 @@ internal COFF_LibWriterMemberNode * coff_lib_writer_member_list_push(Arena *aren internal COFF_LibWriterSymbol * coff_lib_writer_symbol_array_from_list(Arena *arena, COFF_LibWriterSymbolList list); internal COFF_LibWriterMember * coff_lib_writer_member_array_from_list(Arena *arena, COFF_LibWriterMemberList list); -internal void coff_lib_writer_symbol_array_sort(COFF_LibWriterSymbol *arr, U64 count); +internal void coff_lib_writer_symbol_array_sort_on_name(COFF_LibWriterSymbol *arr, U64 count); +internal void coff_lib_writer_symbol_array_sort_on_member_idx(COFF_LibWriterSymbol *arr, U64 count); internal COFF_LibWriter * coff_lib_writer_alloc(void); internal void coff_lib_writer_release(COFF_LibWriter **writer_ptr);