diff --git a/src/coff/coff.c b/src/coff/coff.c index 3792804a..30b8b81a 100644 --- a/src/coff/coff.c +++ b/src/coff/coff.c @@ -550,6 +550,39 @@ coff_make_import_header_by_ordinal(Arena *arena, } //////////////////////////////// +//~ Resources + +internal String8 +coff_resource_string_from_str16(Arena *arena, String16 string) +{ + AssertAlways(string.size <= max_U16); + U16 size16 = (U16)string.size; + + U16 *buffer = push_array_no_zero(arena, U16, size16 + 1); + MemoryCopy(buffer + 0, &size16, sizeof(size16)); + MemoryCopy(buffer + 1, string.str, size16 * sizeof(string.str[0])); + + return str8_array(buffer, size16 + 1); +} + +internal String8 +coff_resource_string_from_str8(Arena *arena, String8 string) +{ + Temp scratch = scratch_begin(&arena, 1); + String16 string16 = str16_from_8(scratch.arena, string); + String8 result = coff_resource_string_from_str16(arena, string16); + scratch_end(scratch); + return result; +} + +internal String8 +coff_resource_number_from_u16(Arena *arena, U16 number) +{ + U16 *buffer = push_array_no_zero(arena, U16, 2); + buffer[0] = max_U16; + buffer[1] = number; + return str8_array(buffer, 2); +} internal B32 coff_resource_id_is_equal(COFF_ResourceID a, COFF_ResourceID b) @@ -567,47 +600,9 @@ coff_resource_id_is_equal(COFF_ResourceID a, COFF_ResourceID b) } internal COFF_ResourceID -coff_resource_id_copy(Arena *arena, COFF_ResourceID id) +coff_utf8_resource_id_from_utf16(Arena *arena, COFF_ResourceID_16 *id_16) { - COFF_ResourceID result = zero_struct; - switch (id.type) { - case COFF_ResourceIDType_NULL: break; - case COFF_ResourceIDType_NUMBER: { - result.type = COFF_ResourceIDType_NUMBER; - result.u.number = id.u.number; - } break; - case COFF_ResourceIDType_STRING: { - result.type = COFF_ResourceIDType_STRING; - result.u.string = id.u.string; - } break; - default: Assert(!"invalid resource id type"); - } - return result; -} - -internal U64 -coff_sizeof_resource_id(COFF_ResourceID id) -{ - U64 size = 0; - switch (id.type) { - case COFF_ResourceIDType_NULL: break; - case COFF_ResourceIDType_NUMBER: { - size += sizeof(U16); - size += sizeof(U16); - } break; - case COFF_ResourceIDType_STRING: { - size += sizeof(U16); - size += (id.u.string.size + /* null: */1) * sizeof(U16); - } break; - default: InvalidPath; - } - return AlignPow2(size, COFF_RES_ALIGN); -} - -internal COFF_ResourceID -coff_convert_resource_id(Arena *arena, COFF_ResourceID_16 *id_16) -{ - COFF_ResourceID id; + COFF_ResourceID id = {0}; id.type = id_16->type; switch (id_16->type) { case COFF_ResourceIDType_NULL: break; @@ -617,23 +612,22 @@ coff_convert_resource_id(Arena *arena, COFF_ResourceID_16 *id_16) case COFF_ResourceIDType_STRING: { id.u.string = str8_from_16(arena, id_16->u.string); } break; - default: Assert(!"invalid resource id type"); + default: InvalidPath; } return id; } internal U64 -coff_read_resource_id(String8 data, U64 off, COFF_ResourceID_16 *id_out) +coff_read_resource_id_utf16(String8 data, U64 off, COFF_ResourceID_16 *id_out) { U64 cursor = off; U16 flag = 0; str8_deserial_read_struct(data, cursor, &flag); - B32 is_number = flag == max_U16; - if (is_number) { - cursor += sizeof(flag); + if (flag == max_U16) { id_out->type = COFF_ResourceIDType_NUMBER; + cursor += sizeof(flag); cursor += str8_deserial_read_struct(data, cursor, &id_out->u.number); } else { id_out->type = COFF_ResourceIDType_STRING; @@ -641,93 +635,81 @@ coff_read_resource_id(String8 data, U64 off, COFF_ResourceID_16 *id_out) } U64 read_size = cursor - off; + read_size = AlignPow2(read_size, COFF_RES_ALIGN); return read_size; } internal U64 coff_read_resource(String8 raw_res, U64 off, Arena *arena, COFF_Resource *res_out) { - // parse header - COFF_ResourceHeaderPrefix prefix; MemoryZeroStruct(&prefix); - U64 cursor = str8_deserial_read_struct(raw_res, off, &prefix); - String8 header_data = str8_substr(raw_res, rng_1u64(off, off + prefix.header_size)); + String8 raw_header = str8_skip(raw_res, off); + U64 header_cursor = 0; + + // prefix + COFF_ResourceHeaderPrefix prefix = {0}; + header_cursor += str8_deserial_read_struct(raw_header, header_cursor, &prefix); + + Assert(prefix.header_size >= sizeof(COFF_ResourceHeaderPrefix)); + raw_header = str8_prefix(raw_header, prefix.header_size); + + // header + COFF_ResourceID_16 type_16 = {0}; + COFF_ResourceID_16 name_16 = {0}; + header_cursor += coff_read_resource_id_utf16(raw_header, header_cursor, &type_16); + header_cursor += coff_read_resource_id_utf16(raw_header, header_cursor, &name_16); + header_cursor += str8_deserial_read_struct(raw_header, header_cursor, &res_out->data_version); + header_cursor += str8_deserial_read_struct(raw_header, header_cursor, &res_out->memory_flags); + header_cursor += str8_deserial_read_struct(raw_header, header_cursor, &res_out->language_id); + header_cursor += str8_deserial_read_struct(raw_header, header_cursor, &res_out->version); + header_cursor += str8_deserial_read_struct(raw_header, header_cursor, &res_out->characteristics); + Assert(prefix.header_size == header_cursor); + + // convert utf-16 resource ids to utf-8 + res_out->type = coff_utf8_resource_id_from_utf16(arena, &type_16); + res_out->name = coff_utf8_resource_id_from_utf16(arena, &name_16); + + // read data + U64 data_read_size = str8_deserial_read_block(raw_res, off + prefix.header_size, prefix.data_size, &res_out->data); + Assert(prefix.data_size == data_read_size); - COFF_ResourceID_16 type_16; MemoryZeroStruct(&type_16); - cursor += coff_read_resource_id(header_data, cursor, &type_16); - cursor = AlignPow2(cursor, COFF_RES_ALIGN); - - COFF_ResourceID_16 name_16; MemoryZeroStruct(&name_16); - cursor += coff_read_resource_id(header_data, cursor, &name_16); - cursor = AlignPow2(cursor, COFF_RES_ALIGN); - - U32 data_version = 0; - cursor += str8_deserial_read_struct(header_data, cursor, &data_version); - - COFF_ResourceMemoryFlags memory_flags = 0; - cursor += str8_deserial_read_struct(header_data, cursor, &memory_flags); - - U16 language_id = 0; - cursor += str8_deserial_read_struct(header_data, cursor, &language_id); - - U32 version = 0; - cursor += str8_deserial_read_struct(header_data, cursor, &version); - - U32 characteristics = 0; - cursor += str8_deserial_read_struct(header_data, cursor, &characteristics); - - String8 data; - cursor += str8_deserial_read_block(raw_res, off + prefix.header_size, prefix.data_size, &data); - - // was resource parsed? - Assert(cursor >= prefix.data_size + prefix.header_size); - - // fill out result - res_out->type = coff_convert_resource_id(arena, &type_16); - res_out->name = coff_convert_resource_id(arena, &name_16); - res_out->language_id = language_id; - res_out->data_version = data_version; - res_out->version = version; - res_out->memory_flags = memory_flags; - res_out->data = data; - - U64 resource_size = AlignPow2(prefix.data_size + prefix.header_size, COFF_RES_ALIGN); - return resource_size; + // compute read size + U64 read_size = Max(prefix.header_size, sizeof(prefix)) + AlignPow2(prefix.data_size, COFF_RES_ALIGN); + return read_size; } internal COFF_ResourceList coff_resource_list_from_data(Arena *arena, String8 data) { - COFF_ResourceList list; MemoryZeroStruct(&list); - for (U64 cursor = 0, stride; cursor < data.size; cursor += stride) { + COFF_ResourceList list = {0}; + U64 cursor; + for (cursor = 0 ; cursor < data.size; ) { COFF_ResourceNode *node = push_array(arena, COFF_ResourceNode, 1); - stride = coff_read_resource(data, cursor, arena, &node->data); - list.count += 1; + cursor += coff_read_resource(data, cursor, arena, &node->data); SLLQueuePush(list.first, list.last, node); + ++list.count; } + Assert(cursor == data.size); return list; } -internal void -coff_write_resource_id(Arena *arena, String8List *srl, COFF_ResourceID id) +internal String8 +coff_write_resource_id(Arena *arena, COFF_ResourceID id) { + String8 result = str8_zero(); switch (id.type) { case COFF_ResourceIDType_NULL: break; case COFF_ResourceIDType_NUMBER: { - str8_serial_push_u16(arena, srl, max_U16); - str8_serial_push_u16(arena, srl, id.u.number); + result = coff_resource_number_from_u16(arena, id.u.number); } break; case COFF_ResourceIDType_STRING: { - String16 str16 = str16_from_8(arena, id.u.string); - Assert(str16.size <= max_U16); - str8_serial_push_u16(arena, srl, str16.size); - str8_serial_push_data(arena, srl, str16.str, str16.size); + result = coff_resource_string_from_str8(arena, id.u.string); } break; default: InvalidPath; } - str8_serial_push_align(arena, srl, COFF_RES_ALIGN); + return result; } -internal String8List +internal String8 coff_write_resource(Arena *arena, COFF_ResourceID type, COFF_ResourceID name, @@ -738,34 +720,43 @@ coff_write_resource(Arena *arena, U32 characteristics, String8 data) { - U64 header_size = sizeof(COFF_ResourceHeaderPrefix) + - coff_sizeof_resource_id(type) + - coff_sizeof_resource_id(name) + - sizeof(data_version) + - sizeof(memory_flags) + - sizeof(language_id) + - sizeof(version) + - sizeof(characteristics); + Temp scratch = scratch_begin(&arena, 1); - COFF_ResourceHeaderPrefix *header = push_array(arena, COFF_ResourceHeaderPrefix, 1); - header->data_size = safe_cast_u32(data.size); - header->header_size = safe_cast_u32(header_size); + String8List list = {0}; - String8List srl = {0}; - str8_serial_begin(arena, &srl); - str8_serial_push_data(arena, &srl, &g_coff_res_magic[0], sizeof(g_coff_res_magic)); - str8_serial_push_data(arena, &srl, header, sizeof(*header)); - coff_write_resource_id(arena, &srl, type); - coff_write_resource_id(arena, &srl, name); - str8_serial_push_u32(arena, &srl, data_version); - str8_serial_push_u16(arena, &srl, memory_flags); - str8_serial_push_u16(arena, &srl, language_id); - str8_serial_push_u32(arena, &srl, version); - str8_serial_push_u32(arena, &srl, characteristics); - str8_serial_push_string(arena, &srl, data); - str8_serial_push_align(arena, &srl, COFF_RES_ALIGN); + COFF_ResourceHeaderPrefix *prefix = push_array(scratch.arena, COFF_ResourceHeaderPrefix, 1); + String8 packed_type = coff_write_resource_id(scratch.arena, type); + String8 packed_name = coff_write_resource_id(scratch.arena, name); - return srl; + // prefix + header + str8_list_push(scratch.arena, &list, str8_struct(prefix)); + str8_list_push(scratch.arena, &list, packed_type); + str8_list_push(scratch.arena, &list, packed_name); + str8_list_push(scratch.arena, &list, str8_struct(&data_version)); + str8_list_push(scratch.arena, &list, str8_struct(&memory_flags)); + str8_list_push(scratch.arena, &list, str8_struct(&language_id)); + str8_list_push(scratch.arena, &list, str8_struct(&version)); + str8_list_push(scratch.arena, &list, str8_struct(&characteristics)); + + prefix->data_size = safe_cast_u32(data.size); + prefix->header_size = safe_cast_u32(list.total_size); + + // data + str8_list_push(scratch.arena, &list, data); + + // magic + str8_list_push_front(scratch.arena, &list, str8_array_fixed(g_coff_res_magic)); + + // align + U64 align_size = AlignPow2(list.total_size, COFF_RES_ALIGN) - list.total_size; + U8 *align = push_array(scratch.arena, U8, align_size); + str8_list_push(scratch.arena, &list, str8(align, align_size)); + + // join + String8 res = str8_list_join(arena, &list, 0); + + scratch_end(scratch); + return res; } //////////////////////////////// @@ -777,12 +768,10 @@ coff_data_type_from_data(String8 data) if (is_big_obj) { return COFF_DataType_BIG_OBJ; } - B32 is_import = coff_is_import(data); if (is_import) { return COFF_DataType_IMPORT; } - return COFF_DataType_OBJ; } diff --git a/src/coff/coff.h b/src/coff/coff.h index c772c597..e37223c6 100644 --- a/src/coff/coff.h +++ b/src/coff/coff.h @@ -608,10 +608,11 @@ typedef struct COFF_Resource { COFF_ResourceID type; COFF_ResourceID name; - U16 language_id; U32 data_version; - U32 version; COFF_ResourceMemoryFlags memory_flags; + U16 language_id; + U32 version; + U32 characteristics; String8 data; } COFF_Resource; @@ -877,25 +878,24 @@ internal String8 coff_make_import_header_by_ordinal(Arena *arena, U16 ordinal, COFF_ImportHeaderType type); +//////////////////////////////// +//~ Resources -internal B32 coff_resource_id_is_equal(COFF_ResourceID a, COFF_ResourceID b); -internal COFF_ResourceID coff_resource_id_copy(Arena *arena, COFF_ResourceID id); -internal U64 coff_sizeof_resource_id(COFF_ResourceID id); -internal COFF_ResourceID coff_convert_resource_id(Arena *arena, COFF_ResourceID_16 *id_16); -internal U64 coff_read_resource_id(String8 res, U64 off, COFF_ResourceID_16 *id_out); +internal String8 coff_resource_string_from_str16(Arena *arena, String16 string); +internal String8 coff_resource_string_from_str8(Arena *arena, String8 string); +internal String8 coff_resource_number_from_u16(Arena *arena, U16 number); + +internal B32 coff_resource_id_is_equal(COFF_ResourceID a, COFF_ResourceID b); +internal COFF_ResourceID coff_utf8_resource_id_from_utf16(Arena *arena, COFF_ResourceID_16 *id_16); + +internal U64 coff_read_resource_id_utf16(String8 res, U64 off, COFF_ResourceID_16 *id_out); internal U64 coff_read_resource(String8 data, U64 off, Arena *arena, COFF_Resource *res_out); internal COFF_ResourceList coff_resource_list_from_data(Arena *arena, String8 data); -internal void coff_write_resource_id(Arena *arena, String8List *srl, COFF_ResourceID id); -internal String8List coff_write_resource(Arena *arena, - COFF_ResourceID type, - COFF_ResourceID name, - U32 data_version, - COFF_ResourceMemoryFlags memory_flags, - U16 language_id, - U32 version, - U32 characteristics, - String8 data); +internal String8 coff_write_resource_id(Arena *arena, COFF_ResourceID id); +internal String8 coff_write_resource(Arena *arena, COFF_ResourceID type, COFF_ResourceID name, U32 data_version, COFF_ResourceMemoryFlags memory_flags, U16 language_id, U32 version, U32 characteristics, String8 data); + +//////////////////////////////// internal COFF_DataType coff_data_type_from_data(String8 data); internal B32 coff_is_import(String8 data); diff --git a/src/linker/lnk.c b/src/linker/lnk.c index 98f1fc9a..756003c1 100644 --- a/src/linker/lnk.c +++ b/src/linker/lnk.c @@ -180,7 +180,7 @@ lnk_input_import_arr_from_list(Arena *arena, LNK_InputImportList list) internal LNK_InputImportList lnk_list_from_input_import_arr(LNK_InputImport **arr, U64 count) { - LNK_InputImportList list; MemoryZeroStruct(&list); + LNK_InputImportList list = {0}; for (U64 i = 0; i < count; i += 1) { SLLQueuePush(list.first, list.last, arr[i]); list.count += 1; @@ -218,12 +218,13 @@ internal void lnk_write_data_list_to_file_path(String8 path, String8List data) { #if PROFILE_TELEMETRY - Temp scratch = scratch_begin(0, 0); - String8 size_str = str8_from_memory_size2(scratch.arena, data.total_size); - ProfBeginDynamic("Write %.*s to %.*s", str8_varg(size_str), str8_varg(path)); - scratch_end(scratch); + { + Temp scratch = scratch_begin(0, 0); + String8 size_str = str8_from_memory_size2(scratch.arena, data.total_size); + ProfBeginDynamic("Write %.*s to %.*s", str8_varg(size_str), str8_varg(path)); + scratch_end(scratch); + } #endif - B32 is_written = os_write_data_list_to_file_path(path, data); if (is_written) { if (lnk_get_log_status(LNK_Log_IO)) { @@ -256,7 +257,7 @@ lnk_make_full_path(Arena *arena, String8 work_dir, PathStyle system_path_style, PathStyle path_style = path_style_from_str8(path); if (path_style == PathStyle_Relative) { Temp scratch = scratch_begin(&arena, 1); - String8List list; MemoryZeroStruct(&list); + String8List list = {0}; str8_list_push(scratch.arena, &list, work_dir); str8_list_push(scratch.arena, &list, path); result = str8_path_list_join_by_style(arena, &list, system_path_style); @@ -326,10 +327,10 @@ lnk_merge_manifest_files(String8 mt_path, String8 out_name, String8List manifest ProfBeginFunction(); Temp scratch = scratch_begin(0,0); - String8List invoke_cmd_line = {0}; - str8_list_push(scratch.arena, &invoke_cmd_line, mt_path); - str8_list_pushf(scratch.arena, &invoke_cmd_line, "-out:%S", out_name); - str8_list_pushf(scratch.arena, &invoke_cmd_line, "-nologo"); + String8List cmd_line = {0}; + str8_list_push(scratch.arena, &cmd_line, mt_path); + str8_list_pushf(scratch.arena, &cmd_line, "-out:%S", out_name); + str8_list_pushf(scratch.arena, &cmd_line, "-nologo"); // register input manifest files on command line String8 work_dir = os_get_current_path(scratch.arena); @@ -343,13 +344,13 @@ lnk_merge_manifest_files(String8 mt_path, String8 out_name, String8List manifest full_path = path_convert_slashes(scratch.arena, full_path, PathStyle_UnixAbsolute); // push input to command line - str8_list_pushf(scratch.arena, &invoke_cmd_line, "-manifest"); - str8_list_push(scratch.arena, &invoke_cmd_line, full_path); + str8_list_pushf(scratch.arena, &cmd_line, "-manifest"); + str8_list_push(scratch.arena, &cmd_line, full_path); } // launch mt.exe with our command line OS_ProcessLaunchParams launch_opts = {0}; - launch_opts.cmd_line = invoke_cmd_line; + launch_opts.cmd_line = cmd_line; launch_opts.path = str8_chop_last_slash(mt_path); launch_opts.inherit_env = 1; launch_opts.consoleless = 1; @@ -413,26 +414,6 @@ lnk_manifest_from_inputs(Arena *arena, return manifest_data; } -internal String8 -lnk_res_from_data(Arena *arena, String8 data) -{ - Temp scratch = scratch_begin(&arena, 1); - - COFF_ResourceID type; - type.type = COFF_ResourceIDType_NUMBER; - type.u.number = PE_ResourceKind_MANIFEST; - - COFF_ResourceID name; - name.type = COFF_ResourceIDType_NUMBER; - name.u.number = 1; - - String8List res_list = coff_write_resource(arena, type, name, 1, 0, 1033, 0, 0, data); - String8 res_data = str8_serial_end(arena, &res_list); - - scratch_end(scratch); - return res_data; -} - //////////////////////////////// internal int @@ -461,167 +442,156 @@ internal void lnk_serialize_pe_resource_tree(LNK_SectionTable *st, LNK_SymbolTable *symtab, PE_ResourceDir *root_dir) { ProfBeginFunction(); - - static const U64 ALIGN = 4; - - struct stack_s { - struct stack_s *next; - U64 arr_idx; - U64 res_idx[2]; - PE_ResourceArray res_arr[2]; - LNK_Chunk *coff_entry_array_chunk; - LNK_Chunk *coff_entry_chunk; - }; - Temp scratch = scratch_begin(0, 0); - LNK_Section *dir_sect = lnk_section_table_push(st, str8_lit(".rsrc$01"), LNK_RSRC_SECTION_FLAGS); + LNK_Section *dir_sect = lnk_section_table_push(st, str8_lit(".rsrc$01"), LNK_RSRC_SECTION_FLAGS); LNK_Section *data_sect = lnk_section_table_push(st, str8_lit(".rsrc$02"), LNK_RSRC_SECTION_FLAGS); - LNK_Chunk *dir_tree_chunk = lnk_section_push_chunk_list(dir_sect, dir_sect->root, str8(0,0)); - LNK_Chunk *dir_data_chunk = lnk_section_push_chunk_list(dir_sect, dir_sect->root, str8(0,0)); - LNK_Chunk *dir_string_chunk = lnk_section_push_chunk_list(dir_sect, dir_sect->root, str8(0,0)); - + LNK_Chunk *dir_tree_chunk = lnk_section_push_chunk_list(dir_sect, dir_sect->root, str8_zero()); + LNK_Chunk *dir_data_chunk = lnk_section_push_chunk_list(dir_sect, dir_sect->root, str8_zero()); + LNK_Chunk *dir_string_chunk = lnk_section_push_chunk_list(dir_sect, dir_sect->root, str8_zero()); + dir_tree_chunk->sort_idx = str8_lit("a"); dir_string_chunk->sort_idx = str8_lit("b"); dir_data_chunk->sort_idx = str8_lit("c"); - PE_Resource root_wrapper; MemoryZeroStruct(&root_wrapper); - root_wrapper.id.type = COFF_ResourceIDType_NUMBER; + PE_Resource root_wrapper = {0}; + root_wrapper.id.type = COFF_ResourceIDType_NUMBER; root_wrapper.id.u.number = 0; - root_wrapper.kind = PE_ResDataKind_DIR; - root_wrapper.u.dir = root_dir; + root_wrapper.kind = PE_ResDataKind_DIR; + root_wrapper.u.dir = root_dir; - struct stack_s *stack = push_array(scratch.arena, struct stack_s, 1); + struct Stack { + struct Stack *next; + U64 arr_idx; + U64 res_idx[2]; + PE_ResourceArray res_arr[2]; + LNK_Chunk *coff_entry_array_chunk; + LNK_Chunk *coff_entry_chunk; + }; + struct Stack *stack = push_array(scratch.arena, struct Stack, 1); stack->res_arr[0].count = 1; - stack->res_arr[0].v = &root_wrapper; + stack->res_arr[0].v = &root_wrapper; - U64 res_counter = 0; + U64 total_res_count = 0; while (stack) { while (stack->arr_idx < ArrayCount(stack->res_arr)) { while (stack->res_idx[stack->arr_idx] < stack->res_arr[stack->arr_idx].count) { PE_Resource *res = &stack->res_arr[stack->arr_idx].v[stack->res_idx[stack->arr_idx]]; - stack->res_idx[stack->arr_idx] += 1; + ++stack->res_idx[stack->arr_idx]; - String8 flag_name = push_str8f(symtab->arena, "flag_%u", res_counter); - String8 offset_name = push_str8f(symtab->arena, "offset_%u", res_counter); - ++res_counter; + String8 flag_name = push_str8f(symtab->arena, "flag_%u", total_res_count); + String8 offset_name = push_str8f(symtab->arena, "offset_%u", total_res_count); + ++total_res_count; if (stack->coff_entry_array_chunk) { COFF_ResourceDirEntry *entry = push_array(dir_sect->arena, COFF_ResourceDirEntry, 1); - stack->coff_entry_chunk = lnk_section_push_chunk_data(dir_sect, stack->coff_entry_array_chunk, str8_struct(entry), str8(0,0)); + stack->coff_entry_chunk = lnk_section_push_chunk_data(dir_sect, stack->coff_entry_array_chunk, str8_struct(entry), str8_zero()); switch (res->id.type) { - case COFF_ResourceIDType_NUMBER: { - entry->name.id = res->id.u.number; - } break; - case COFF_ResourceIDType_STRING: { - // TODO: we can make string table smaller by reusing offsets for same strings - - // not sure why high bit has to be turned on here since number id and string id entries are - // in separate arrays but windows doesn't treat name offset like string without this bit. - entry->name.offset |= (1 << 31); - - // convert name to utf-16 - String16 name16 = str16_from_8(dir_sect->arena, res->id.u.string); - - // build name string - U64 name16_byte_size = name16.size * sizeof(U16); - U64 buffer_size = /* char count: */ sizeof(U16) + name16_byte_size; - U8 *buffer = push_array_no_zero(dir_sect->arena, U8, buffer_size); - *(U16*)buffer = name16.size; - MemoryCopy(buffer + sizeof(U16), name16.str, name16_byte_size); - - // push string table chunk - String8 name_data = str8(buffer, buffer_size); - LNK_Chunk *name_chunk = lnk_section_push_chunk_data(dir_sect, dir_string_chunk, name_data, str8(0,0)); - - // push name chunk symbol - LNK_Symbol *name_symbol = lnk_make_defined_symbol_chunk(symtab->arena, str8_lit("COFF_RESOURCE_ID_STRING"), LNK_DefinedSymbolVisibility_Static, 0, name_chunk, 0, 0, 0); - lnk_section_push_reloc(dir_sect, stack->coff_entry_chunk, LNK_Reloc_SECT_REL, OffsetOf(COFF_ResourceDirEntry, name.offset), name_symbol); - } break; - case COFF_ResourceIDType_NULL: break; - default: InvalidPath; + case COFF_ResourceIDType_NUMBER: { + entry->name.id = res->id.u.number; + } break; + + case COFF_ResourceIDType_STRING: { + // TODO: we can make string table smaller by reusing offsets for same strings + + // not sure why high bit has to be turned on here since number id and string id entries are + // in separate arrays but windows doesn't treat name offset like string without this bit. + entry->name.offset |= (1 << 31); + + // make chunk and symbol + String8 res_name = coff_resource_string_from_str8(dir_sect->arena, res->id.u.string); + LNK_Chunk *name_chunk = lnk_section_push_chunk_data(dir_sect, dir_string_chunk, res_name, str8_zero()); + LNK_Symbol *name_symbol = lnk_make_defined_symbol_chunk(symtab->arena, str8_lit("COFF_RESOURCE_ID_STRING"), LNK_DefinedSymbolVisibility_Static, 0, name_chunk, 0, 0, 0); + + // patch COFF_ResourceDirEntry.name.offset + lnk_section_push_reloc(dir_sect, stack->coff_entry_chunk, LNK_Reloc_SECT_REL, OffsetOf(COFF_ResourceDirEntry, name.offset), name_symbol); + } break; + + case COFF_ResourceIDType_NULL: break; + + default: InvalidPath; } } switch (res->kind) { - case PE_ResDataKind_DIR: { - // initialize directory header - COFF_ResourceDirTable *dir_header = push_array(dir_sect->arena, COFF_ResourceDirTable, 1); - dir_header->characteristics = res->u.dir->characteristics; - dir_header->time_stamp = res->u.dir->time_stamp; - dir_header->major_version = res->u.dir->major_version; - dir_header->minor_version = res->u.dir->minor_version; - dir_header->name_entry_count = res->u.dir->named_list.count; - dir_header->id_entry_count = res->u.dir->id_list.count; - - // push sub directory chunk layout - LNK_Chunk *dir_node_chunk = lnk_section_push_chunk_list(dir_sect, dir_tree_chunk, str8(0,0)); - dir_node_chunk->align = ALIGN; - LNK_Chunk *dir_header_chunk = lnk_section_push_chunk_data(dir_sect, dir_node_chunk, str8_struct(dir_header), str8(0,0)); - LNK_Chunk *entry_array_chunk = lnk_section_push_chunk_list(dir_sect, dir_node_chunk, str8(0,0)); - lnk_chunk_set_debugf(dir_sect->arena, dir_header_chunk, "DIR_HEADER_CHUNK"); - lnk_chunk_set_debugf(dir_sect->arena, entry_array_chunk, "DIR_ENTRY_ARRAY_CHUNK"); - - // push symbols to patch coff entry - LNK_Symbol *flag_symbol = lnk_make_defined_symbol_va(symtab->arena, flag_name, LNK_DefinedSymbolVisibility_Internal, 0, COFF_RESOURCE_SUB_DIR_FLAG); - LNK_Symbol *offset_symbol = lnk_make_defined_symbol_chunk(symtab->arena, offset_name, LNK_DefinedSymbolVisibility_Internal, 0, dir_header_chunk, 0, 0, 0); - lnk_symbol_table_push(symtab, flag_symbol); // set high bit to indicate directory - lnk_symbol_table_push(symtab, offset_symbol); // write offset for this directory - - // patch resource dir header - if (stack->coff_entry_chunk) { - lnk_section_push_reloc(dir_sect, stack->coff_entry_chunk, LNK_Reloc_ADDR_32, OffsetOf(COFF_ResourceDirEntry, id.data_entry_offset), flag_symbol); - lnk_section_push_reloc(dir_sect, stack->coff_entry_chunk, LNK_Reloc_SECT_REL, OffsetOf(COFF_ResourceDirEntry, id.data_entry_offset), offset_symbol); - } - - // sort entries by id - PE_ResourceArray named_array = pe_resource_list_to_array(scratch.arena, &res->u.dir->named_list); - PE_ResourceArray id_array = pe_resource_list_to_array(scratch.arena, &res->u.dir->id_list); - radsort(named_array.v, named_array.count, lnk_res_string_id_is_before); - radsort(id_array.v, id_array.count, lnk_res_number_id_is_before); - - // frame for sub directory - struct stack_s *frame = push_array(scratch.arena, struct stack_s, 1); - frame->coff_entry_array_chunk = entry_array_chunk; - frame->res_arr[0] = named_array; - frame->res_arr[1] = id_array; - SLLStackPush(stack, frame); - } goto yeild; // recurse to sub directory - - case PE_ResDataKind_COFF_RESOURCE: { - COFF_ResourceDataEntry *coff_resource_data_entry = push_array(dir_sect->arena, COFF_ResourceDataEntry, 1); - coff_resource_data_entry->data_size = res->u.coff_res.data.size; - coff_resource_data_entry->data_voff = 0; // relocated - coff_resource_data_entry->code_page = 0; // TODO: whats this for? (lld-link writes zero) - - // push layout chunks - LNK_Chunk *coff_resource_data_entry_chunk = lnk_section_push_chunk_data(dir_sect, dir_data_chunk, str8_struct(coff_resource_data_entry), str8(0,0)); - LNK_Chunk *resource_data_chunk = lnk_section_push_chunk_data(data_sect, data_sect->root, res->u.coff_res.data, str8(0,0)); - - // windows errors out on unaligned data - coff_resource_data_entry_chunk->align = ALIGN; - resource_data_chunk->align = ALIGN; - - // relocate data - String8 resource_data_symbol_name = push_str8f(symtab->arena, "$R%06X", res_counter); - LNK_Symbol *resource_data_symbol = lnk_make_defined_symbol_chunk(symtab->arena, resource_data_symbol_name, LNK_DefinedSymbolVisibility_Static, 0, resource_data_chunk, 0, 0, 0); - lnk_section_push_reloc(dir_sect, coff_resource_data_entry_chunk, LNK_Reloc_VIRT_OFF_32, OffsetOf(COFF_ResourceDataEntry, data_voff), resource_data_symbol); - - // push symbol for data offset relocation - LNK_Symbol *coff_data_offset_symbol = lnk_make_defined_symbol_chunk(symtab->arena, offset_name, LNK_DefinedSymbolVisibility_Internal, 0, coff_resource_data_entry_chunk, 0, 0, 0); - lnk_symbol_table_push(symtab, coff_data_offset_symbol); - - Assert(stack->coff_entry_chunk); - lnk_section_push_reloc(dir_sect, stack->coff_entry_chunk, LNK_Reloc_SECT_REL, OffsetOf(COFF_ResourceDirEntry, id.data_entry_offset), coff_data_offset_symbol); - } break; - - case PE_ResDataKind_NULL: break; - - // we must not have this resource node here, it is used to represent on-disk version of entry - case PE_ResDataKind_COFF_LEAF: InvalidPath; + case PE_ResDataKind_DIR: { + // initialize directory header + COFF_ResourceDirTable *dir_header = push_array(dir_sect->arena, COFF_ResourceDirTable, 1); + dir_header->characteristics = res->u.dir->characteristics; + dir_header->time_stamp = res->u.dir->time_stamp; + dir_header->major_version = res->u.dir->major_version; + dir_header->minor_version = res->u.dir->minor_version; + dir_header->name_entry_count = res->u.dir->named_list.count; + dir_header->id_entry_count = res->u.dir->id_list.count; + + // push sub directory chunk layout + LNK_Chunk *dir_node_chunk = lnk_section_push_chunk_list(dir_sect, dir_tree_chunk, str8_zero()); + dir_node_chunk->align = COFF_RES_ALIGN; + LNK_Chunk *dir_header_chunk = lnk_section_push_chunk_data(dir_sect, dir_node_chunk, str8_struct(dir_header), str8_zero()); + LNK_Chunk *entry_array_chunk = lnk_section_push_chunk_list(dir_sect, dir_node_chunk, str8_zero()); + lnk_chunk_set_debugf(dir_sect->arena, dir_header_chunk, "DIR_HEADER_CHUNK"); + lnk_chunk_set_debugf(dir_sect->arena, entry_array_chunk, "DIR_ENTRY_ARRAY_CHUNK"); + + // push symbols to patch coff entry + LNK_Symbol *flag_symbol = lnk_make_defined_symbol_va(symtab->arena, flag_name, LNK_DefinedSymbolVisibility_Internal, 0, COFF_RESOURCE_SUB_DIR_FLAG); + LNK_Symbol *offset_symbol = lnk_make_defined_symbol_chunk(symtab->arena, offset_name, LNK_DefinedSymbolVisibility_Internal, 0, dir_header_chunk, 0, 0, 0); + lnk_symbol_table_push(symtab, flag_symbol); // set high bit to indicate directory + lnk_symbol_table_push(symtab, offset_symbol); // write offset for this directory + + // patch resource dir header + if (stack->coff_entry_chunk) { + lnk_section_push_reloc(dir_sect, stack->coff_entry_chunk, LNK_Reloc_ADDR_32, OffsetOf(COFF_ResourceDirEntry, id.data_entry_offset), flag_symbol); + lnk_section_push_reloc(dir_sect, stack->coff_entry_chunk, LNK_Reloc_SECT_REL, OffsetOf(COFF_ResourceDirEntry, id.data_entry_offset), offset_symbol); + } + + // sort entries by id + PE_ResourceArray named_array = pe_resource_list_to_array(scratch.arena, &res->u.dir->named_list); + PE_ResourceArray id_array = pe_resource_list_to_array(scratch.arena, &res->u.dir->id_list); + radsort(named_array.v, named_array.count, lnk_res_string_id_is_before); + radsort(id_array.v, id_array.count, lnk_res_number_id_is_before); + + // frame for sub directory + struct Stack *frame = push_array(scratch.arena, struct Stack, 1); + frame->coff_entry_array_chunk = entry_array_chunk; + frame->res_arr[0] = named_array; + frame->res_arr[1] = id_array; + SLLStackPush(stack, frame); + } goto yeild; // recurse to sub directory + + case PE_ResDataKind_COFF_RESOURCE: { + COFF_ResourceDataEntry *coff_resource_data_entry = push_array(dir_sect->arena, COFF_ResourceDataEntry, 1); + coff_resource_data_entry->data_size = res->u.coff_res.data.size; + coff_resource_data_entry->data_voff = 0; // relocated + coff_resource_data_entry->code_page = 0; // TODO: whats this for? (lld-link writes zero) + + // push layout chunks + LNK_Chunk *coff_resource_data_entry_chunk = lnk_section_push_chunk_data(dir_sect, dir_data_chunk, str8_struct(coff_resource_data_entry), str8_zero()); + LNK_Chunk *resource_data_chunk = lnk_section_push_chunk_data(data_sect, data_sect->root, res->u.coff_res.data, str8_zero()); + + // windows errors out on unaligned data + coff_resource_data_entry_chunk->align = COFF_RES_ALIGN; + resource_data_chunk->align = COFF_RES_ALIGN; + + // relocate data + String8 resource_data_symbol_name = push_str8f(symtab->arena, "$R%06X", total_res_count); + LNK_Symbol *resource_data_symbol = lnk_make_defined_symbol_chunk(symtab->arena, resource_data_symbol_name, LNK_DefinedSymbolVisibility_Static, 0, resource_data_chunk, 0, 0, 0); + lnk_section_push_reloc(dir_sect, coff_resource_data_entry_chunk, LNK_Reloc_VIRT_OFF_32, OffsetOf(COFF_ResourceDataEntry, data_voff), resource_data_symbol); + + // push symbol for data offset relocation + LNK_Symbol *coff_data_offset_symbol = lnk_make_defined_symbol_chunk(symtab->arena, offset_name, LNK_DefinedSymbolVisibility_Internal, 0, coff_resource_data_entry_chunk, 0, 0, 0); + lnk_symbol_table_push(symtab, coff_data_offset_symbol); + + Assert(stack->coff_entry_chunk); + lnk_section_push_reloc(dir_sect, stack->coff_entry_chunk, LNK_Reloc_SECT_REL, OffsetOf(COFF_ResourceDirEntry, id.data_entry_offset), coff_data_offset_symbol); + } break; + + case PE_ResDataKind_NULL: break; + + // we must not have this resource node here, it is used to represent on-disk version of entry + case PE_ResDataKind_COFF_LEAF: InvalidPath; } } ++stack->arr_idx; @@ -731,7 +701,7 @@ lnk_add_resource_debug_s(LNK_SectionTable *st, LNK_Section *debug_s = lnk_section_table_push(st, str8_lit(".debug$S"), LNK_DEBUG_SECTION_FLAGS); String8 sub_sect_data = str8_serial_end(debug_s->arena, &sub_sect_srl); - lnk_section_push_chunk_data(debug_s, debug_s->root, sub_sect_data, str8(0,0)); + lnk_section_push_chunk_data(debug_s, debug_s->root, sub_sect_data, str8_zero()); scratch_end(scratch); ProfEnd(); @@ -882,10 +852,10 @@ lnk_make_res_obj(TP_Context *tp, reloc_sect->emit_header = 0; // push chunk layout for relocations - LNK_Chunk *reloc_array_chunk = lnk_section_push_chunk_list(reloc_sect, reloc_sect->root, str8(0,0)); + LNK_Chunk *reloc_array_chunk = lnk_section_push_chunk_list(reloc_sect, reloc_sect->root, str8_zero()); for (COFF_RelocNode *i = coff_reloc_list.first; i != 0; i = i->next) { String8 reloc_data = push_str8_copy(reloc_sect->arena, str8_struct(&i->data)); - lnk_section_push_chunk_data(reloc_sect, reloc_array_chunk, reloc_data, str8(0,0)); + lnk_section_push_chunk_data(reloc_sect, reloc_array_chunk, reloc_data, str8_zero()); } // emit symbols for coff section header patch @@ -908,7 +878,7 @@ lnk_make_res_obj(TP_Context *tp, str8_serial_push_struct(scratch.arena, &srl, &i->data); } String8 coff_symbol_table_data = str8_serial_end(scratch.arena, &srl); - LNK_Chunk *coff_symbol_table_chunk = lnk_section_push_chunk_data(misc_sect, misc_sect->root, coff_symbol_table_data, str8(0,0)); + LNK_Chunk *coff_symbol_table_chunk = lnk_section_push_chunk_data(misc_sect, misc_sect->root, coff_symbol_table_data, str8_zero()); LNK_Symbol *coff_symbol_table_symbol = lnk_make_defined_symbol_chunk(symtab->arena, str8_lit("COFF_SYMBOL_TABLE"), LNK_DefinedSymbolVisibility_Internal, 0, coff_symbol_table_chunk, 0, 0, 0); lnk_symbol_table_push(symtab, coff_symbol_table_symbol); @@ -929,7 +899,7 @@ lnk_make_res_obj(TP_Context *tp, // push coff header chunk String8 coff_header_data = str8_struct(coff_header); - LNK_Chunk *coff_header_chunk = lnk_section_push_chunk_data(header_sect, header_sect->root, coff_header_data, str8(0,0)); + LNK_Chunk *coff_header_chunk = lnk_section_push_chunk_data(header_sect, header_sect->root, coff_header_data, str8_zero()); // relocate coff header fields lnk_section_push_reloc_undefined(header_sect, coff_header_chunk, LNK_Reloc_ADDR_32, OffsetOf(COFF_Header, section_count), str8_lit(LNK_COFF_SECT_HEADER_COUNT_SYMBOL_NAME), LNK_SymbolScopeFlag_Internal); @@ -943,7 +913,7 @@ lnk_make_res_obj(TP_Context *tp, // build section headers { - LNK_Chunk *coff_section_header_array_chunk = lnk_section_push_chunk_list(header_sect, header_sect->root, str8(0,0)); + LNK_Chunk *coff_section_header_array_chunk = lnk_section_push_chunk_list(header_sect, header_sect->root, str8_zero()); for (LNK_SectionNode *sect_node = st->list.first; sect_node != 0; sect_node = sect_node->next) { if (sect_node == st->null_sect) continue; if (!sect_node->data.emit_header) continue; @@ -965,7 +935,7 @@ lnk_make_res_obj(TP_Context *tp, // push section header chunk String8 coff_sect_header_data = str8_struct(coff_sect_header); - String8 sort_index = lnk_make_section_sort_index(header_sect->arena, str8(0,0), 0, sect->isect); + String8 sort_index = lnk_make_section_sort_index(header_sect->arena, str8_zero(), 0, sect->isect); LNK_Chunk *coff_sect_header_chunk = lnk_section_push_chunk_data(header_sect, coff_section_header_array_chunk, coff_sect_header_data, sort_index); lnk_chunk_set_debugf(header_sect->arena, coff_sect_header_chunk, "%S", sect->name); @@ -1091,7 +1061,7 @@ lnk_make_linker_coff_obj(TP_Context *tp, coff_header->section_count = 0; coff_header->time_stamp = time_stamp; - LNK_Chunk *coff_header_chunk = lnk_section_push_chunk_raw(header_sect, header_sect->root, coff_header, sizeof(*coff_header), str8(0,0)); + LNK_Chunk *coff_header_chunk = lnk_section_push_chunk_raw(header_sect, header_sect->root, coff_header, sizeof(*coff_header), str8_zero()); lnk_section_push_reloc_undefined(header_sect, coff_header_chunk, LNK_Reloc_ADDR_32, OffsetOf(COFF_Header, section_count), str8_lit(LNK_COFF_SECT_HEADER_COUNT_SYMBOL_NAME), LNK_SymbolScopeFlag_Internal); } @@ -1147,7 +1117,7 @@ lnk_make_linker_coff_obj(TP_Context *tp, // push debug info to section String8 debug_s_data = str8_list_join(debug_s_sect->arena, &debug_s_data_list, 0); - lnk_section_push_chunk_data(debug_s_sect, debug_s_sect->root, debug_s_data, str8(0,0)); + lnk_section_push_chunk_data(debug_s_sect, debug_s_sect->root, debug_s_data, str8_zero()); } { @@ -1158,7 +1128,7 @@ lnk_make_linker_coff_obj(TP_Context *tp, lnk_symbol_table_push(symtab, sect_symbol); } - LNK_Chunk *coff_section_header_array_chunk = lnk_section_push_chunk_list(header_sect, header_sect->root, str8(0,0)); + LNK_Chunk *coff_section_header_array_chunk = lnk_section_push_chunk_list(header_sect, header_sect->root, str8_zero()); for (LNK_SectionNode *sect_node = st->list.first; sect_node != NULL; sect_node = sect_node->next) { if (sect_node == st->null_sect) continue; if (!sect_node->data.emit_header) continue; @@ -1179,7 +1149,7 @@ lnk_make_linker_coff_obj(TP_Context *tp, coff_sect_header->reloc_count = 0; // relocated // push section header chunk - String8 sort_index = lnk_make_section_sort_index(header_sect->arena, str8(0,0), 0, sect->isect); + String8 sort_index = lnk_make_section_sort_index(header_sect->arena, str8_zero(), 0, sect->isect); LNK_Chunk *coff_sect_header_chunk = lnk_section_push_chunk_raw(header_sect, coff_section_header_array_chunk, coff_sect_header, sizeof(*coff_sect_header), sort_index); lnk_chunk_set_debugf(header_sect->arena, coff_sect_header_chunk, "%S", sect->name); @@ -1458,7 +1428,7 @@ lnk_push_pe_debug_data_directory(LNK_Section *sect, //dir->size = 0; // relocated through 'symbol' // push chunk - LNK_Chunk *dir_entry_chunk = lnk_section_push_chunk_data(sect, dir_array_chunk, str8_struct(dir), str8(0,0)); + LNK_Chunk *dir_entry_chunk = lnk_section_push_chunk_data(sect, dir_array_chunk, str8_struct(dir), str8_zero()); lnk_chunk_set_debugf(sect->arena, dir_entry_chunk, "DebugDirectory[%u]", type); // push debug directory relocs @@ -1512,7 +1482,7 @@ lnk_build_debug_rdi(LNK_SectionTable *st, // push chunks String8 debug_rdi = pe_make_debug_header_rdi(rdi_sect->arena, guid, rdi_path); - LNK_Chunk *debug_rdi_chunk = lnk_section_push_chunk_data(rdi_sect, rdi_sect->root, debug_rdi, str8(0,0)); lnk_chunk_set_debugf(rdi_sect->arena, debug_rdi, LNK_CV_HEADER_RDI_SYMBOL_NAME); + LNK_Chunk *debug_rdi_chunk = lnk_section_push_chunk_data(rdi_sect, rdi_sect->root, debug_rdi, str8_zero()); lnk_chunk_set_debugf(rdi_sect->arena, debug_rdi, LNK_CV_HEADER_RDI_SYMBOL_NAME); // push symbols LNK_Symbol *debug_rdi_symbol = lnk_make_defined_symbol_chunk(symtab->arena, str8_lit(LNK_CV_HEADER_RDI_SYMBOL_NAME), LNK_DefinedSymbolVisibility_Internal, 0, debug_rdi_chunk, 0, 0, 0); @@ -1554,26 +1524,26 @@ lnk_build_guard_tables(TP_Context *tp, if (has_guard_flags) { LNK_SymbolArray symbol_arr = lnk_symbol_array_from_list(scratch.arena, obj->symbol_list); if (guard_flags & LNK_Guard_Cf) { - LNK_ChunkList gfids_list = lnk_obj_search_chunks(scratch.arena, obj, str8_lit(".gfids"), str8(0,0), 1); + LNK_ChunkList gfids_list = lnk_obj_search_chunks(scratch.arena, obj, str8_lit(".gfids"), str8_zero(), 1); for (LNK_ChunkNode *node = gfids_list.first; node != 0; node = node->next) { Assert(node->data->type == LNK_Chunk_Leaf); lnk_push_coff_symbols_from_data(scratch.arena, &guard_symbol_list_table[GUARD_FIDS], node->data->u.leaf, symbol_arr); } - LNK_ChunkList giats_list = lnk_obj_search_chunks(scratch.arena, obj, str8_lit(".giats"), str8(0,0), 1); + LNK_ChunkList giats_list = lnk_obj_search_chunks(scratch.arena, obj, str8_lit(".giats"), str8_zero(), 1); for (LNK_ChunkNode *node = giats_list.first; node != 0; node = node->next) { Assert(node->data->type == LNK_Chunk_Leaf); lnk_push_coff_symbols_from_data(scratch.arena, &guard_symbol_list_table[GUARD_IATS], node->data->u.leaf, symbol_arr); } } if (guard_flags & LNK_Guard_LongJmp) { - LNK_ChunkList gljmp_list = lnk_obj_search_chunks(scratch.arena, obj, str8_lit(".gljmp"), str8(0,0), 1); + LNK_ChunkList gljmp_list = lnk_obj_search_chunks(scratch.arena, obj, str8_lit(".gljmp"), str8_zero(), 1); for (LNK_ChunkNode *node = gljmp_list.first; node != 0; node = node->next) { Assert(node->data->type == LNK_Chunk_Leaf); lnk_push_coff_symbols_from_data(scratch.arena, &guard_symbol_list_table[GUARD_LJMP], node->data->u.leaf, symbol_arr); } } if (guard_flags & LNK_Guard_EhCont) { - LNK_ChunkList gehcont_list = lnk_obj_search_chunks(scratch.arena, obj, str8_lit(".gehcont"), str8(0,0), 1); + LNK_ChunkList gehcont_list = lnk_obj_search_chunks(scratch.arena, obj, str8_lit(".gehcont"), str8_zero(), 1); for (LNK_ChunkNode *node = gehcont_list.first; node != 0; node = node->next) { Assert(node->data->type == LNK_Chunk_Leaf); lnk_push_coff_symbols_from_data(scratch.arena, &guard_symbol_list_table[GUARD_EHCONT], node->data->u.leaf, symbol_arr); @@ -1732,10 +1702,10 @@ lnk_build_guard_tables(TP_Context *tp, String8 gehcont_data = lnk_build_guard_data(gehcont_sect->arena, guard_voff_arr_table[GUARD_EHCONT], entry_stride); // push guard data - lnk_section_push_chunk_data(gfids_sect, gfids_array_chunk, gfids_data, str8(0,0)); - lnk_section_push_chunk_data(giats_sect, giats_array_chunk, giats_data, str8(0,0)); - lnk_section_push_chunk_data(gljmp_sect, gljmp_array_chunk, gljmp_data, str8(0,0)); - lnk_section_push_chunk_data(gehcont_sect, gehcont_array_chunk, gehcont_data, str8(0,0)); + lnk_section_push_chunk_data(gfids_sect, gfids_array_chunk, gfids_data, str8_zero()); + lnk_section_push_chunk_data(giats_sect, giats_array_chunk, giats_data, str8_zero()); + lnk_section_push_chunk_data(gljmp_sect, gljmp_array_chunk, gljmp_data, str8_zero()); + lnk_section_push_chunk_data(gehcont_sect, gehcont_array_chunk, gehcont_data, str8_zero()); LNK_Symbol *gflags_symbol = lnk_symbol_table_search(symtab, LNK_SymbolScopeFlag_Main, str8_lit(LNK_GUARD_FLAGS_SYMBOL_NAME)); LNK_Symbol *gfids_table_symbol = lnk_symbol_table_search(symtab, LNK_SymbolScopeFlag_Main, str8_lit(LNK_GUARD_FIDS_TABLE_SYMBOL_NAME)); @@ -2065,7 +2035,7 @@ lnk_build_base_relocs(TP_Context *tp, Assert(*block_size_ptr <= buf_size); // push page chunk - lnk_section_push_chunk_raw(base_reloc_sect, base_reloc_sect->root, buf, block_size, str8(0,0)); + lnk_section_push_chunk_raw(base_reloc_sect, base_reloc_sect->root, buf, block_size, str8_zero()); // purge voffs for next run hash_table_purge(voff_ht); @@ -2102,9 +2072,9 @@ lnk_build_dos_header(LNK_SymbolTable *symtab, LNK_Section *header_sect, LNK_Chun MemoryZeroArray(dos_header->reserved2); dos_header->coff_file_offset = 0; // :coff_file_offset - LNK_Chunk *dos_chunk = lnk_section_push_chunk_list(header_sect, parent_chunk, str8(0,0)); - LNK_Chunk *dos_header_chunk = lnk_section_push_chunk_raw(header_sect, dos_chunk, dos_header, sizeof(*dos_header), str8(0,0)); - LNK_Chunk *dos_program_chunk = lnk_section_push_chunk_data(header_sect, dos_chunk, pe_dos_program, str8(0,0)); + LNK_Chunk *dos_chunk = lnk_section_push_chunk_list(header_sect, parent_chunk, str8_zero()); + LNK_Chunk *dos_header_chunk = lnk_section_push_chunk_raw(header_sect, dos_chunk, dos_header, sizeof(*dos_header), str8_zero()); + LNK_Chunk *dos_program_chunk = lnk_section_push_chunk_data(header_sect, dos_chunk, pe_dos_program, str8_zero()); lnk_chunk_set_debugf(header_sect->arena, dos_chunk, "DOS Header & Stub"); lnk_chunk_set_debugf(header_sect->arena, dos_header_chunk, LNK_DOS_HEADER_SYMBOL_NAME); lnk_chunk_set_debugf(header_sect->arena, dos_program_chunk, LNK_DOS_PROGRAM_SYMBOL_NAME); @@ -2126,7 +2096,7 @@ lnk_build_pe_magic(LNK_SymbolTable *symtab, LNK_Section *header_sect, LNK_Chunk U32 *pe_magic = push_array_no_zero(header_sect->arena, U32, 1); *pe_magic = PE_MAGIC; - LNK_Chunk *pe_magic_chunk = lnk_section_push_chunk_raw(header_sect, parent, pe_magic, sizeof(*pe_magic), str8(0,0)); + LNK_Chunk *pe_magic_chunk = lnk_section_push_chunk_raw(header_sect, parent, pe_magic, sizeof(*pe_magic), str8_zero()); lnk_chunk_set_debugf(header_sect->arena, pe_magic_chunk, LNK_PE_MAGIC_SYMBOL_NAME); LNK_Symbol *pe_magic_symbol = lnk_make_defined_symbol_chunk(symtab->arena, str8_lit(LNK_PE_MAGIC_SYMBOL_NAME), LNK_DefinedSymbolVisibility_Internal, 0, pe_magic_chunk, 0, 0, 0); @@ -2148,7 +2118,7 @@ lnk_build_coff_file_header(LNK_SymbolTable *symtab, LNK_Section *header_sect, LN file_header->optional_header_size = 0; // :optional_header_size file_header->flags = file_characteristics; - LNK_Chunk *file_header_chunk = lnk_section_push_chunk_raw(header_sect, parent, file_header, sizeof(*file_header), str8(0,0)); + LNK_Chunk *file_header_chunk = lnk_section_push_chunk_raw(header_sect, parent, file_header, sizeof(*file_header), str8_zero()); lnk_chunk_set_debugf(header_sect->arena, file_header_chunk, LNK_COFF_HEADER_SYMBOL_NAME); LNK_Symbol *file_header_symbol = lnk_make_defined_symbol_chunk(symtab->arena, str8_lit(LNK_COFF_HEADER_SYMBOL_NAME), LNK_DefinedSymbolVisibility_Internal, 0, file_header_chunk, 0, 0, 0); @@ -2217,7 +2187,7 @@ lnk_build_pe_optional_header_x64(LNK_SymbolTable *symtab, opt_header->data_dir_count = 0; // :data_dir_count // push chunk - LNK_Chunk *opt_header_chunk = lnk_section_push_chunk_raw(header_sect, parent, opt_header, sizeof(*opt_header), str8(0,0)); + LNK_Chunk *opt_header_chunk = lnk_section_push_chunk_raw(header_sect, parent, opt_header, sizeof(*opt_header), str8_zero()); lnk_chunk_set_debugf(header_sect->arena, opt_header_chunk, LNK_PE_OPT_HEADER_SYMBOL_NAME); // define optional header symbol @@ -2298,7 +2268,7 @@ lnk_build_pe_directories(LNK_SymbolTable *symtab, LNK_Section *header_sect, LNK_ U64 directory_count = PE_DataDirectoryIndex_COUNT; PE_DataDirectory *directory_array = push_array(header_sect->arena, PE_DataDirectory, directory_count); - LNK_Chunk *directory_array_chunk = lnk_section_push_chunk_raw(header_sect, parent, directory_array, sizeof(directory_array[0])*directory_count, str8(0,0)); + LNK_Chunk *directory_array_chunk = lnk_section_push_chunk_raw(header_sect, parent, directory_array, sizeof(directory_array[0])*directory_count, str8_zero()); lnk_chunk_set_debugf(header_sect->arena, directory_array_chunk, LNK_PE_DIRECTORY_ARRAY_SYMBOL_NAME); // define PE directory symbols @@ -2339,7 +2309,7 @@ lnk_build_coff_section_table(LNK_SymbolTable *symtab, LNK_Section *header_sect, } // push COFF header array chunk - LNK_Chunk *coff_header_array_chunk = lnk_section_push_chunk_list(header_sect, parent_chunk, str8(0,0)); + LNK_Chunk *coff_header_array_chunk = lnk_section_push_chunk_list(header_sect, parent_chunk, str8_zero()); lnk_chunk_set_debugf(header_sect->arena, coff_header_array_chunk, LNK_COFF_SECT_HEADER_ARRAY_SYMBOL_NAME); // define symbol for COFF header array @@ -2374,7 +2344,7 @@ lnk_build_coff_section_table(LNK_SymbolTable *symtab, LNK_Section *header_sect, coff_header->flags = sect->flags; // push chunk - LNK_Chunk *coff_header_chunk = lnk_section_push_chunk_raw(header_sect, coff_header_array_chunk, coff_header, sizeof(*coff_header), str8(0,0)); + LNK_Chunk *coff_header_chunk = lnk_section_push_chunk_raw(header_sect, coff_header_array_chunk, coff_header, sizeof(*coff_header), str8_zero()); // :vsize lnk_section_push_reloc_undefined(header_sect, coff_header_chunk, LNK_Reloc_CHUNK_SIZE_VIRT_32, OffsetOf(COFF_SectionHeader, vsize), sect->name, LNK_SymbolScopeFlag_Internal); @@ -2412,7 +2382,7 @@ lnk_build_win32_image_header(LNK_SymbolTable *symtab, // header sections must be written first Assert(header_sect->id == 0); - LNK_Chunk *win32_header_chunk = lnk_section_push_chunk_list(header_sect, parent_chunk , str8(0,0) ); + LNK_Chunk *win32_header_chunk = lnk_section_push_chunk_list(header_sect, parent_chunk , str8_zero() ); LNK_Chunk *dos_chunk = lnk_section_push_chunk_list(header_sect, win32_header_chunk, str8_lit("a")); LNK_Chunk *nt_chunk = lnk_section_push_chunk_list(header_sect, win32_header_chunk, str8_lit("b")); LNK_Chunk *pe_magic_chunk = lnk_section_push_chunk_list(header_sect, nt_chunk , str8_lit("a")); @@ -3752,7 +3722,7 @@ l.count += 1; \ // search disk for library String8List match_list = os_file_search(scratch.arena, config->lib_dir_list, path); - String8 absolute_path = match_list.node_count ? match_list.first->string : str8(0,0); + String8 absolute_path = match_list.node_count ? match_list.first->string : str8_zero(); // default to first match if (lnk_is_lib_loaded(default_lib_ht, loaded_lib_ht, input_source, absolute_path)) { @@ -3857,7 +3827,7 @@ l.count += 1; \ // TODO: currently we convert manifest to res and parse res again, this unnecessary instead push manifest // resource to the tree directly String8 manifest_data = lnk_manifest_from_inputs(scratch.arena, config->mt_path, config->manifest_name, config->manifest_uac, config->manifest_level, config->manifest_ui_access, input_manifest_path_list, manifest_dep_list); - String8 manifest_res = lnk_res_from_data(scratch.arena, manifest_data); + String8 manifest_res = pe_make_manifest_resource(scratch.arena, *config->manifest_resource_id, manifest_data); str8_list_push(scratch.arena, &res_data_list, manifest_res); str8_list_push(scratch.arena, &res_path_list, str8_lit("* Manifest *")); ProfEnd(); @@ -4004,8 +3974,8 @@ l.count += 1; \ // push debug directory layout chunks LNK_Section *debug_sect = lnk_section_table_search(st, str8_lit(".rdata")); - LNK_Chunk *debug_chunk = lnk_section_push_chunk_list(debug_sect, debug_sect->root, str8(0,0)); - LNK_Chunk *debug_dir_array_chunk = lnk_section_push_chunk_list(debug_sect, debug_chunk, str8(0,0)); + LNK_Chunk *debug_chunk = lnk_section_push_chunk_list(debug_sect, debug_sect->root, str8_zero()); + LNK_Chunk *debug_dir_array_chunk = lnk_section_push_chunk_list(debug_sect, debug_chunk, str8_zero()); // push symbols for PE directory patch LNK_Symbol *dir_array_symbol = lnk_make_defined_symbol_chunk(symtab->arena, str8_lit(LNK_DEBUG_DIR_SYMBOL_NAME), LNK_DefinedSymbolVisibility_Internal, 0, debug_dir_array_chunk, 0, 0, 0); @@ -4578,7 +4548,7 @@ lnk_dump_resource_dir_(COFF_ResourceID dir_id, PE_ResourceDir *dir) { Temp scratch = scratch_begin(0, 0); - SYMS_String8 dir_id_syms = syms_str8(0,0); + SYMS_String8 dir_id_syms = syms_str8_zero(); if (dir_id.type == COFF_ResourceIDType_NUMBER) { dir_id_syms = syms_pe_resource_type_to_string(dir_id.u.number); } @@ -4612,7 +4582,7 @@ lnk_dump_resource_dir_(COFF_ResourceID dir_id, PE_ResourceDir *dir) } break; case PE_ResData_COFF_RESOURCE: { SYMS_String8 id_syms = syms_coff_resource_id_to_string(scratch.arena, res->id); - SYMS_String8 type_syms = syms_str8(0,0); + SYMS_String8 type_syms = syms_str8_zero(); if (res->u.coff_res.type.type == COFF_ResourceIDType_NUMBER) { type_syms = syms_pe_resource_type_to_string(res->u.coff_res.type.u.number); } diff --git a/src/linker/lnk.h b/src/linker/lnk.h index a0875c6d..871be5dc 100644 --- a/src/linker/lnk.h +++ b/src/linker/lnk.h @@ -254,7 +254,6 @@ internal void lnk_push_loaded_lib(Arena *arena, HashTable *default_lib_ht, Ha internal String8 lnk_make_linker_manifest(Arena *arena, B32 manifest_uac, String8 manifest_level, String8 manifest_ui_access, String8List manifest_dependency_list); internal void lnk_merge_manifest_files(String8 mt_path, String8 out_name, String8List manifest_path_list); -internal String8 lnk_res_from_data(Arena *arena, String8 data); //////////////////////////////// // Resources diff --git a/src/linker/lnk_config.c b/src/linker/lnk_config.c index 45e099c7..e8d26fd5 100644 --- a/src/linker/lnk_config.c +++ b/src/linker/lnk_config.c @@ -832,7 +832,7 @@ lnk_config_from_cmd_line(Arena *arena, String8List raw_cmd_line) // parse command line String8List unwrapped_cmd_line = lnk_unwrap_rsp(scratch.arena, raw_cmd_line); - LNK_CmdLine cmd_line = lnk_cmd_line_parse_windows_rules(scratch.arena, unwrapped_cmd_line); + LNK_CmdLine cmd_line = lnk_cmd_line_parse_windows_rules(scratch.arena, unwrapped_cmd_line); // setup default flags lnk_cmd_line_push_option_if_not_presentf(scratch.arena, &cmd_line, LNK_CmdSwitch_Align, "%u", KB(4)); @@ -1132,25 +1132,21 @@ lnk_config_from_cmd_line(Arena *arena, String8List raw_cmd_line) config->manifest_opt = LNK_ManifestOpt_Embed; if (param_arr.count == 1) { - if (lnk_cmd_line_has_switch(cmd_line, LNK_CmdSwitch_Dll)) { - config->manifest_resource_id = 2; - } else { - config->manifest_resource_id = 1; - } + config->manifest_resource_id = 0; } else if (param_arr.count > 1) { // parse resource id if (str8_match(param_arr.v[1], str8_lit("id="), StringMatchFlag_RightSideSloppy|StringMatchFlag_CaseInsensitive)) { - String8List res_id_list = str8_split_by_string_chars(scratch.arena, param_arr.v[1], str8_lit("="), 0); - String8Array res_id_arr = str8_array_from_list(scratch.arena, &res_id_list); + String8List res_id_list = str8_split_by_string_chars(scratch.arena, param_arr.v[1], str8_lit("="), 0); + String8Array res_id_arr = str8_array_from_list(scratch.arena, &res_id_list); if (res_id_arr.count == 2) { U64 resource_id; if (try_u64_from_str8_c_rules(res_id_arr.v[1], &resource_id)) { - config->manifest_resource_id = resource_id; + config->manifest_resource_id = push_u64(arena, resource_id); } else { lnk_error_cmd_switch(LNK_Error_Cmdl, cmd_switch, "unable to parse resource_id \"%S\"", res_id_arr.v[1]); } } else { - lnk_error_cmd_switch(LNK_Error_Cmdl, cmd_switch, "invalid syntax expected form ID=resource_id but got \"%S\"", param_arr.v[1]); + lnk_error_cmd_switch(LNK_Error_Cmdl, cmd_switch, "invalid syntax expected form ID=# but got \"%S\"", param_arr.v[1]); } } else { lnk_error_cmd_switch_invalid_param(LNK_Error_Cmdl, cmd_switch, param_arr.v[0]); @@ -1168,6 +1164,8 @@ lnk_config_from_cmd_line(Arena *arena, String8List raw_cmd_line) } } else if (cmd->value_strings.node_count == 0) { config->manifest_opt = LNK_ManifestOpt_WriteToFile; + } else { + lnk_error_cmd_switch_invalid_param_count(LNK_Error_Cmdl, cmd_switch); } } break; @@ -1616,6 +1614,15 @@ lnk_config_from_cmd_line(Arena *arena, String8List raw_cmd_line) } } + // set default manifest resource id + if (config->manifest_resource_id == 0) { + if (config->file_characteristics & PE_ImageFileCharacteristic_FILE_DLL) { + config->manifest_resource_id = push_u64(arena, 2); + } else { + config->manifest_resource_id = push_u64(arena, 1); + } + } + // input files for (String8Node *input_node = cmd_line.input_list.first; input_node != 0; input_node = input_node->next) { String8 path = push_str8_copy(arena, input_node->string); diff --git a/src/linker/lnk_config.h b/src/linker/lnk_config.h index eb3af973..8b8147d2 100644 --- a/src/linker/lnk_config.h +++ b/src/linker/lnk_config.h @@ -247,7 +247,7 @@ typedef struct LNK_Config U64 pdb_page_size; U64 worker_count; U64 function_pad_min; - U64 manifest_resource_id; + U64 *manifest_resource_id; Version link_ver; Version os_ver; Version image_ver; diff --git a/src/pe/pe.c b/src/pe/pe.c index b4496741..a99c195c 100644 --- a/src/pe/pe.c +++ b/src/pe/pe.c @@ -901,6 +901,21 @@ pe_resource_table_from_directory_data(Arena *arena, String8 data) return bottom_frame->table; } +internal String8 +pe_make_manifest_resource(Arena *arena, U32 resource_id, String8 manifest_data) +{ + COFF_ResourceID type = {0}; + type.type = COFF_ResourceIDType_NUMBER; + type.u.number = PE_ResourceKind_MANIFEST; + + COFF_ResourceID id = {0}; + id.type = COFF_ResourceIDType_NUMBER; + id.u.number = resource_id; + + String8 res = coff_write_resource(arena, type, id, 1, 0, 1033, 0, 0, manifest_data); + return res; +} + //////////////////////////////// //~ Debug Directory diff --git a/src/pe/pe.h b/src/pe/pe.h index 3835dc6e..331dd3a6 100644 --- a/src/pe/pe.h +++ b/src/pe/pe.h @@ -452,8 +452,6 @@ struct PE_TLSHeader64 U32 characteristics; // COFF_SectionFlags but only align flags are used. }; -#define PE_RES_ALIGN 4u - global read_only U8 PE_RES_MAGIC[] = { 0x00, 0x00, 0x00, 0x00, @@ -781,6 +779,8 @@ internal PE_Resource * pe_resource_dir_search(PE_ResourceDir *dir, COFF_Reso internal PE_ResourceArray pe_resource_list_to_array(Arena *arena, PE_ResourceList *list); internal PE_ResourceDir * pe_resource_table_from_directory_data(Arena *arena, String8 data); +internal String8 pe_make_manifest_resource(Arena *arena, U32 resource_id, String8 manifest_data); + //////////////////////////////// //~ Debug Directory