pass over COFF resource reader and writer

This commit is contained in:
Nikita Smith
2024-10-19 13:44:36 -07:00
parent 46390ba0b8
commit 800a2349e5
8 changed files with 347 additions and 367 deletions
+119 -130
View File
@@ -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;
}
+17 -17
View File
@@ -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);
+176 -206
View File
@@ -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);
}
-1
View File
@@ -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
+17 -10
View File
@@ -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);
+1 -1
View File
@@ -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;
+15
View File
@@ -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
+2 -2
View File
@@ -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