write first linker member header with symbol names grouped by member

This commit is contained in:
Nikita Smith
2025-09-07 21:13:13 -07:00
committed by Ryan Fleury
parent 24b427fe72
commit bbe430cc2f
2 changed files with 113 additions and 92 deletions
+111 -91
View File
@@ -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
+2 -1
View File
@@ -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);