mirror of
https://github.com/Ed94/raddebugger.git
synced 2026-06-24 12:44:59 -07:00
246 lines
8.1 KiB
C
246 lines
8.1 KiB
C
// Copyright (c) 2025 Epic Games Tools
|
|
// Licensed under the MIT license (https://opensource.org/license/mit/)
|
|
|
|
internal LNK_LibNode *
|
|
lnk_lib_list_pop_node_atomic(LNK_LibList *list)
|
|
{
|
|
for (;;) {
|
|
LNK_LibNode *expected = list->first;
|
|
LNK_LibNode *current = ins_atomic_ptr_eval_cond_assign(&list->first, expected->next, expected);
|
|
if (expected == current) {
|
|
ins_atomic_u64_dec_eval(&list->count);
|
|
return expected;
|
|
}
|
|
}
|
|
}
|
|
|
|
internal void
|
|
lnk_lib_list_push_node_atomic(LNK_LibList *list, LNK_LibNode *node)
|
|
{
|
|
for (;;) {
|
|
LNK_LibNode *expected = list->first;
|
|
LNK_LibNode *current = ins_atomic_ptr_eval_cond_assign(&list->first, node, expected);
|
|
if (current == expected) {
|
|
node->next = expected;
|
|
ins_atomic_u64_inc_eval(&list->count);
|
|
return;
|
|
}
|
|
}
|
|
}
|
|
|
|
internal void
|
|
lnk_lib_list_push_node(LNK_LibList *list, LNK_LibNode *node)
|
|
{
|
|
SLLStackPush(list->first, node);
|
|
list->count += 1;
|
|
}
|
|
|
|
internal LNK_LibList
|
|
lnk_lib_list_reserve(Arena *arena, U64 count)
|
|
{
|
|
LNK_LibList result = {0};
|
|
LNK_LibNode *nodes = push_array(arena, LNK_LibNode, count);
|
|
for (U64 i = 0; i < count; i += 1) { lnk_lib_list_push_node(&result, &nodes[i]); }
|
|
return result;
|
|
}
|
|
|
|
internal LNK_LibNodeArray
|
|
lnk_array_from_lib_list(Arena *arena, LNK_LibList list)
|
|
{
|
|
LNK_LibNodeArray result = {0};
|
|
result.v = push_array(arena, LNK_LibNode, list.count);
|
|
for (LNK_LibNode *n = list.first; n != 0; n = n->next) { result.v[result.count++] = *n; }
|
|
return result;
|
|
}
|
|
|
|
internal B32
|
|
lnk_lib_from_data(Arena *arena, String8 data, String8 path, LNK_Lib *lib_out)
|
|
{
|
|
ProfBeginFunction();
|
|
|
|
// is data archive?
|
|
COFF_ArchiveType type = coff_archive_type_from_data(data);
|
|
if (type == COFF_Archive_Null) {
|
|
return 0;
|
|
}
|
|
|
|
COFF_ArchiveParse parse = coff_archive_parse_from_data(data);
|
|
if (parse.error.size) {
|
|
return 0;
|
|
}
|
|
|
|
U64 symbol_count = 0;
|
|
String8 string_table = {0};
|
|
U16 *symbol_indices = 0;
|
|
U32 *member_offsets = 0;
|
|
|
|
// try to init library from optional second member
|
|
if (parse.second_member.member_count) {
|
|
COFF_ArchiveSecondMember second_member = parse.second_member;
|
|
Assert(second_member.symbol_count == second_member.symbol_index_count);
|
|
Assert(second_member.member_count == second_member.member_offset_count);
|
|
|
|
symbol_count = second_member.symbol_count;
|
|
string_table = second_member.string_table;
|
|
member_offsets = second_member.member_offsets;
|
|
symbol_indices = second_member.symbol_indices;
|
|
}
|
|
// first member is deprecated however tools emit it for compatibility reasons
|
|
// and lld-link with /DLL emits only first member
|
|
else if (parse.first_member.symbol_count) {
|
|
Temp scratch = scratch_begin(&arena, 1);
|
|
|
|
COFF_ArchiveFirstMember first_member = parse.first_member;
|
|
Assert(first_member.symbol_count == first_member.member_offset_count);
|
|
|
|
symbol_count = first_member.symbol_count;
|
|
string_table = first_member.string_table;
|
|
|
|
// convert big endian offsets
|
|
for (U32 offset_idx = 0; offset_idx < symbol_count; offset_idx += 1) {
|
|
first_member.member_offsets[offset_idx] = from_be_u32(first_member.member_offsets[offset_idx]);
|
|
}
|
|
|
|
// compress member offsets to match those from the second header
|
|
{
|
|
HashTable *member_off_ht = hash_table_init(scratch.arena, (U64)((F64)first_member.symbol_count * 1.3));
|
|
for EachIndex(symbol_idx, symbol_count) {
|
|
if (!hash_table_search_u32_u32(member_off_ht, first_member.member_offsets[symbol_idx], 0)) {
|
|
hash_table_push_u32_u32(scratch.arena, member_off_ht, first_member.member_offsets[symbol_idx], member_off_ht->count);
|
|
}
|
|
}
|
|
|
|
symbol_indices = push_array(arena, U16, first_member.symbol_count);
|
|
for EachIndex(symbol_idx, first_member.symbol_count) {
|
|
U32 member_off = first_member.member_offsets[symbol_idx];
|
|
U32 member_off_idx = 0;
|
|
if (!hash_table_search_u32_u32(member_off_ht, member_off, &member_off_idx)) {
|
|
InvalidPath;
|
|
}
|
|
symbol_indices[symbol_idx] = member_off_idx+1;
|
|
}
|
|
|
|
member_offsets = push_array_no_zero(arena, U32, member_off_ht->count);
|
|
for EachIndex(bucket_idx, member_off_ht->cap) {
|
|
BucketList *bucket = &member_off_ht->buckets[bucket_idx];
|
|
for (BucketNode *n = bucket->first; n != 0; n = n->next) {
|
|
U32 member_off = n->v.key_u32;
|
|
U32 member_off_idx = n->v.value_u32;
|
|
member_offsets[member_off_idx] = member_off;
|
|
}
|
|
}
|
|
}
|
|
|
|
scratch_end(scratch);
|
|
}
|
|
|
|
// parse string table
|
|
String8Array symbol_names;
|
|
{
|
|
Temp scratch = scratch_begin(&arena, 1);
|
|
String8List symbol_name_list = str8_split_by_string_chars(scratch.arena, string_table, str8_lit("\0"), StringSplitFlag_KeepEmpties);
|
|
Assert(symbol_name_list.node_count >= symbol_count);
|
|
symbol_names = str8_array_from_list(arena, &symbol_name_list);
|
|
scratch_end(scratch);
|
|
}
|
|
|
|
symbol_count = Min(symbol_count, symbol_names.count);
|
|
|
|
// init lib
|
|
lib_out->path = push_str8_copy(arena, path);
|
|
lib_out->data = data;
|
|
lib_out->type = type;
|
|
lib_out->symbol_count = symbol_count;
|
|
lib_out->member_offsets = member_offsets;
|
|
lib_out->symbol_indices = symbol_indices;
|
|
lib_out->symbol_names = symbol_names;
|
|
lib_out->long_names = parse.long_names;
|
|
|
|
ProfEnd();
|
|
return 1;
|
|
}
|
|
|
|
internal
|
|
THREAD_POOL_TASK_FUNC(lnk_lib_initer)
|
|
{
|
|
LNK_LibIniter *task = raw_task;
|
|
|
|
LNK_LibNode *lib_node = lnk_lib_list_pop_node_atomic(&task->free_libs);
|
|
lib_node->data.input_idx = task_id;
|
|
|
|
B32 is_valid_lib = lnk_lib_from_data(arena, task->data_arr[task_id], task->path_arr[task_id], &lib_node->data);
|
|
if (is_valid_lib) {
|
|
lnk_lib_list_push_node_atomic(&task->valid_libs, lib_node);
|
|
} else {
|
|
lnk_lib_list_push_node_atomic(&task->invalid_libs, lib_node);
|
|
}
|
|
}
|
|
|
|
internal int
|
|
lnk_lib_node_is_before(void *a, void *b)
|
|
{
|
|
return ((LNK_LibNode*)a)->data.input_idx < ((LNK_LibNode*)b)->data.input_idx;
|
|
}
|
|
|
|
internal LNK_LibNodeArray
|
|
lnk_lib_list_push_parallel(TP_Context *tp, TP_Arena *arena, LNK_LibList *list, String8Array data_arr, String8Array path_arr)
|
|
{
|
|
Temp scratch = scratch_begin(arena->v, arena->count);
|
|
|
|
Assert(data_arr.count == path_arr.count);
|
|
U64 lib_count = data_arr.count;
|
|
|
|
// parse libs in parallel
|
|
LNK_LibIniter task = {0};
|
|
task.free_libs = lnk_lib_list_reserve(scratch.arena, lib_count);
|
|
task.data_arr = data_arr.v;
|
|
task.path_arr = path_arr.v;
|
|
tp_for_parallel(tp, arena, lib_count, lnk_lib_initer, &task);
|
|
|
|
// report invalid libs
|
|
LNK_LibNodeArray invalid_libs = lnk_array_from_lib_list(scratch.arena, task.invalid_libs);
|
|
radsort(invalid_libs.v, invalid_libs.count, lnk_lib_node_is_before);
|
|
for (U64 i = 0; i < task.invalid_libs.count; i += 1) {
|
|
U64 input_idx = invalid_libs.v[i].data.input_idx;
|
|
lnk_error(LNK_Error_InvalidLib, "%S: failed to parse library", path_arr.v[input_idx]);
|
|
}
|
|
|
|
// push parsed libs
|
|
LNK_LibNodeArray result = lnk_array_from_lib_list(arena->v[0], task.valid_libs);
|
|
radsort(result.v, result.count, lnk_lib_node_is_before);
|
|
for (U64 i = result.count; i > 0; i -= 1) {
|
|
result.v[i-1].data.input_idx = list->count;
|
|
lnk_lib_list_push_node(list, &result.v[i-1]);
|
|
}
|
|
|
|
scratch_end(scratch);
|
|
return result;
|
|
}
|
|
|
|
internal
|
|
THREAD_POOL_TASK_FUNC(lnk_push_lib_symbols_task)
|
|
{
|
|
LNK_SymbolPusher *task = raw_task;
|
|
LNK_SymbolTable *symtab = task->symtab;
|
|
LNK_Lib *lib = &task->u.libs.v[task_id].data;
|
|
for EachIndex(symbol_idx, lib->symbol_count) {
|
|
U32 member_offset_number = lib->symbol_indices[symbol_idx];
|
|
if (member_offset_number > 0) {
|
|
LNK_Symbol *symbol = lnk_make_lib_symbol(arena, lib->symbol_names.v[symbol_idx], lib, lib->member_offsets[member_offset_number-1]);
|
|
lnk_symbol_table_push_(symtab, arena, worker_id, LNK_SymbolScope_Lib, symbol);
|
|
}
|
|
}
|
|
}
|
|
|
|
internal void
|
|
lnk_input_lib_symbols(TP_Context *tp, LNK_SymbolTable *symtab, LNK_LibNodeArray libs)
|
|
{
|
|
ProfBeginFunction();
|
|
LNK_SymbolPusher task = {0};
|
|
task.symtab = symtab;
|
|
task.u.libs = libs;
|
|
tp_for_parallel(tp, symtab->arena, libs.count, lnk_push_lib_symbols_task, &task);
|
|
ProfEnd();
|
|
}
|
|
|