mirror of
https://github.com/Ed94/raddebugger.git
synced 2026-06-13 07:32:23 -07:00
pack export table into obj and input back to the linker
This commit is contained in:
committed by
Ryan Fleury
parent
c5164bd490
commit
f25dc5cc8d
+128
-41
@@ -869,6 +869,48 @@ lnk_push_loaded_lib(Arena *arena, HashTable *loaded_lib_ht, String8 path)
|
||||
}
|
||||
}
|
||||
|
||||
internal void
|
||||
lnk_push_export(Arena *arena, HashTable *export_ht, LNK_ExportParseList *export_list, String8List *include_symbol_list, LNK_ExportParse export_parse)
|
||||
{
|
||||
LNK_ExportParseNode *exp_n = 0;
|
||||
String8 export_name = lnk_name_from_export_parse(&export_parse);
|
||||
hash_table_search_string_raw(export_ht, export_name, &exp_n);
|
||||
|
||||
if (exp_n == 0) {
|
||||
// make sure export is defined
|
||||
if (!export_parse.is_forwarder) {
|
||||
str8_list_push(arena, include_symbol_list, export_parse.name);
|
||||
}
|
||||
|
||||
// push new export
|
||||
exp_n = lnk_export_parse_list_push(arena, export_list, export_parse);
|
||||
|
||||
hash_table_push_string_raw(arena, export_ht, export_name, exp_n);
|
||||
} else {
|
||||
B32 is_ambiguous = 1;
|
||||
LNK_ExportParse *extant_export = &exp_n->data;
|
||||
|
||||
if (extant_export->alias.size && export_parse.alias.size && !str8_match(extant_export->alias, export_parse.alias, 0)) {
|
||||
goto report;
|
||||
}
|
||||
|
||||
if (extant_export->ordinal != export_parse.ordinal) {
|
||||
goto report;
|
||||
}
|
||||
|
||||
is_ambiguous = 0;
|
||||
|
||||
if (extant_export->alias.size == 0 && export_parse.alias.size != 0) {
|
||||
extant_export->alias = export_parse.alias;
|
||||
}
|
||||
|
||||
report:;
|
||||
if (is_ambiguous) {
|
||||
lnk_error_with_loc(LNK_Error_IllExport, export_parse.obj_path, export_parse.lib_path, "ambiguous symbol export %S", export_parse.name);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
internal LNK_InputObjList
|
||||
lnk_push_linker_symbols(Arena *arena, LNK_Config *config)
|
||||
{
|
||||
@@ -963,13 +1005,13 @@ lnk_queue_lib_member_input(Arena *arena, PathStyle path_style, LNK_SymbolLib *sy
|
||||
}
|
||||
|
||||
internal int
|
||||
lnk_section_contrib_is_before(void *raw_a, void *raw_b)
|
||||
lnk_section_contrib_ptr_is_before(void *raw_a, void *raw_b)
|
||||
{
|
||||
// Grouped Sections (PE Format)
|
||||
// "All contributions with the same object-section name are allocated contiguously in the image,
|
||||
// and the blocks of contributions are sorted in lexical order by object-section name."
|
||||
LNK_SectionContrib *a = raw_a;
|
||||
LNK_SectionContrib *b = raw_b;
|
||||
LNK_SectionContrib *a = *(LNK_SectionContrib **)raw_a;
|
||||
LNK_SectionContrib *b = *(LNK_SectionContrib **)raw_b;
|
||||
|
||||
int cmp;
|
||||
|
||||
@@ -1220,7 +1262,6 @@ internal String8List
|
||||
lnk_build_guard_tables(TP_Context *tp,
|
||||
LNK_SectionTable *sectab,
|
||||
LNK_SymbolTable *symtab,
|
||||
LNK_ExportTable *exptab,
|
||||
U64 objs_count,
|
||||
LNK_Obj **objs,
|
||||
COFF_MachineType machine,
|
||||
@@ -2007,7 +2048,7 @@ lnk_pdata_is_before_x8664(void *raw_a, void *raw_b)
|
||||
}
|
||||
|
||||
internal String8
|
||||
lnk_build_win32_image(TP_Arena *arena, TP_Context *tp, LNK_Config *config, LNK_SymbolTable *symtab, LNK_ExportTable *exptab, LNK_ObjList obj_list)
|
||||
lnk_build_win32_image(TP_Arena *arena, TP_Context *tp, LNK_Config *config, LNK_SymbolTable *symtab, LNK_ObjList obj_list)
|
||||
{
|
||||
Temp scratch = scratch_begin(arena->v, arena->count);
|
||||
|
||||
@@ -2182,18 +2223,18 @@ lnk_build_win32_image(TP_Arena *arena, TP_Context *tp, LNK_Config *config, LNK_S
|
||||
COFF_SectionFlags flags = sect_header->flags & ~COFF_SectionFlags_LnkFlags;
|
||||
LNK_Section *sect = lnk_section_table_search(sectab, sect_name, flags);
|
||||
|
||||
String8Node *data_n = push_array(sect->arena, String8Node, 1);
|
||||
data_n->string = sect_data;
|
||||
|
||||
// fill out contrib
|
||||
LNK_SectionContribChunk *sc_chunk = sect->contribs.first;
|
||||
LNK_SectionContrib *sc = lnk_section_contrib_chunk_push(sc_chunk, 1);
|
||||
sc->align = sc_align;
|
||||
sc->data_list = data_n;
|
||||
sc->u.obj_idx = obj_idx;
|
||||
sc->u.sort_idx_size = (U16)sect_sort_idx.size;
|
||||
sc->u.sort_idx = sect_sort_idx.str;
|
||||
|
||||
String8Node *data_n = push_array(sect->arena, String8Node, 1);
|
||||
data_n->string = sect_data;
|
||||
SLLStackPush(sc->data_list, data_n);
|
||||
|
||||
sect_map[obj_idx][sect_idx] = sc;
|
||||
}
|
||||
}
|
||||
@@ -2242,7 +2283,7 @@ lnk_build_win32_image(TP_Arena *arena, TP_Context *tp, LNK_Config *config, LNK_S
|
||||
for (LNK_SectionNode *sect_n = sectab->list.first; sect_n != 0; sect_n = sect_n->next) {
|
||||
for (LNK_SectionContribChunk *sc_chunk = sect_n->data.contribs.first; sc_chunk != 0; sc_chunk = sc_chunk->next) {
|
||||
Assert(sc_chunk->count == sc_chunk->cap);
|
||||
radsort(sc_chunk->v, sc_chunk->count, lnk_section_contrib_is_before);
|
||||
radsort(sc_chunk->v, sc_chunk->count, lnk_section_contrib_ptr_is_before);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -2279,7 +2320,7 @@ lnk_build_win32_image(TP_Arena *arena, TP_Context *tp, LNK_Config *config, LNK_S
|
||||
LNK_Section *sect = §_n->data;
|
||||
for (LNK_SectionContribChunk *sc_chunk = sect->contribs.first; sc_chunk != 0; sc_chunk = sc_chunk->next) {
|
||||
for (U64 sc_idx = 0; sc_idx < sc_chunk->count; sc_idx += 1) {
|
||||
sc_chunk->v[sc_idx].u.sect_idx = sect->sect_idx;
|
||||
sc_chunk->v[sc_idx]->u.sect_idx = sect->sect_idx;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -2417,11 +2458,11 @@ lnk_build_win32_image(TP_Arena *arena, TP_Context *tp, LNK_Config *config, LNK_S
|
||||
if (obj->header.is_big_obj) {
|
||||
COFF_Symbol32 *symbol32 = symbol.raw_symbol;
|
||||
symbol32->section_number = safe_cast_u32(sc->u.sect_idx + 1);
|
||||
symbol32->value = safe_cast_u32(sc->u.off);
|
||||
symbol32->value = safe_cast_u32(sc->u.off + symbol32->value);
|
||||
} else {
|
||||
COFF_Symbol16 *symbol16 = symbol.raw_symbol;
|
||||
symbol16->section_number = safe_cast_u16(sc->u.sect_idx + 1);
|
||||
symbol16->value = safe_cast_u32(sc->u.off);
|
||||
symbol16->value = safe_cast_u32(sc->u.off + symbol16->value);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -2789,7 +2830,7 @@ lnk_build_win32_image(TP_Arena *arena, TP_Context *tp, LNK_Config *config, LNK_S
|
||||
U64 prev_sc_opl = 0;
|
||||
for (LNK_SectionContribChunk *sc_chunk = sect->contribs.first; sc_chunk != 0; sc_chunk = sc_chunk->next) {
|
||||
for (U64 sc_idx = 0; sc_idx < sc_chunk->count; sc_idx += 1) {
|
||||
LNK_SectionContrib *sc = &sc_chunk->v[sc_idx];
|
||||
LNK_SectionContrib *sc = sc_chunk->v[sc_idx];
|
||||
|
||||
// fill align bytes
|
||||
Assert(sc->u.off >= prev_sc_opl);
|
||||
@@ -2961,7 +3002,7 @@ lnk_build_win32_image(TP_Arena *arena, TP_Context *tp, LNK_Config *config, LNK_S
|
||||
|
||||
for (LNK_SectionContribChunk *sc_chunk = tls_sect->contribs.first; sc_chunk != 0; sc_chunk = sc_chunk->next) {
|
||||
for (U64 sc_idx = 0; sc_idx < sc_chunk->count; sc_idx += 1) {
|
||||
LNK_SectionContrib *sc = &sc_chunk->v[sc_idx];
|
||||
LNK_SectionContrib *sc = sc_chunk->v[sc_idx];
|
||||
tls_align = Max(tls_align, sc->align);
|
||||
}
|
||||
}
|
||||
@@ -3080,7 +3121,7 @@ lnk_build_win32_image(TP_Arena *arena, TP_Context *tp, LNK_Config *config, LNK_S
|
||||
}
|
||||
|
||||
internal String8List
|
||||
lnk_build_import_lib(Arena *arena, COFF_MachineType machine, COFF_TimeStamp time_stamp, String8 dll_name, LNK_ExportTable *exptab)
|
||||
lnk_build_import_lib(Arena *arena, COFF_MachineType machine, COFF_TimeStamp time_stamp, String8 dll_name, LNK_ExportParseList export_list)
|
||||
{
|
||||
ProfBeginFunction();
|
||||
Temp scratch = scratch_begin(&arena, 1);
|
||||
@@ -3094,20 +3135,24 @@ lnk_build_import_lib(Arena *arena, COFF_MachineType machine, COFF_TimeStamp time
|
||||
String8 null_thunk_data_obj = lnk_build_null_thunk_data_obj(scratch.arena, dll_name, time_stamp, machine);
|
||||
|
||||
COFF_LibWriter *lib_writer = coff_lib_writer_alloc();
|
||||
|
||||
// push import table nulls
|
||||
coff_lib_writer_push_obj(lib_writer, dll_name, import_entry_obj);
|
||||
coff_lib_writer_push_obj(lib_writer, dll_name, null_import_descriptor_obj);
|
||||
coff_lib_writer_push_obj(lib_writer, dll_name, null_thunk_data_obj);
|
||||
|
||||
KeyValuePair *raw_export_arr = key_value_pairs_from_hash_table(scratch.arena, exptab->name_export_ht);
|
||||
for (U64 i = 0; i < exptab->name_export_ht->count; ++i) {
|
||||
LNK_Export *exp = raw_export_arr[i].value_raw;
|
||||
if (exp->name.size) {
|
||||
coff_lib_writer_push_export_by_name(lib_writer, machine, time_stamp, dll_name, exp->type, exp->name, safe_cast_u16(exp->id));
|
||||
} else {
|
||||
// push exports
|
||||
for (LNK_ExportParseNode *exp_n = export_list.first; exp_n != 0; exp_n = exp_n->next) {
|
||||
LNK_ExportParse *exp = &exp_n->data;
|
||||
if (exp->is_noname_present) {
|
||||
coff_lib_writer_push_export_by_ordinal(lib_writer, machine, time_stamp, dll_name, exp->type, exp->ordinal);
|
||||
} else {
|
||||
String8 name = lnk_name_from_export_parse(exp);
|
||||
coff_lib_writer_push_export_by_name(lib_writer, machine, time_stamp, dll_name, exp->type, name, exp->hint);
|
||||
}
|
||||
}
|
||||
|
||||
// serialize lib
|
||||
String8List lib = coff_lib_writer_serialize(arena, lib_writer, COFF_TimeStamp_Max, 0, /* emit second member: */ 1);
|
||||
coff_lib_writer_release(&lib_writer);
|
||||
|
||||
@@ -3284,7 +3329,7 @@ lnk_build_rad_chunk_map(Arena *arena, String8 image_data, U64 thread_count, LNK_
|
||||
for (LNK_SectionContribChunk *sc_chunk = sect->contribs.first; sc_chunk != 0; sc_chunk = sc_chunk->next) {
|
||||
for (U64 sc_idx = 0; sc_idx < sc_chunk->count; sc_idx += 1) {
|
||||
Temp temp = temp_begin(scratch.arena);
|
||||
LNK_SectionContrib *sc = &sc_chunk->v[sc_idx];
|
||||
LNK_SectionContrib *sc = sc_chunk->v[sc_idx];
|
||||
|
||||
U64 file_off = image_section_table[sc->u.sect_idx]->foff + sc->u.off;
|
||||
U64 virt_off = image_section_table[sc->u.sect_idx]->voff + sc->u.off;
|
||||
@@ -3499,6 +3544,7 @@ lnk_run(int argc, char **argv)
|
||||
String8List input_manifest_path_list = str8_list_copy(scratch.arena, &config->input_list[LNK_Input_Manifest]);
|
||||
String8List manifest_dep_list = str8_list_copy(scratch.arena, &config->manifest_dependency_list);
|
||||
LNK_ExportParseList export_symbol_list = config->export_symbol_list;
|
||||
HashTable *export_ht = hash_table_init(scratch.arena, max_U16/2);
|
||||
LNK_AltNameList alt_name_list = config->alt_name_list;
|
||||
LNK_InputObjList input_obj_list = {0};
|
||||
LNK_InputImportList input_import_list = {0};
|
||||
@@ -3520,7 +3566,6 @@ lnk_run(int argc, char **argv)
|
||||
LNK_SectionTable *sectab = 0;
|
||||
LNK_ImportTable *imptab_static = lnk_import_table_alloc(0);
|
||||
LNK_ImportTable *imptab_delayed = lnk_import_table_alloc(config->import_table_flags);
|
||||
LNK_ExportTable *exptab = lnk_export_table_alloc();
|
||||
LNK_ObjList obj_list = {0};
|
||||
LNK_LibList lib_index[LNK_InputSource_Count] = {0};
|
||||
Arena *ht_arena = arena_alloc();
|
||||
@@ -3570,10 +3615,17 @@ lnk_run(int argc, char **argv)
|
||||
//
|
||||
lnk_merge_directive_list_push(scratch.arena, &config->merge_list, (LNK_MergeDirective){ str8_lit_comp(".xdata"), str8_lit_comp(".rdata") });
|
||||
lnk_merge_directive_list_push(scratch.arena, &config->merge_list, (LNK_MergeDirective){ str8_lit_comp(".tls"), str8_lit_comp(".data") });
|
||||
lnk_merge_directive_list_push(scratch.arena, &config->merge_list, (LNK_MergeDirective){ str8_lit_comp(".edata"), str8_lit_comp(".rdata") });
|
||||
//lnk_merge_directive_list_push(scratch.arena, &config->merge_list, (LNK_MergeDirective){ str8_lit_comp(".edata"), str8_lit_comp(".rdata") });
|
||||
lnk_merge_directive_list_push(scratch.arena, &config->merge_list, (LNK_MergeDirective){ str8_lit_comp(".idata"), str8_lit_comp(".rdata") });
|
||||
lnk_merge_directive_list_push(scratch.arena, &config->merge_list, (LNK_MergeDirective){ str8_lit_comp(".didat"), str8_lit_comp(".didat") });
|
||||
lnk_merge_directive_list_push(scratch.arena, &config->merge_list, (LNK_MergeDirective){ str8_lit_comp(".RAD_LINKER_DEBUG_DIR"), str8_lit_comp(".rdata") });
|
||||
|
||||
//
|
||||
// Push config exports
|
||||
//
|
||||
for (LNK_ExportParseNode *exp_n = config->export_symbol_list.first; exp_n != 0; exp_n = exp_n->next) {
|
||||
lnk_push_export(scratch.arena, export_ht, &export_symbol_list, &include_symbol_list, exp_n->data);
|
||||
}
|
||||
|
||||
ProfBegin("Image"); // :EndImage
|
||||
lnk_timer_begin(LNK_Timer_Image);
|
||||
@@ -3792,14 +3844,11 @@ lnk_run(int argc, char **argv)
|
||||
|
||||
// /EXPORT
|
||||
{
|
||||
LNK_ExportParseList obj_exports = {0};
|
||||
for (LNK_Directive *dir = directive_info.v[LNK_CmdSwitch_Export].first; dir != 0; dir = dir->next) {
|
||||
lnk_parse_export_directive(scratch.arena, &obj_exports, dir->value_list, obj->path, obj->lib_path);
|
||||
LNK_ExportParse export_parse = {0};
|
||||
lnk_parse_export_directive_ex(scratch.arena, dir->value_list, obj->path, obj->lib_path, &export_parse);
|
||||
lnk_push_export(scratch.arena, export_ht, &export_symbol_list, &include_symbol_list, export_parse);
|
||||
}
|
||||
for (LNK_ExportParse *exp = obj_exports.first; exp != 0; exp = exp->next) {
|
||||
str8_list_push(scratch.arena, &include_symbol_list, exp->name);
|
||||
}
|
||||
lnk_export_parse_list_concat_in_place(&export_symbol_list, &obj_exports);
|
||||
}
|
||||
|
||||
// /INCLUDESYMBOL
|
||||
@@ -4145,7 +4194,7 @@ lnk_run(int argc, char **argv)
|
||||
case State_ReportUnresolvedSymbols: {
|
||||
// report unresolved symbols
|
||||
for (LNK_SymbolNode *node = unresolved_undef_list.first; node != 0; node = node->next) {
|
||||
lnk_error(LNK_Error_UnresolvedSymbol, "unresolved symbol %S", node->data->name);
|
||||
lnk_error_obj(LNK_Error_UnresolvedSymbol, node->data->u.undef.obj, "unresolved symbol %S", node->data->name);
|
||||
}
|
||||
if (unresolved_undef_list.count) {
|
||||
goto exit;
|
||||
@@ -4179,14 +4228,52 @@ lnk_run(int argc, char **argv)
|
||||
if (export_symbol_list.count) {
|
||||
ProfBegin("Build Export Table");
|
||||
|
||||
ProfBeginV("Push Exports [Count %u]", export_symbol_list.count);
|
||||
for (LNK_ExportParse *exp_parse = export_symbol_list.first; exp_parse != 0; exp_parse = exp_parse->next) {
|
||||
lnk_export_table_push_export(exptab, symtab, exp_parse);
|
||||
}
|
||||
ProfEnd();
|
||||
LNK_ExportParseList resolved_exports = {0};
|
||||
for (LNK_ExportParseNode *exp_n = export_symbol_list.first, *exp_n_next; exp_n != 0; exp_n = exp_n_next) {
|
||||
exp_n_next = exp_n->next;
|
||||
LNK_ExportParse *exp = &exp_n->data;
|
||||
|
||||
LNK_InputObjList export_objs = lnk_export_table_serialize(scratch.arena, exptab, str8_skip_last_slash(config->image_name), config->machine);
|
||||
lnk_input_obj_list_concat_in_place(&input_obj_list, &export_objs);
|
||||
if (!exp->is_forwarder) {
|
||||
// filter out unresolved exports
|
||||
LNK_Symbol *symbol = lnk_symbol_table_search(symtab, LNK_SymbolScope_Defined, exp_n->data.name);
|
||||
if (symbol == 0) {
|
||||
lnk_error_with_loc(LNK_Warning_IllExport, exp->obj_path, exp->lib_path, "unresolved export symbol %S\n", exp->name);
|
||||
continue;
|
||||
}
|
||||
|
||||
// check export type
|
||||
switch (exp->type) {
|
||||
case COFF_ImportHeader_Code: {
|
||||
COFF_ParsedSymbol defn = lnk_parsed_symbol_from_coff_symbol_idx(symbol->u.defined.obj, symbol->u.defined.symbol_idx);
|
||||
B32 is_export_data = !COFF_SymbolType_IsFunc(defn.type);
|
||||
if (is_export_data) {
|
||||
lnk_error_with_loc(LNK_Warning_IllExport, exp->obj_path, exp->lib_path, "export \"%S\" is DATA but has type CODE", exp->name);
|
||||
}
|
||||
} break;
|
||||
case COFF_ImportHeader_Data: {
|
||||
COFF_ParsedSymbol defn = lnk_parsed_symbol_from_coff_symbol_idx(symbol->u.defined.obj, symbol->u.defined.symbol_idx);
|
||||
B32 is_export_code = COFF_SymbolType_IsFunc(defn.type);
|
||||
if (is_export_code) {
|
||||
lnk_error_with_loc(LNK_Warning_IllExport, exp->obj_path, exp->lib_path, "export \"%S\" is CODE but has type DATA", exp->name);
|
||||
}
|
||||
} break;
|
||||
case COFF_ImportHeader_Const: {
|
||||
lnk_not_implemented("TODO: COFF_ImportHeader_Const");
|
||||
} break;
|
||||
default: { InvalidPath; } break;
|
||||
}
|
||||
}
|
||||
|
||||
// push resolved export
|
||||
lnk_export_parse_list_push_node(&resolved_exports, exp_n);
|
||||
}
|
||||
|
||||
String8 edata_obj = lnk_make_edata_obj(scratch.arena, symtab, str8_skip_last_slash(config->image_name), config->machine, resolved_exports);
|
||||
|
||||
LNK_InputObj *input = lnk_input_obj_list_push(scratch.arena, &input_obj_list);
|
||||
input->path = str8_lit("* Exports *");
|
||||
input->dedup_id = input->path;
|
||||
input->data = edata_obj;
|
||||
|
||||
ProfEnd();
|
||||
}
|
||||
@@ -4309,7 +4396,7 @@ lnk_run(int argc, char **argv)
|
||||
} break;
|
||||
case State_BuildImage: {
|
||||
// build image
|
||||
image_data = lnk_build_win32_image(tp_arena, tp, config, symtab, exptab, obj_list);
|
||||
image_data = lnk_build_win32_image(tp_arena, tp, config, symtab, obj_list);
|
||||
|
||||
// write image to disk in a background thread
|
||||
{
|
||||
@@ -4343,7 +4430,7 @@ lnk_run(int argc, char **argv)
|
||||
case State_BuildImpLib: {
|
||||
ProfBegin("Build Imp Lib");
|
||||
lnk_timer_begin(LNK_Timer_Lib);
|
||||
String8List lib_list = lnk_build_import_lib(tp_arena->v[0], config->machine, config->time_stamp, config->image_name, exptab);
|
||||
String8List lib_list = lnk_build_import_lib(tp_arena->v[0], config->machine, config->time_stamp, config->image_name, export_symbol_list);
|
||||
lnk_write_data_list_to_file_path(config->imp_lib_name, str8_zero(), lib_list);
|
||||
lnk_timer_end(LNK_Timer_Lib);
|
||||
ProfEnd();
|
||||
|
||||
+3
-3
@@ -187,14 +187,14 @@ internal void lnk_queue_lib_member_input(Arena *arena, PathStyle pat
|
||||
|
||||
// --- Win32 Image -------------------------------------------------------------
|
||||
|
||||
internal String8List lnk_build_guard_tables(TP_Context *tp, LNK_SectionTable *sectab, LNK_SymbolTable *symtab, LNK_ExportTable *exptab, U64 objs_count, LNK_Obj **objs, COFF_MachineType machine, String8 entry_point_name, LNK_GuardFlags guard_flags, B32 emit_suppress_flag);
|
||||
internal String8List lnk_build_guard_tables(TP_Context *tp, LNK_SectionTable *sectab, LNK_SymbolTable *symtab, U64 objs_count, LNK_Obj **objs, COFF_MachineType machine, String8 entry_point_name, LNK_GuardFlags guard_flags, B32 emit_suppress_flag);
|
||||
internal String8List lnk_build_base_relocs(TP_Context *tp, TP_Arena *tp_temp, LNK_Config *config, U64 objs_count, LNK_Obj **objs);
|
||||
internal String8List lnk_build_win32_image_header(Arena *arena, LNK_SymbolTable *symtab, LNK_Config *config, LNK_SectionArray sect_arr, U64 expected_image_header_size);
|
||||
internal String8 lnk_build_win32_image(TP_Arena *arena, TP_Context *tp, LNK_Config *config, LNK_SymbolTable *symtab, LNK_ExportTable *exptab, LNK_ObjList obj_list);
|
||||
internal String8 lnk_build_win32_image(TP_Arena *arena, TP_Context *tp, LNK_Config *config, LNK_SymbolTable *symtab, LNK_ObjList obj_list);
|
||||
|
||||
// --- Import Lib --------------------------------------------------------------
|
||||
|
||||
internal String8List lnk_build_import_lib(Arena *arena, COFF_MachineType machine, COFF_TimeStamp time_stamp, String8 dll_name, LNK_ExportTable *exptab);
|
||||
internal String8List lnk_build_import_lib(Arena *arena, COFF_MachineType machine, COFF_TimeStamp time_stamp, String8 dll_name, LNK_ExportParseList export_list);
|
||||
|
||||
// --- Logger ------------------------------------------------------------------
|
||||
|
||||
|
||||
+6
-63
@@ -801,72 +801,13 @@ lnk_parse_alt_name_directive_list(Arena *arena, String8List list, LNK_AltNameLis
|
||||
return 0;
|
||||
}
|
||||
|
||||
internal void
|
||||
lnk_export_parse_list_concat_in_place(LNK_ExportParseList *list, LNK_ExportParseList *to_concat)
|
||||
{
|
||||
SLLConcatInPlace(list, to_concat);
|
||||
}
|
||||
|
||||
internal LNK_ExportParse *
|
||||
lnk_parse_export_directive(Arena *arena, LNK_ExportParseList *list, String8List value_list, String8 obj_path, String8 lib_path)
|
||||
{
|
||||
ProfBeginFunction();
|
||||
Temp scratch = scratch_begin(&arena, 1);
|
||||
LNK_ExportParse *parse = 0;
|
||||
|
||||
// parse directive
|
||||
String8 name = str8_zero();
|
||||
String8 alias = str8_zero();
|
||||
String8 type = coff_string_from_import_header_type(COFF_ImportHeader_Code);
|
||||
if (value_list.node_count > 0) {
|
||||
String8List dir_split = str8_split_by_string_chars(scratch.arena, value_list.first->string, str8_lit("="), 0);
|
||||
B32 is_export_valid = value_list.node_count <= 2 && value_list.node_count > 0;
|
||||
if (is_export_valid) {
|
||||
if (dir_split.node_count > 0) {
|
||||
name = dir_split.last->string;
|
||||
}
|
||||
if (dir_split.node_count == 2) {
|
||||
alias = dir_split.first->string;
|
||||
}
|
||||
if (value_list.node_count == 2) {
|
||||
type = value_list.last->string;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// prase error check
|
||||
if (name.size == 0) {
|
||||
String8 dir = str8_list_join(scratch.arena, &value_list, 0);
|
||||
lnk_error_with_loc(LNK_Error_IllData, obj_path, lib_path, "invalid export directive \"%S\"", dir);
|
||||
goto exit;
|
||||
}
|
||||
|
||||
parse = push_array_no_zero(arena, LNK_ExportParse, 1);
|
||||
parse->next = 0;
|
||||
parse->name = name;
|
||||
parse->alias = alias;
|
||||
parse->type = type;
|
||||
|
||||
SLLQueuePush(list->first, list->last, parse);
|
||||
++list->count;
|
||||
|
||||
exit:;
|
||||
|
||||
scratch_end(scratch);
|
||||
ProfEnd();
|
||||
return parse;
|
||||
}
|
||||
|
||||
internal LNK_MergeDirectiveNode *
|
||||
lnk_merge_directive_list_push(Arena *arena, LNK_MergeDirectiveList *list, LNK_MergeDirective data)
|
||||
{
|
||||
LNK_MergeDirectiveNode *node = push_array_no_zero(arena, LNK_MergeDirectiveNode, 1);
|
||||
node->data = data;
|
||||
node->next = 0;
|
||||
|
||||
node->data = data;
|
||||
SLLQueuePush(list->first, list->last, node);
|
||||
++list->count;
|
||||
|
||||
list->count += 1;
|
||||
return node;
|
||||
}
|
||||
|
||||
@@ -1121,8 +1062,10 @@ lnk_apply_cmd_option_to_config(Arena *arena, LNK_Config *config, String8 cmd_nam
|
||||
} break;
|
||||
|
||||
case LNK_CmdSwitch_Export: {
|
||||
String8List value_strings_copy = str8_list_copy(arena, &value_strings);
|
||||
lnk_parse_export_directive(arena, &config->export_symbol_list, value_strings_copy, obj_path, lib_path);
|
||||
LNK_ExportParse export_parse = {0};
|
||||
if (lnk_parse_export_directive_ex(arena, value_strings, obj_path, lib_path, &export_parse)) {
|
||||
lnk_export_parse_list_push(arena, &config->export_symbol_list, export_parse);
|
||||
}
|
||||
} break;
|
||||
|
||||
case LNK_CmdSwitch_FastFail: {
|
||||
|
||||
+2
-18
@@ -238,21 +238,6 @@ typedef struct LNK_AltNameList
|
||||
String8List to_list;
|
||||
} LNK_AltNameList;
|
||||
|
||||
typedef struct LNK_ExportParse
|
||||
{
|
||||
String8 name;
|
||||
String8 alias;
|
||||
String8 type;
|
||||
struct LNK_ExportParse *next;
|
||||
} LNK_ExportParse;
|
||||
|
||||
typedef struct LNK_ExportParseList
|
||||
{
|
||||
U64 count;
|
||||
LNK_ExportParse *first;
|
||||
LNK_ExportParse *last;
|
||||
} LNK_ExportParseList;
|
||||
|
||||
typedef struct LNK_MergeDirective
|
||||
{
|
||||
String8 src;
|
||||
@@ -573,10 +558,9 @@ internal void lnk_alt_name_list_concat_in_place(LNK_AltNameList *list, LNK_
|
||||
internal B32 lnk_parse_alt_name_directive (Arena *arena, String8 input, LNK_AltNameList *list_out);
|
||||
internal String8 * lnk_parse_alt_name_directive_list(Arena *arena, String8List list, LNK_AltNameList *list_out);
|
||||
|
||||
internal LNK_ExportParse * lnk_parse_export_directive(Arena *arena, LNK_ExportParseList *list, String8List value_list, String8 obj_path, String8 lib_path);
|
||||
|
||||
internal LNK_MergeDirectiveNode * lnk_merge_directive_list_push(Arena *arena, LNK_MergeDirectiveList *list, LNK_MergeDirective data);
|
||||
internal B32 lnk_parse_merge_directive(String8 string, LNK_MergeDirective *out);
|
||||
|
||||
internal B32 lnk_parse_merge_directive(String8 string, LNK_MergeDirective *parse_out);
|
||||
|
||||
////////////////////////////////
|
||||
|
||||
|
||||
+347
-244
@@ -1,303 +1,406 @@
|
||||
// Copyright (c) 2025 Epic Games Tools
|
||||
// Licensed under the MIT license (https://opensource.org/license/mit/)
|
||||
|
||||
int
|
||||
lnk_export_name_compar(const void *a_, const void *b_)
|
||||
internal String8
|
||||
lnk_name_from_export_parse(LNK_ExportParse *exp)
|
||||
{
|
||||
const LNK_Export *a = (const LNK_Export *)a_;
|
||||
const LNK_Export *b = (const LNK_Export *)b_;
|
||||
return str8_compar_case_sensitive(&a->name, &b->name);
|
||||
String8 name;
|
||||
if (exp->is_forwarder) {
|
||||
name = exp->alias;
|
||||
} else if (exp->alias.size) {
|
||||
name = exp->alias;
|
||||
} else {
|
||||
name = exp->name;
|
||||
}
|
||||
return name;
|
||||
}
|
||||
|
||||
int
|
||||
lnk_export_ordinal_compar(const void *a_, const void *b_)
|
||||
{
|
||||
const LNK_Export *a = (const LNK_Export *)a_;
|
||||
const LNK_Export *b = (const LNK_Export *)b_;
|
||||
int cmp = u16_compar(&a->ordinal, &b->ordinal);
|
||||
return cmp;
|
||||
}
|
||||
|
||||
internal LNK_ExportTable *
|
||||
lnk_export_table_alloc(void)
|
||||
internal B32
|
||||
lnk_parse_export_directive_ex(Arena *arena, String8List directive, String8 obj_path, String8 lib_path, LNK_ExportParse *export_out)
|
||||
{
|
||||
ProfBeginFunction();
|
||||
Arena *arena = arena_alloc();
|
||||
Temp scratch = scratch_begin(&arena, 1);
|
||||
B32 is_parsed = 0;
|
||||
|
||||
LNK_ExportTable *exptab = push_array(arena, LNK_ExportTable, 1);
|
||||
exptab->arena = arena;
|
||||
exptab->voff_size = sizeof(U32);
|
||||
exptab->max_ordinal = max_U16;
|
||||
exptab->is_ordinal_used = push_array(arena, B8, exptab->max_ordinal);
|
||||
exptab->name_export_ht = hash_table_init(arena, 0x10000);
|
||||
exptab->noname_export_ht = hash_table_init(arena, 0x100);
|
||||
// parse "alias=name"
|
||||
String8 name = {0};
|
||||
String8 alias = {0};
|
||||
String8List flags = {0};
|
||||
{
|
||||
String8List alias_name_split = str8_split_by_string_chars(scratch.arena, directive.first->string, str8_lit("="), 0);
|
||||
if (alias_name_split.node_count == 2) {
|
||||
alias = alias_name_split.first->string;
|
||||
name = alias_name_split.last->string;
|
||||
} else if (alias_name_split.node_count == 1) {
|
||||
name = alias_name_split.first->string;
|
||||
} else {
|
||||
String8 d = str8_list_join(scratch.arena, &directive, &(StringJoin){.sep=str8_lit(",")});
|
||||
lnk_error_with_loc(LNK_Error_IllExport, obj_path, lib_path, "invalid export directive \"/EXPORT:%S\"", d);
|
||||
goto exit;
|
||||
}
|
||||
|
||||
flags = directive;
|
||||
str8_list_pop_front(&flags);
|
||||
}
|
||||
|
||||
// discard alias to itself
|
||||
if (str8_match(name, alias, 0)) {
|
||||
alias = str8_zero();
|
||||
}
|
||||
|
||||
// does directive have ordinal?
|
||||
U16 ordinal16 = 0;
|
||||
String8 ordinal = {0};
|
||||
String8 noname_flag = {0};
|
||||
if (str8_match(str8_prefix(str8_list_first(&flags), 1), str8_lit("@"), 0)) {
|
||||
// parse ordinal
|
||||
ordinal = str8_skip(str8_list_pop_front(&flags)->string, 1);
|
||||
if (str8_is_integer(ordinal, 10)) {
|
||||
U64 ordinal64 = u64_from_str8(ordinal, 10);
|
||||
if (ordinal64 <= max_U16) {
|
||||
ordinal16 = (U16)ordinal64;
|
||||
} else {
|
||||
String8 d = str8_list_join(scratch.arena, &directive, &(StringJoin){.sep=str8_lit(",")});
|
||||
lnk_error_with_loc(LNK_Error_IllExport, obj_path, lib_path, "ordinal value must fit into 16-bit integer, \"/EXPORT:%S\"", d);
|
||||
goto exit;
|
||||
}
|
||||
} else {
|
||||
String8 d = str8_list_join(scratch.arena, &directive, &(StringJoin){.sep=str8_lit(",")});
|
||||
lnk_error_with_loc(LNK_Error_IllExport, obj_path, lib_path, "invalid export directive \"/EXPORT:%S\"", d);
|
||||
goto exit;
|
||||
}
|
||||
|
||||
// detect NONAME flag
|
||||
if (str8_match(str8_list_first(&flags), str8_lit("NONAME"), StringMatchFlag_CaseInsensitive)) {
|
||||
noname_flag = str8_list_pop_front(&flags)->string;
|
||||
}
|
||||
}
|
||||
|
||||
// detect PRIVATE flag
|
||||
String8 private_flag = {0};
|
||||
if (str8_match(str8_list_first(&flags), str8_lit("PRIVATE"), StringMatchFlag_CaseInsensitive)) {
|
||||
private_flag = str8_list_pop_front(&flags)->string;
|
||||
}
|
||||
|
||||
// parse export type
|
||||
COFF_ImportType type = COFF_ImportHeader_Code;
|
||||
if (flags.node_count) {
|
||||
type = coff_import_header_type_from_string(str8_list_pop_front(&flags)->string);
|
||||
if (type == COFF_ImportType_Invalid) {
|
||||
String8 d = str8_list_join(scratch.arena, &directive, &(StringJoin){.sep=str8_lit(",")});
|
||||
lnk_error_with_loc(LNK_Error_IllExport, obj_path, lib_path, "invalid export directive \"/EXPORT:%S\"", d);
|
||||
goto exit;
|
||||
}
|
||||
}
|
||||
|
||||
// are there leftover nodes?
|
||||
if (flags.node_count != 0) {
|
||||
String8 d = str8_list_join(scratch.arena, &directive, &(StringJoin){.sep=str8_lit(",")});
|
||||
lnk_error_with_loc(LNK_Error_IllExport, obj_path, lib_path, "invalid export directive \"/EXPORT:%S\"", d);
|
||||
goto exit;
|
||||
}
|
||||
|
||||
// fill out export
|
||||
export_out->obj_path = obj_path;
|
||||
export_out->lib_path = lib_path;
|
||||
export_out->name = push_str8_copy(arena, name);
|
||||
export_out->alias = push_str8_copy(arena, alias);
|
||||
export_out->type = type;
|
||||
export_out->ordinal = ordinal16;
|
||||
export_out->is_ordinal_assigned = ordinal.size > 0;
|
||||
export_out->is_noname_present = noname_flag.size > 0;
|
||||
export_out->is_private = private_flag.size > 0;
|
||||
export_out->is_forwarder = str8_find_needle(name, 0, str8_lit("."), 0) < name.size;
|
||||
|
||||
is_parsed = 1;
|
||||
|
||||
exit:;
|
||||
scratch_end(scratch);
|
||||
ProfEnd();
|
||||
return exptab;
|
||||
return is_parsed;
|
||||
}
|
||||
|
||||
internal B32
|
||||
lnk_parse_export_directive(Arena *arena, String8 directive, String8 obj_path, String8 lib_path, LNK_ExportParse *export_out)
|
||||
{
|
||||
Temp scratch = scratch_begin(&arena, 1);
|
||||
String8List split_directive = str8_split_by_string_chars(scratch.arena, directive, str8_lit(","), 0);
|
||||
B32 is_parsed = lnk_parse_export_directive_ex(arena, split_directive, obj_path, lib_path, export_out);
|
||||
scratch_end(scratch);
|
||||
return is_parsed;
|
||||
}
|
||||
|
||||
internal LNK_ExportParsePtrArray
|
||||
lnk_array_from_export_list(Arena *arena, LNK_ExportParseList list)
|
||||
{
|
||||
LNK_ExportParsePtrArray result = {0};
|
||||
result.v = push_array_no_zero(arena, LNK_ExportParse *, list.count);
|
||||
for (LNK_ExportParseNode *exp = list.first; exp != 0; exp = exp->next) {
|
||||
result.v[result.count++] = &exp->data;
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
internal void
|
||||
lnk_export_table_release(LNK_ExportTable **exptab_ptr)
|
||||
lnk_export_parse_list_push_node(LNK_ExportParseList *list, LNK_ExportParseNode *node)
|
||||
{
|
||||
ProfBeginFunction();
|
||||
arena_release((*exptab_ptr)->arena);
|
||||
*exptab_ptr = NULL;
|
||||
ProfEnd();
|
||||
SLLQueuePush(list->first, list->last, node);
|
||||
list->count += 1;
|
||||
}
|
||||
|
||||
internal LNK_Export *
|
||||
lnk_export_table_search(LNK_ExportTable *exptab, String8 name)
|
||||
internal LNK_ExportParseNode *
|
||||
lnk_export_parse_list_push(Arena *arena, LNK_ExportParseList *list, LNK_ExportParse data)
|
||||
{
|
||||
KeyValuePair *kv = hash_table_search_string(exptab->name_export_ht, name);
|
||||
if (kv) {
|
||||
return kv->value_raw;
|
||||
}
|
||||
return 0;
|
||||
LNK_ExportParseNode *node = push_array(arena, LNK_ExportParseNode, 1);
|
||||
node->data = data;
|
||||
lnk_export_parse_list_push_node(list, node);
|
||||
return node;
|
||||
}
|
||||
|
||||
internal LNK_Export *
|
||||
lnk_export_table_push_export(LNK_ExportTable *exptab, LNK_SymbolTable *symtab, LNK_ExportParse *exp_parse)
|
||||
internal void
|
||||
lnk_export_parse_list_concat_in_place(LNK_ExportParseList *list, LNK_ExportParseList *to_concat)
|
||||
{
|
||||
LNK_Export *exp = 0;
|
||||
|
||||
// get export symbol
|
||||
LNK_Symbol *symbol = lnk_symbol_table_search(symtab, LNK_SymbolScope_Defined, exp_parse->name);
|
||||
if (symbol == 0) {
|
||||
lnk_error(LNK_Warning_IllExport, "symbol \"%S\" for export doesn't exist", exp_parse->name);
|
||||
goto exit;
|
||||
}
|
||||
if (symbol->type != LNK_Symbol_Defined) {
|
||||
lnk_error(LNK_Warning_IllExport, "unable to resolve symbol \"%S\" for export", exp_parse->name);
|
||||
goto exit;
|
||||
}
|
||||
|
||||
// NOTE: It is possible to export a global variable as CODE
|
||||
// with following snippet:
|
||||
// int global_bar = 0;
|
||||
// #pragma comment(linker, "/export:global_bar")
|
||||
// for some reason MSVC and LLD don't check symbol type and default
|
||||
// to CODE instead of DATA. But if you try export global variable with:
|
||||
// #pragma comment(linker, "/export:global_bar,CODE")
|
||||
// MSVC and LLD issue an error. For compatibility sake we do the same thing too.
|
||||
COFF_ImportType type = coff_import_header_type_from_string(exp_parse->type);
|
||||
switch (type) {
|
||||
case COFF_ImportHeader_Code: {
|
||||
COFF_ParsedSymbol defn = lnk_parsed_symbol_from_coff_symbol_idx(symbol->u.defined.obj, symbol->u.defined.symbol_idx);
|
||||
B32 is_export_data = !COFF_SymbolType_IsFunc(defn.type);
|
||||
if (is_export_data) {
|
||||
lnk_error(LNK_Error_IllExport, "export \"%S\" is DATA but has specifier CODE", exp_parse->name);
|
||||
}
|
||||
} break;
|
||||
case COFF_ImportHeader_Data: {
|
||||
COFF_ParsedSymbol defn = lnk_parsed_symbol_from_coff_symbol_idx(symbol->u.defined.obj, symbol->u.defined.symbol_idx);
|
||||
B32 is_export_code = COFF_SymbolType_IsFunc(defn.type);
|
||||
if (is_export_code) {
|
||||
lnk_error(LNK_Error_IllExport, "export \"%S\" is CODE but has specifier DATA", exp_parse->name);
|
||||
}
|
||||
} break;
|
||||
case COFF_ImportHeader_Const: {
|
||||
lnk_not_implemented("TODO: COFF_ImportHeader_Const");
|
||||
} break;
|
||||
default: {
|
||||
if (exp_parse->type.size) {
|
||||
lnk_error(LNK_Error_IllExport, "invalid type \"%S\" for export \"%S\"", exp_parse->type, exp_parse->name);
|
||||
}
|
||||
} break;
|
||||
}
|
||||
|
||||
// error check multiple def
|
||||
exp = lnk_export_table_search(exptab, exp_parse->alias);
|
||||
if (exp) {
|
||||
if (exp->type != type) {
|
||||
lnk_error(LNK_Warning_IllExport, "trying to rexport symbol \"%S\"", exp_parse->alias);
|
||||
}
|
||||
goto exit;
|
||||
}
|
||||
exp = lnk_export_table_search(exptab, exp_parse->name);
|
||||
if (exp) {
|
||||
if (exp->type != type) {
|
||||
lnk_error(LNK_Warning_IllExport, "multiple export definition for \"%S\"", exp_parse->name);
|
||||
}
|
||||
goto exit;
|
||||
}
|
||||
|
||||
|
||||
// find free ordinal
|
||||
U16 ordinal;
|
||||
for (ordinal = 0; ordinal < exptab->max_ordinal; ++ordinal) {
|
||||
if (!exptab->is_ordinal_used[ordinal]) {
|
||||
exptab->is_ordinal_used[ordinal] = 1;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
// ordinal alloc error check
|
||||
if (ordinal >= exptab->max_ordinal) {
|
||||
lnk_error(LNK_Error_OutOfExportOrdinals, "reached export limit of %u, discarding export %S", exptab->max_ordinal, exp_parse->name);
|
||||
goto exit;
|
||||
}
|
||||
|
||||
|
||||
// fill out export
|
||||
exp = push_array_no_zero(exptab->arena, LNK_Export, 1);
|
||||
exp->next = 0;
|
||||
exp->name = push_str8_copy(exptab->arena, exp_parse->alias.size > 0 ? exp_parse->alias : exp_parse->name);
|
||||
exp->symbol = symbol;
|
||||
exp->id = exptab->name_export_ht->count;
|
||||
exp->ordinal = ordinal;
|
||||
exp->type = type;
|
||||
exp->is_private = 0; // exports through directives are public
|
||||
|
||||
hash_table_push_string_raw(exptab->arena, exptab->name_export_ht, exp->name, exp);
|
||||
|
||||
exit:;
|
||||
return exp;
|
||||
SLLConcatInPlace(list, to_concat);
|
||||
}
|
||||
|
||||
internal LNK_ExportArray
|
||||
lnk_export_array_from_list(Arena *arena, LNK_ExportList list)
|
||||
internal int
|
||||
lnk_named_export_is_before(void *raw_a, void *raw_b)
|
||||
{
|
||||
ProfBeginFunction();
|
||||
LNK_ExportArray arr;
|
||||
arr.count = 0;
|
||||
arr.v = push_array_no_zero(arena, LNK_Export, list.count);
|
||||
for (LNK_Export *exp = list.first; exp != NULL; exp = exp->next) {
|
||||
arr.v[arr.count++] = *exp;
|
||||
}
|
||||
ProfEnd();
|
||||
return arr;
|
||||
LNK_ExportParse *a = *(LNK_ExportParse **)raw_a;
|
||||
LNK_ExportParse *b = *(LNK_ExportParse **)raw_b;
|
||||
int cmp = str8_compar_case_sensitive(&a->name, &b->name);
|
||||
return cmp < 0;
|
||||
}
|
||||
|
||||
internal LNK_InputObjList
|
||||
lnk_export_table_serialize(Arena *arena, LNK_ExportTable *exptab, String8 image_name, COFF_MachineType machine)
|
||||
internal int
|
||||
lnk_ordinal_export_is_before(void *raw_a, void *raw_b)
|
||||
{
|
||||
LNK_ExportParse *a = raw_a;
|
||||
LNK_ExportParse *b = raw_b;
|
||||
return a->ordinal < b->ordinal;
|
||||
}
|
||||
|
||||
internal String8
|
||||
lnk_make_edata_obj(Arena *arena,
|
||||
LNK_SymbolTable *symtab,
|
||||
String8 image_name,
|
||||
COFF_MachineType machine,
|
||||
LNK_ExportParseList export_list)
|
||||
{
|
||||
Temp scratch = scratch_begin(&arena, 1);
|
||||
|
||||
// compute ordinal bounds
|
||||
U64 ordinal_low;
|
||||
for (ordinal_low = 0; ordinal_low < exptab->max_ordinal; ++ordinal_low) {
|
||||
if (exptab->is_ordinal_used[ordinal_low]) {
|
||||
break;
|
||||
// compute max ordinal and used ordinal flag array
|
||||
U64 ordinal_low = max_U64;
|
||||
B8 *is_ordinal_used = push_array(arena, B8, max_U16);
|
||||
for (LNK_ExportParseNode *exp_n = export_list.first; exp_n != 0; exp_n = exp_n->next) {
|
||||
LNK_ExportParse *exp = &exp_n->data;
|
||||
if (exp->is_ordinal_assigned) {
|
||||
ordinal_low = Min(ordinal_low, exp->ordinal);
|
||||
is_ordinal_used[exp->ordinal] = 1;
|
||||
}
|
||||
}
|
||||
U64 ordinal_high;
|
||||
for (ordinal_high = exptab->max_ordinal - 1; ordinal_high > 0; --ordinal_high) {
|
||||
if (exptab->is_ordinal_used[ordinal_high]) {
|
||||
break;
|
||||
|
||||
LNK_ExportParsePtrArray named_exports = {0};
|
||||
LNK_ExportParsePtrArray noname_exports = {0};
|
||||
LNK_ExportParsePtrArray forwarder_exports = {0};
|
||||
{
|
||||
// group exports based on flags
|
||||
LNK_ExportParseList named_exports_list = {0};
|
||||
LNK_ExportParseList noname_exports_list = {0};
|
||||
LNK_ExportParseList forwarder_exports_list = {0};
|
||||
for (LNK_ExportParseNode *exp_n = export_list.first, *exp_n_next; exp_n != 0; exp_n = exp_n_next) {
|
||||
exp_n_next = exp_n->next;
|
||||
if (exp_n->data.is_forwarder) {
|
||||
lnk_export_parse_list_push_node(&forwarder_exports_list, exp_n);
|
||||
} else if (exp_n->data.is_noname_present) {
|
||||
AssertAlways(exp_n->data.is_ordinal_assigned);
|
||||
lnk_export_parse_list_push_node(&noname_exports_list, exp_n);
|
||||
} else {
|
||||
lnk_export_parse_list_push_node(&named_exports_list, exp_n);
|
||||
}
|
||||
}
|
||||
|
||||
// list -> array
|
||||
named_exports = lnk_array_from_export_list(scratch.arena, named_exports_list);
|
||||
noname_exports = lnk_array_from_export_list(scratch.arena, noname_exports_list);
|
||||
forwarder_exports = lnk_array_from_export_list(scratch.arena, forwarder_exports_list);
|
||||
|
||||
// sort exports
|
||||
radsort(named_exports.v, named_exports.count, lnk_named_export_is_before);
|
||||
radsort(noname_exports.v, noname_exports.count, lnk_ordinal_export_is_before);
|
||||
radsort(forwarder_exports.v, forwarder_exports.count, lnk_named_export_is_before);
|
||||
|
||||
MemoryZeroStruct(&export_list);
|
||||
lnk_export_parse_list_concat_in_place(&export_list, &named_exports_list);
|
||||
lnk_export_parse_list_concat_in_place(&export_list, &forwarder_exports_list);
|
||||
lnk_export_parse_list_concat_in_place(&export_list, &noname_exports_list);
|
||||
}
|
||||
|
||||
// assign omitted ordinals
|
||||
{
|
||||
U16 last_ordinal = ordinal_low;
|
||||
for (U64 exp_idx = 0; exp_idx < named_exports.count; exp_idx += 1) {
|
||||
LNK_ExportParse *exp = named_exports.v[exp_idx];
|
||||
if (!exp->is_ordinal_assigned) {
|
||||
for (; last_ordinal < max_U16 && is_ordinal_used[last_ordinal] != 0; last_ordinal += 1);
|
||||
exp->ordinal = last_ordinal;
|
||||
exp->is_ordinal_assigned = 1;
|
||||
is_ordinal_used[last_ordinal] = 1;
|
||||
}
|
||||
}
|
||||
for (U64 exp_idx = 0; exp_idx < forwarder_exports.count; exp_idx += 1) {
|
||||
LNK_ExportParse *exp = forwarder_exports.v[exp_idx];
|
||||
if (!exp->is_ordinal_assigned) {
|
||||
for (; last_ordinal < max_U16 && is_ordinal_used[last_ordinal] != 0; last_ordinal += 1);
|
||||
exp->ordinal = last_ordinal;
|
||||
exp->is_ordinal_assigned = 1;
|
||||
is_ordinal_used[last_ordinal] = 1;
|
||||
}
|
||||
}
|
||||
for (U64 exp_idx = 0; exp_idx < noname_exports.count; exp_idx += 1) {
|
||||
LNK_ExportParse *exp = noname_exports.v[exp_idx];
|
||||
if (!exp->is_ordinal_assigned) {
|
||||
exp->ordinal = last_ordinal;
|
||||
exp->is_ordinal_assigned = 1;
|
||||
is_ordinal_used[last_ordinal] = 1;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
COFF_ObjWriter *obj_writer = coff_obj_writer_alloc(COFF_TimeStamp_Max, machine);
|
||||
|
||||
// fill out export table header
|
||||
PE_ExportTableHeader *header = push_array(obj_writer->arena, PE_ExportTableHeader, 1);
|
||||
header->ordinal_base = safe_cast_u16(ordinal_low + 1);
|
||||
header->export_address_table_count = safe_cast_u32(exptab->name_export_ht->count + exptab->noname_export_ht->count);
|
||||
header->name_pointer_table_count = safe_cast_u32(exptab->name_export_ht->count);
|
||||
|
||||
|
||||
// make iamge name c-string
|
||||
String8 image_name_cstr = push_cstr(obj_writer->arena, image_name);
|
||||
|
||||
// push sections
|
||||
COFF_ObjSection *header_sect = coff_obj_writer_push_section(obj_writer, str8_lit(".edata$1"), LNK_EDATA_SECTION_FLAGS, str8_struct(header));
|
||||
COFF_ObjSection *voff_table_sect = coff_obj_writer_push_section(obj_writer, str8_lit(".edata$2"), LNK_EDATA_SECTION_FLAGS, str8_zero());
|
||||
COFF_ObjSection *name_voff_table_sect = coff_obj_writer_push_section(obj_writer, str8_lit(".edata$3"), LNK_EDATA_SECTION_FLAGS, str8_zero());
|
||||
COFF_ObjSection *ordinal_table_sect = coff_obj_writer_push_section(obj_writer, str8_lit(".edata$4"), LNK_EDATA_SECTION_FLAGS, str8_zero());
|
||||
COFF_ObjSection *string_buffer_sect = coff_obj_writer_push_section(obj_writer, str8_lit(".edata$5"), LNK_EDATA_SECTION_FLAGS, str8_zero());
|
||||
COFF_ObjSection *image_name_sect = coff_obj_writer_push_section(obj_writer, str8_lit(".edata$6"), LNK_EDATA_SECTION_FLAGS, image_name_cstr);
|
||||
COFF_ObjSection *voff_table_sect = coff_obj_writer_push_section(obj_writer, str8_lit(".edata$2"), LNK_EDATA_SECTION_FLAGS|COFF_SectionFlag_Align4Bytes, str8_zero());
|
||||
COFF_ObjSection *name_voff_table_sect = coff_obj_writer_push_section(obj_writer, str8_lit(".edata$3"), LNK_EDATA_SECTION_FLAGS|COFF_SectionFlag_Align4Bytes, str8_zero());
|
||||
COFF_ObjSection *ordinal_table_sect = coff_obj_writer_push_section(obj_writer, str8_lit(".edata$4"), LNK_EDATA_SECTION_FLAGS|COFF_SectionFlag_Align2Bytes, str8_zero());
|
||||
COFF_ObjSection *string_table_sect = coff_obj_writer_push_section(obj_writer, str8_lit(".edata$5"), LNK_EDATA_SECTION_FLAGS|COFF_SectionFlag_Align1Bytes, str8_zero());
|
||||
COFF_ObjSection *image_name_sect = coff_obj_writer_push_section(obj_writer, str8_lit(".edata$6"), LNK_EDATA_SECTION_FLAGS|COFF_SectionFlag_Align1Bytes, push_cstr(obj_writer->arena, image_name));
|
||||
|
||||
// push symbols
|
||||
COFF_ObjSymbol *image_name_symbol = coff_obj_writer_push_symbol_static(obj_writer, str8_lit("EXPORT_TABLE_NAME_VOFF"), 0, image_name_sect);
|
||||
COFF_ObjSymbol *address_table_symbol = coff_obj_writer_push_symbol_static(obj_writer, str8_lit("EXPORT_TABLE_ADDRESS_TABLE_VOFF"), 0, voff_table_sect);
|
||||
COFF_ObjSymbol *name_table_symbol = coff_obj_writer_push_symbol_static(obj_writer, str8_lit("EXPORT_TABLE_NAME_POINTER_VOFF"), 0, name_voff_table_sect);
|
||||
COFF_ObjSymbol *ordinal_table_symbol = coff_obj_writer_push_symbol_static(obj_writer, str8_lit("EXPORT_TABLE_ORDINAL_TABLE_VOFF"), 0, ordinal_table_sect);
|
||||
ProfBegin("Virtual Offset Table");
|
||||
{
|
||||
B8 *is_ordinal_bound = push_array(scratch.arena, B8, max_U16);
|
||||
LNK_ExportParsePtrArray *all_exports[] = { &named_exports, &forwarder_exports, &noname_exports };
|
||||
|
||||
// patch export table header
|
||||
switch (machine) {
|
||||
case COFF_MachineType_Unknown: break;
|
||||
case COFF_MachineType_X64: {
|
||||
coff_obj_writer_section_push_reloc(obj_writer, header_sect, OffsetOf(PE_ExportTableHeader, name_voff), image_name_symbol, COFF_Reloc_X64_Addr32Nb);
|
||||
coff_obj_writer_section_push_reloc(obj_writer, header_sect, OffsetOf(PE_ExportTableHeader, export_address_table_voff), address_table_symbol, COFF_Reloc_X64_Addr32Nb);
|
||||
coff_obj_writer_section_push_reloc(obj_writer, header_sect, OffsetOf(PE_ExportTableHeader, name_pointer_table_voff), name_table_symbol, COFF_Reloc_X64_Addr32Nb);
|
||||
coff_obj_writer_section_push_reloc(obj_writer, header_sect, OffsetOf(PE_ExportTableHeader, ordinal_table_voff), ordinal_table_symbol, COFF_Reloc_X64_Addr32Nb);
|
||||
} break;
|
||||
default: { NotImplemented; } break;
|
||||
}
|
||||
|
||||
|
||||
B8 *is_ordinal_bound = push_array(scratch.arena, B8, exptab->max_ordinal);
|
||||
HashTable *exp_ht_arr[] = { exptab->name_export_ht, exptab->noname_export_ht };
|
||||
|
||||
for (U64 ht_idx = 0; ht_idx < ArrayCount(exp_ht_arr); ht_idx += 1) {
|
||||
HashTable *ht = exp_ht_arr[ht_idx];
|
||||
|
||||
KeyValuePair *kv_arr = key_value_pairs_from_hash_table(scratch.arena, exptab->name_export_ht);
|
||||
|
||||
// named exports must be lexically sorted
|
||||
if (ht_idx == 0) {
|
||||
sort_key_value_pairs_as_string_sensitive(kv_arr, exptab->name_export_ht->count);
|
||||
}
|
||||
|
||||
for (U64 i = 0; i < ht->count; i += 1) {
|
||||
LNK_Export *exp = kv_arr[i].value_raw;
|
||||
|
||||
{
|
||||
U64 export_name_offset = string_buffer_sect->data.total_size;
|
||||
String8 export_name_cstr = push_cstr(obj_writer->arena, exp->name);
|
||||
str8_list_push(obj_writer->arena, &string_buffer_sect->data, export_name_cstr);
|
||||
|
||||
String8 export_name_symbol_name = push_str8f(obj_writer->arena, "EXPORT.%S", exp->name);
|
||||
COFF_ObjSymbol *export_name_symbol = coff_obj_writer_push_symbol_static(obj_writer, export_name_symbol_name, export_name_offset, string_buffer_sect);
|
||||
|
||||
U64 export_name_voff_offset = name_voff_table_sect->data.total_size;
|
||||
U64 export_name_voff_size = sizeof(U32);
|
||||
U8 *export_name_voff = push_array(obj_writer->arena, U8, export_name_voff_size);
|
||||
str8_list_push(obj_writer->arena, &name_voff_table_sect->data, str8_array(export_name_voff, export_name_voff_size));
|
||||
|
||||
switch (machine) {
|
||||
case COFF_MachineType_Unknown: break;
|
||||
case COFF_MachineType_X64: { coff_obj_writer_section_push_reloc(obj_writer, name_voff_table_sect, export_name_voff_offset, export_name_symbol, COFF_Reloc_X64_Addr32Nb); } break;
|
||||
default: { NotImplemented; } break;
|
||||
}
|
||||
}
|
||||
|
||||
{
|
||||
U16 *ordinal = push_array(obj_writer->arena, U16, 1);
|
||||
*ordinal = exp->ordinal - ordinal_low;
|
||||
str8_list_push(obj_writer->arena, &ordinal_table_sect->data, str8_struct(ordinal));
|
||||
|
||||
if ( ! is_ordinal_bound[exp->ordinal]) {
|
||||
for (U64 arr_idx = 0; arr_idx < ArrayCount(all_exports); arr_idx += 1) {
|
||||
for (U64 exp_idx = 0; exp_idx < all_exports[arr_idx]->count; exp_idx += 1) {
|
||||
LNK_ExportParse *exp = all_exports[arr_idx]->v[exp_idx];
|
||||
if (is_ordinal_bound[exp->ordinal] == 0) {
|
||||
// alloc only one slot per ordinal, so it's possible to map ordinal to a virtual offset
|
||||
is_ordinal_bound[exp->ordinal] = 1;
|
||||
|
||||
// create slot for the ordinal virtual offset
|
||||
U64 voff_offset = voff_table_sect->data.total_size;
|
||||
U32 *voff = push_array(obj_writer->arena, U32, 1);
|
||||
str8_list_push(obj_writer->arena, &voff_table_sect->data, str8_struct(voff));
|
||||
|
||||
COFF_ObjSymbol *symbol = coff_obj_writer_push_symbol_undef(obj_writer, exp->name);
|
||||
switch (machine) {
|
||||
case COFF_MachineType_Unknown: break;
|
||||
case COFF_MachineType_X64: { coff_obj_writer_section_push_reloc(obj_writer, voff_table_sect, voff_offset, symbol, COFF_Reloc_X64_Addr32Nb); } break;
|
||||
default: { NotImplemented; } break;
|
||||
COFF_ObjSymbol *exp_symbol;
|
||||
if (exp->is_forwarder) {
|
||||
U64 forwarder_name_offset = string_table_sect->data.total_size;
|
||||
String8 forwarder_name_cstr = push_cstr(obj_writer->arena, exp->name);
|
||||
str8_list_push(obj_writer->arena, &string_table_sect->data, forwarder_name_cstr);
|
||||
// symbol to the name string
|
||||
exp_symbol = coff_obj_writer_push_symbol_static(obj_writer, exp->name, forwarder_name_offset, string_table_sect);
|
||||
} else {
|
||||
// function or global var symbol
|
||||
exp_symbol = coff_obj_writer_push_symbol_undef(obj_writer, exp->name);
|
||||
}
|
||||
|
||||
U16 ordinal_nb = exp->ordinal - ordinal_low;
|
||||
coff_obj_writer_section_push_reloc(obj_writer, voff_table_sect, ordinal_nb*sizeof(U32), exp_symbol, coff_virt_off_reloc_from_machine(machine));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
ProfEnd();
|
||||
|
||||
ProfBegin("Named & Forwarder Exports");
|
||||
{
|
||||
LNK_ExportParsePtrArray *exports_with_names[] = { &named_exports, &forwarder_exports };
|
||||
|
||||
// assign hints
|
||||
for (U64 arr_idx = 0, hint = 0; arr_idx < ArrayCount(exports_with_names); arr_idx += 1) {
|
||||
for (U64 exp_idx = 0; exp_idx < exports_with_names[arr_idx]->count; exp_idx += 1, hint += 1) {
|
||||
LNK_ExportParse *exp = exports_with_names[arr_idx]->v[exp_idx];
|
||||
exp->hint = hint;
|
||||
}
|
||||
}
|
||||
|
||||
for (U64 arr_idx = 0; arr_idx < ArrayCount(exports_with_names); arr_idx += 1) {
|
||||
LNK_ExportParsePtrArray *exports = exports_with_names[arr_idx];
|
||||
for (U64 exp_idx = 0; exp_idx < exports->count; exp_idx += 1) {
|
||||
LNK_ExportParse *exp = exports->v[exp_idx];
|
||||
|
||||
String8 name = lnk_name_from_export_parse(exp);
|
||||
|
||||
// store symbol name string
|
||||
U64 export_name_offset = string_table_sect->data.total_size;
|
||||
String8 export_name_cstr = push_cstr(obj_writer->arena, name);
|
||||
str8_list_push(obj_writer->arena, &string_table_sect->data, export_name_cstr);
|
||||
|
||||
// create symbol for the name string
|
||||
String8 export_name_symbol_name = push_str8f(obj_writer->arena, "RAD_NAME:%S", name);
|
||||
COFF_ObjSymbol *export_name_symbol = coff_obj_writer_push_symbol_extern(obj_writer, export_name_symbol_name, export_name_offset, string_table_sect);
|
||||
|
||||
// create slot for export virtual offset
|
||||
U64 export_name_voff_offset = name_voff_table_sect->data.total_size;
|
||||
U8 *export_name_voff = push_array(obj_writer->arena, U8, sizeof(U32));
|
||||
str8_list_push(obj_writer->arena, &name_voff_table_sect->data, str8_array(export_name_voff, sizeof(U32)));
|
||||
|
||||
// write string's virtual offset
|
||||
coff_obj_writer_section_push_reloc(obj_writer, name_voff_table_sect, export_name_voff_offset, export_name_symbol, coff_virt_off_reloc_from_machine(machine));
|
||||
|
||||
// create and store export's ordinal
|
||||
U16 *ordinal = push_array(obj_writer->arena, U16, 1);
|
||||
*ordinal = exp->ordinal - ordinal_low;
|
||||
str8_list_push(obj_writer->arena, &ordinal_table_sect->data, str8_struct(ordinal));
|
||||
}
|
||||
}
|
||||
}
|
||||
ProfEnd();
|
||||
|
||||
ProfBegin("NONAME Exports");
|
||||
{
|
||||
for (U64 exp_idx = 0; exp_idx < noname_exports.count; exp_idx += 1) {
|
||||
// create and store export's ordinal
|
||||
LNK_ExportParse *exp = noname_exports.v[exp_idx];
|
||||
U16 *ordinal = push_array(obj_writer->arena, U16, 1);
|
||||
*ordinal = exp->ordinal - ordinal_low;
|
||||
str8_list_push(obj_writer->arena, &ordinal_table_sect->data, str8_struct(ordinal));
|
||||
}
|
||||
}
|
||||
ProfEnd();
|
||||
|
||||
// fill out export table header
|
||||
PE_ExportTableHeader *header = push_array(obj_writer->arena, PE_ExportTableHeader, 1);
|
||||
header->time_stamp = COFF_TimeStamp_Max;
|
||||
header->ordinal_base = safe_cast_u16(ordinal_low);
|
||||
header->export_address_table_count = safe_cast_u32(voff_table_sect->data.node_count);
|
||||
header->name_pointer_table_count = safe_cast_u32(name_voff_table_sect->data.node_count);
|
||||
|
||||
// push header field's symbols
|
||||
COFF_ObjSymbol *image_name_symbol = coff_obj_writer_push_symbol_static(obj_writer, str8_lit("EXPORT_HEADER_NAME_VOFF"), 0, image_name_sect);
|
||||
COFF_ObjSymbol *address_table_symbol = coff_obj_writer_push_symbol_static(obj_writer, str8_lit("EXPORT_HEADER_ADDRESS_TABLE_VOFF"), 0, voff_table_sect);
|
||||
COFF_ObjSymbol *name_table_symbol = coff_obj_writer_push_symbol_static(obj_writer, str8_lit("EXPORT_HEADER_NAME_POINTER_VOFF"), 0, name_voff_table_sect);
|
||||
COFF_ObjSymbol *ordinal_table_symbol = coff_obj_writer_push_symbol_static(obj_writer, str8_lit("EXPORT_HEADER_ORDINAL_TABLE_VOFF"), 0, ordinal_table_sect);
|
||||
|
||||
// push export table header section
|
||||
COFF_ObjSection *header_sect = coff_obj_writer_push_section(obj_writer, str8_lit(".edata$1"), LNK_EDATA_SECTION_FLAGS|COFF_SectionFlag_Align1Bytes, str8_struct(header));
|
||||
coff_obj_writer_push_symbol_static(obj_writer, str8_lit("EXPORT_TABLE_HEADER"), 0, header_sect);
|
||||
|
||||
// patch export table header
|
||||
COFF_RelocType virt_off_reloc_type = coff_virt_off_reloc_from_machine(machine);
|
||||
coff_obj_writer_section_push_reloc(obj_writer, header_sect, OffsetOf(PE_ExportTableHeader, name_voff), image_name_symbol, virt_off_reloc_type);
|
||||
coff_obj_writer_section_push_reloc(obj_writer, header_sect, OffsetOf(PE_ExportTableHeader, export_address_table_voff), address_table_symbol, virt_off_reloc_type);
|
||||
coff_obj_writer_section_push_reloc(obj_writer, header_sect, OffsetOf(PE_ExportTableHeader, name_pointer_table_voff), name_table_symbol, virt_off_reloc_type);
|
||||
coff_obj_writer_section_push_reloc(obj_writer, header_sect, OffsetOf(PE_ExportTableHeader, ordinal_table_voff), ordinal_table_symbol, virt_off_reloc_type);
|
||||
|
||||
String8 obj = coff_obj_writer_serialize(arena, obj_writer);
|
||||
coff_obj_writer_release(&obj_writer);
|
||||
|
||||
LNK_InputObjList result = {0};
|
||||
LNK_InputObj *input = lnk_input_obj_list_push(arena, &result);
|
||||
input->path = str8_lit("* Exports *");
|
||||
input->dedup_id = input->path;
|
||||
input->data = obj;
|
||||
os_write_data_to_file_path(str8_lit("foo.obj"), obj);
|
||||
|
||||
scratch_end(scratch);
|
||||
return result;
|
||||
return obj;
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
@@ -3,42 +3,44 @@
|
||||
|
||||
#pragma once
|
||||
|
||||
typedef struct LNK_Export
|
||||
typedef struct LNK_ExportParse
|
||||
{
|
||||
struct LNK_Export *next;
|
||||
String8 name;
|
||||
struct LNK_Symbol *symbol;
|
||||
U32 id;
|
||||
U16 ordinal;
|
||||
COFF_ImportType type;
|
||||
B32 is_private;
|
||||
} LNK_Export;
|
||||
String8 obj_path;
|
||||
String8 lib_path;
|
||||
String8 name;
|
||||
String8 alias;
|
||||
COFF_ImportType type;
|
||||
U16 ordinal;
|
||||
U16 hint;
|
||||
B32 is_ordinal_assigned;
|
||||
B32 is_noname_present;
|
||||
B32 is_private;
|
||||
B32 is_forwarder;
|
||||
} LNK_ExportParse;
|
||||
|
||||
typedef struct LNK_ExportList
|
||||
typedef struct LNK_ExportParseNode
|
||||
{
|
||||
U64 count;
|
||||
LNK_Export *first;
|
||||
LNK_Export *last;
|
||||
} LNK_ExportList;
|
||||
LNK_ExportParse data;
|
||||
struct LNK_ExportParseNode *next;
|
||||
} LNK_ExportParseNode;
|
||||
|
||||
typedef struct LNK_ExportArray
|
||||
typedef struct LNK_ExportParseList
|
||||
{
|
||||
U64 count;
|
||||
LNK_Export *v;
|
||||
} LNK_ExportArray;
|
||||
U64 count;
|
||||
LNK_ExportParseNode *first;
|
||||
LNK_ExportParseNode *last;
|
||||
} LNK_ExportParseList;
|
||||
|
||||
typedef struct LNK_ExportTable
|
||||
typedef struct LNK_ExportParsePtrArray
|
||||
{
|
||||
Arena *arena;
|
||||
HashTable *name_export_ht;
|
||||
HashTable *noname_export_ht;
|
||||
U64 voff_size;
|
||||
U64 max_ordinal;
|
||||
B8 *is_ordinal_used;
|
||||
} LNK_ExportTable;
|
||||
U64 count;
|
||||
LNK_ExportParse **v;
|
||||
} LNK_ExportParsePtrArray;
|
||||
|
||||
internal LNK_ExportTable * lnk_export_table_alloc(void);
|
||||
internal void lnk_export_table_release(LNK_ExportTable **exptab_ptr);
|
||||
internal LNK_Export * lnk_export_table_search(LNK_ExportTable *exptab, String8 name);
|
||||
internal LNK_InputObjList lnk_export_table_serialize(Arena *arena, LNK_ExportTable *exptab, String8 image_name, COFF_MachineType machine);
|
||||
////////////////////////////////
|
||||
|
||||
internal B32 lnk_parse_export_directive_ex(Arena *arena, String8List directive, String8 obj_path, String8 lib_path, LNK_ExportParse *export_out);
|
||||
internal B32 lnk_parse_export_directive(Arena *arena, String8 directive, String8 obj_path, String8 lib_path, LNK_ExportParse *parse_out);
|
||||
internal LNK_ExportParsePtrArray lnk_array_from_export_list(Arena *arena, LNK_ExportParseList list);
|
||||
internal LNK_ExportParseNode * lnk_export_parse_list_push(Arena *arena, LNK_ExportParseList *list, LNK_ExportParse data);
|
||||
|
||||
|
||||
@@ -35,7 +35,7 @@ internal LNK_SectionContrib *
|
||||
lnk_section_contrib_chunk_push(LNK_SectionContribChunk *chunk, U64 count)
|
||||
{
|
||||
Assert(chunk->count + count <= chunk->cap);
|
||||
LNK_SectionContrib *result = &chunk->v[chunk->count];
|
||||
LNK_SectionContrib *result = chunk->v[chunk->count];
|
||||
chunk->count += count;
|
||||
return result;
|
||||
}
|
||||
@@ -46,7 +46,9 @@ lnk_section_contrib_chunk_list_push_chunk(Arena *arena, LNK_SectionContribChunkL
|
||||
LNK_SectionContribChunk *chunk = push_array(arena, LNK_SectionContribChunk, 1);
|
||||
chunk->count = 0;
|
||||
chunk->cap = cap;
|
||||
chunk->v = push_array(arena, LNK_SectionContrib, cap);
|
||||
chunk->v = push_array(arena, LNK_SectionContrib *, cap);
|
||||
chunk->v2 = push_array(arena, LNK_SectionContrib, cap);
|
||||
for (U64 i = 0; i < cap; i += 1) { chunk->v[i] = &chunk->v2[i]; }
|
||||
SLLQueuePush(list->first, list->last, chunk);
|
||||
list->chunk_count += 1;
|
||||
return chunk;
|
||||
@@ -317,7 +319,7 @@ lnk_finalize_section_layout(LNK_SectionTable *sectab, LNK_Section *sect, U64 fil
|
||||
U64 cursor = 0;
|
||||
for (LNK_SectionContribChunk *sc_chunk = sect->contribs.first; sc_chunk != 0; sc_chunk = sc_chunk->next) {
|
||||
for (U64 sc_idx = 0; sc_idx < sc_chunk->count; sc_idx += 1) {
|
||||
LNK_SectionContrib *sc = &sc_chunk->v[sc_idx];
|
||||
LNK_SectionContrib *sc = sc_chunk->v[sc_idx];
|
||||
|
||||
cursor = AlignPow2(cursor, sc->align);
|
||||
|
||||
|
||||
@@ -38,7 +38,8 @@ typedef struct LNK_SectionContribChunk
|
||||
struct LNK_SectionContribChunk *next;
|
||||
U64 count;
|
||||
U64 cap;
|
||||
LNK_SectionContrib *v;
|
||||
LNK_SectionContrib **v;
|
||||
LNK_SectionContrib *v2;
|
||||
} LNK_SectionContribChunk;
|
||||
|
||||
typedef struct LNK_SectionContribChunkList
|
||||
|
||||
Reference in New Issue
Block a user