make import lib objs with COFF obj writer

This commit is contained in:
Nikita Smith
2025-04-16 13:53:35 -07:00
committed by Ryan Fleury
parent e580b69180
commit 3a2bb318c7
8 changed files with 352 additions and 489 deletions
+15 -1
View File
@@ -21,6 +21,7 @@ read_only global U8 g_coff_thin_archive_sig[8] = "!<thin>\n";
#pragma pack(push, 1)
#define COFF_TimeStamp_Max max_U32
typedef U32 COFF_TimeStamp;
typedef U16 COFF_FileHeaderFlags;
@@ -135,6 +136,20 @@ enum
COFF_SectionFlag_MemPreload = (1 << 19),
COFF_SectionFlag_AlignShift = 20,
COFF_SectionFlag_AlignMask = 0xf,
COFF_SectionFlag_Align1Bytes = (COFF_SectionAlign_1Bytes << COFF_SectionFlag_AlignShift),
COFF_SectionFlag_Align2Bytes = (COFF_SectionAlign_2Bytes << COFF_SectionFlag_AlignShift),
COFF_SectionFlag_Align4Bytes = (COFF_SectionAlign_4Bytes << COFF_SectionFlag_AlignShift),
COFF_SectionFlag_Align8Bytes = (COFF_SectionAlign_8Bytes << COFF_SectionFlag_AlignShift),
COFF_SectionFlag_Align16Bytes = (COFF_SectionAlign_16Bytes << COFF_SectionFlag_AlignShift),
COFF_SectionFlag_Align32Bytes = (COFF_SectionAlign_32Bytes << COFF_SectionFlag_AlignShift),
COFF_SectionFlag_Align64Bytes = (COFF_SectionAlign_64Bytes << COFF_SectionFlag_AlignShift),
COFF_SectionFlag_Align128Bytes = (COFF_SectionAlign_128Bytes << COFF_SectionFlag_AlignShift),
COFF_SectionFlag_Align256Bytes = (COFF_SectionAlign_256Bytes << COFF_SectionFlag_AlignShift),
COFF_SectionFlag_Align512Bytes = (COFF_SectionAlign_512Bytes << COFF_SectionFlag_AlignShift),
COFF_SectionFlag_Align1024Bytes = (COFF_SectionAlign_1024Bytes << COFF_SectionFlag_AlignShift),
COFF_SectionFlag_Align2048Bytes = (COFF_SectionAlign_2048Bytes << COFF_SectionFlag_AlignShift),
COFF_SectionFlag_Align4096Bytes = (COFF_SectionAlign_4096Bytes << COFF_SectionFlag_AlignShift),
COFF_SectionFlag_Align8192Bytes = (COFF_SectionAlign_8192Bytes << COFF_SectionFlag_AlignShift),
COFF_SectionFlag_LnkNRelocOvfl = (1 << 24),
COFF_SectionFlag_MemDiscardable = (1 << 25),
COFF_SectionFlag_MemNotCached = (1 << 26),
@@ -144,7 +159,6 @@ enum
COFF_SectionFlag_MemRead = (1 << 30),
COFF_SectionFlag_MemWrite = (1 << 31)
};
#define COFF_SectionFlags_PackAlign(f) ((f) << COFF_SectionFlag_AlignShift)
#define COFF_SectionFlags_ExtractAlign(f) (COFF_SectionAlign)(((f) >> COFF_SectionFlag_AlignShift) & COFF_SectionFlag_AlignMask)
#define COFF_SectionFlags_LnkFlags ((COFF_SectionFlag_AlignMask << COFF_SectionFlag_AlignShift) | COFF_SectionFlag_LnkCOMDAT | COFF_SectionFlag_LnkInfo | COFF_SectionFlag_LnkOther | COFF_SectionFlag_LnkRemove | COFF_SectionFlag_LnkNRelocOvfl)
+64 -12
View File
@@ -17,7 +17,7 @@ coff_obj_writer_release(COFF_ObjWriter **obj_writer)
}
internal COFF_ObjSymbol *
coff_obj_writer_push_symbol(COFF_ObjWriter *obj_writer, String8 name, U32 value, COFF_ObjSection *section, COFF_SymbolType type, COFF_SymStorageClass storage_class)
coff_obj_writer_push_symbol(COFF_ObjWriter *obj_writer, String8 name, U32 value, COFF_SymbolLocation loc, COFF_SymbolType type, COFF_SymStorageClass storage_class)
{
COFF_ObjSymbolNode *n = push_array(obj_writer->arena, COFF_ObjSymbolNode, 1);
SLLQueuePush(obj_writer->symbol_first, obj_writer->symbol_last, n);
@@ -26,7 +26,7 @@ coff_obj_writer_push_symbol(COFF_ObjWriter *obj_writer, String8 name, U32 value,
COFF_ObjSymbol *s = &n->v;
s->name = name;
s->value = value;
s->section = section;
s->loc = loc;
s->type = type;
s->storage_class = storage_class;
s->idx = obj_writer->symbol_count-1;
@@ -35,16 +35,41 @@ coff_obj_writer_push_symbol(COFF_ObjWriter *obj_writer, String8 name, U32 value,
}
internal COFF_ObjSymbol *
coff_obj_writer_push_symbol_static(COFF_ObjWriter *obj_writer, String8 name, U32 off, COFF_ObjSection *section)
coff_obj_writer_push_symbol_external(COFF_ObjWriter *obj_writer, String8 name, U32 value, COFF_ObjSection *section)
{
COFF_ObjSymbol *s = coff_obj_writer_push_symbol(obj_writer, name, off, section, (COFF_SymbolType){0}, COFF_SymStorageClass_Static);
COFF_SymbolLocation loc = {0};
loc.type = COFF_SymbolLocation_Section;
loc.u.section = section;
COFF_ObjSymbol *s = coff_obj_writer_push_symbol(obj_writer, name, value, loc, (COFF_SymbolType){0}, COFF_SymStorageClass_External);
return s;
}
internal COFF_ObjSymbol *
coff_obj_writer_push_symbol_abs(COFF_ObjWriter *obj_writer, String8 name, COFF_SymStorageClass storage_class, U32 value)
coff_obj_writer_push_symbol_static(COFF_ObjWriter *obj_writer, String8 name, U32 off, COFF_ObjSection *section)
{
COFF_ObjSymbol *s = coff_obj_writer_push_symbol(obj_writer, name, value, 0, (COFF_SymbolType){0}, storage_class);
COFF_SymbolLocation loc = {0};
loc.type = COFF_SymbolLocation_Section;
loc.u.section = section;
COFF_ObjSymbol *s = coff_obj_writer_push_symbol(obj_writer, name, off, loc, (COFF_SymbolType){0}, COFF_SymStorageClass_Static);
return s;
}
internal COFF_ObjSymbol *
coff_obj_writer_push_symbol_abs(COFF_ObjWriter *obj_writer, String8 name, U32 value, COFF_SymStorageClass storage_class)
{
COFF_SymbolLocation loc = {0};
loc.type = COFF_SymbolLocation_Abs;
COFF_ObjSymbol *s = coff_obj_writer_push_symbol(obj_writer, name, value, loc, (COFF_SymbolType){0}, storage_class);
return s;
}
internal COFF_ObjSymbol *
coff_obj_writer_push_symbol_undef(COFF_ObjWriter *obj_writer, String8 name)
{
COFF_SymbolType type = {0};
COFF_SymbolLocation loc = {0};
loc.type = COFF_SymbolLocation_Undef;
COFF_ObjSymbol *s = coff_obj_writer_push_symbol(obj_writer, name, 0, loc, type, COFF_SymStorageClass_External);
return s;
}
@@ -53,7 +78,34 @@ coff_obj_writer_push_symbol_undef_func(COFF_ObjWriter *obj_writer, String8 name)
{
COFF_SymbolType type = {0};
type.u.msb = COFF_SymDType_Func;
COFF_ObjSymbol *s = coff_obj_writer_push_symbol(obj_writer, name, 0, 0, type, COFF_SymStorageClass_External);
COFF_SymbolLocation loc = {0};
loc.type = COFF_SymbolLocation_Undef;
COFF_ObjSymbol *s = coff_obj_writer_push_symbol(obj_writer, name, 0, loc, type, COFF_SymStorageClass_External);
return s;
}
internal COFF_ObjSymbol *
coff_obj_writer_push_symbol_undef_sect(COFF_ObjWriter *obj_writer, String8 name, U32 value)
{
COFF_SymbolType type = {0};
COFF_SymbolLocation loc = {0};
loc.type = COFF_SymbolLocation_Undef;
COFF_ObjSymbol *s = coff_obj_writer_push_symbol(obj_writer, name, value, loc, type, COFF_SymStorageClass_Section);
return s;
}
internal COFF_ObjSymbol *
coff_obj_writer_push_symbol_sect(COFF_ObjWriter *obj_writer, String8 name, COFF_ObjSection *sect)
{
COFF_SymbolType type = {0};
COFF_SymbolLocation loc = {0};
loc.type = COFF_SymbolLocation_Section;
loc.u.section = sect;
// strip align flags
COFF_SectionFlags expected_flags = sect->flags & ~(COFF_SectionFlag_AlignMask << COFF_SectionFlag_AlignShift);
COFF_ObjSymbol *s = coff_obj_writer_push_symbol(obj_writer, name, expected_flags, loc, type, COFF_SymStorageClass_Section);
return s;
}
@@ -67,7 +119,6 @@ coff_obj_writer_push_section(COFF_ObjWriter *obj_writer, String8 name, COFF_Sect
COFF_ObjSection *sect = &sect_n->v;
sect->name = name;
sect->flags = flags;
sect->symbol = coff_obj_writer_push_symbol_static(obj_writer, name, 0, sect);
str8_list_push(obj_writer->arena, &sect->data, data);
@@ -234,10 +285,11 @@ coff_obj_writer_serialize(Arena *arena, COFF_ObjWriter *obj_writer)
AssertAlways(s->aux_symbols.node_count <= max_U8);
d->name = name;
d->value = s->value;
if (s->section == 0) {
d->section_number = COFF_Symbol_AbsSection16;
} else {
d->section_number = safe_cast_u16(s->section->section_number);
switch (s->loc.type) {
case COFF_SymbolLocation_Null: break;
case COFF_SymbolLocation_Section: d->section_number = safe_cast_u16(s->loc.u.section->section_number); break;
case COFF_SymbolLocation_Abs: d->section_number = COFF_Symbol_AbsSection16; break;
case COFF_SymbolLocation_Undef: d->section_number = COFF_Symbol_UndefinedSection; break;
}
d->type = s->type;
d->storage_class = s->storage_class;
+18 -3
View File
@@ -1,11 +1,27 @@
#ifndef COFF_OBJ_WRITER_H
#define COFF_OBJ_WRITER_H
typedef enum
{
COFF_SymbolLocation_Null,
COFF_SymbolLocation_Section,
COFF_SymbolLocation_Abs,
COFF_SymbolLocation_Undef
} COFF_SymbolLocationType;
typedef struct COFF_SymbolLocation
{
COFF_SymbolLocationType type;
union {
struct COFF_ObjSection *section;
} u;
} COFF_SymbolLocation;
typedef struct COFF_ObjSymbol
{
String8 name;
U32 value;
struct COFF_ObjSection *section;
COFF_SymbolLocation loc;
COFF_SymbolType type;
COFF_SymStorageClass storage_class;
String8List aux_symbols;
@@ -36,7 +52,6 @@ typedef struct COFF_ObjSection
String8 name;
String8List data;
COFF_SectionFlags flags;
COFF_ObjSymbol *symbol;
U64 reloc_count;
COFF_ObjRelocNode *reloc_first;
@@ -71,7 +86,7 @@ typedef struct COFF_ObjWriter
internal COFF_ObjWriter* coff_obj_writer_alloc(COFF_TimeStamp time_stamp, COFF_MachineType machine_type);
internal void coff_obj_writer_release(COFF_ObjWriter **obj_writer);
internal COFF_ObjSection* coff_obj_writer_push_section(COFF_ObjWriter *obj_writer, String8 name, COFF_SectionFlags flags, String8 data);
internal COFF_ObjSymbol* coff_obj_writer_push_symbol(COFF_ObjWriter *obj_writer, String8 name, U32 value, COFF_ObjSection *section, COFF_SymbolType type, COFF_SymStorageClass storage_class);
internal COFF_ObjSymbol* coff_obj_writer_push_symbol(COFF_ObjWriter *obj_writer, String8 name, U32 value, COFF_SymbolLocation loc, COFF_SymbolType type, COFF_SymStorageClass storage_class);
internal COFF_ObjReloc* coff_obj_writer_section_push_reloc(COFF_ObjWriter *obj_writer, COFF_ObjSection *sect, U32 apply_off, COFF_ObjSymbol *symbol, COFF_RelocType reloc_type);
#endif // COFF_OBJ_WRITER_H
+8 -27
View File
@@ -121,6 +121,7 @@
#include "lnk_reloc.h"
#include "lnk_symbol_table.h"
#include "lnk_section_table.h"
#include "lnk_debug_helper.h"
#include "lnk_obj.h"
#include "lnk_import_table.h"
#include "lnk_export_table.h"
@@ -139,6 +140,7 @@
#include "lnk_symbol_table.c"
#include "lnk_section_table.c"
#include "lnk_obj.c"
#include "lnk_debug_helper.c"
#include "lnk_import_table.c"
#include "lnk_export_table.c"
#include "lnk_lib.c"
@@ -763,27 +765,16 @@ lnk_make_linker_coff_obj(Arena *arena,
{
Temp scratch = scratch_begin(&arena, 1);
String8 debug_s_data = {0};
String8 debug_symbols = {0};
{
CV_SymbolList symbol_list = {0};
symbol_list.signature = CV_Signature_C13;
CV_SymbolList symbol_list = { .signature = CV_Signature_C13 };
// S_OBJ
String8 obj_data = cv_make_obj_name(scratch.arena, obj_name, 0);
cv_symbol_list_push_data(scratch.arena, &symbol_list, CV_SymKind_OBJNAME, obj_data);
// S_COMPILE3
CV_Arch cv_arch = cv_arch_from_coff_machine(machine);
U64 ver_fe_major = 0;
U64 ver_fe_minor = 0;
U64 ver_fe_build = 0;
U64 ver_feqfe = 0;
U64 ver_major = 14;
U64 ver_minor = 36;
U64 ver_build = 32537;
U64 ver_qfe = 0;
String8 version_string = push_str8f(scratch.arena, "Epic Games Tools (R) RAD Linker");
String8 comp3_data = cv_make_comp3(scratch.arena, 0, CV_Language_LINK, cv_arch, ver_fe_major, ver_fe_minor, ver_fe_build, ver_feqfe, ver_major, ver_minor, ver_build, ver_qfe, version_string);
String8 comp3_data = lnk_make_linker_compile3(scratch.arena, machine);
cv_symbol_list_push_data(scratch.arena, &symbol_list, CV_SymKind_COMPILE3, comp3_data);
// S_ENVBLOCK
@@ -798,28 +789,18 @@ lnk_make_linker_coff_obj(Arena *arena,
str8_list_push(scratch.arena, &env_list, cmd_line);
str8_list_push(scratch.arena, &env_list, str8_lit(""));
str8_list_push(scratch.arena, &env_list, str8_lit(""));
String8 env_data = cv_make_envblock(scratch.arena, env_list);
cv_symbol_list_push_data(scratch.arena, &symbol_list, CV_SymKind_ENVBLOCK, env_data);
cv_symbol_list_push_data(scratch.arena, &symbol_list, CV_SymKind_ENVBLOCK, cv_make_envblock(scratch.arena, env_list));
// TODO: emit S_SECTION and S_COFFGROUP
// TODO: emit S_TRAMPOLINE
String8List symbol_data_list = cv_data_from_symbol_list(scratch.arena, symbol_list, CV_SymbolAlign);
CV_DebugS debug_s = {0};
String8List *symbols_list_ptr = cv_sub_section_ptr_from_debug_s(&debug_s, CV_C13SubSectionKind_Symbols);
*symbols_list_ptr = symbol_data_list;
B32 include_sig = 1;
String8List debug_s_data_list = cv_data_c13_from_debug_s(scratch.arena, &debug_s, include_sig);
debug_s_data = str8_list_join(scratch.arena, &debug_s_data_list, 0);
debug_symbols = lnk_make_debug_s(scratch.arena, symbol_list);
}
String8 obj;
{
COFF_ObjWriter *obj_writer = coff_obj_writer_alloc(time_stamp, machine);
coff_obj_writer_push_section(obj_writer, str8_lit(".debug$S"), LNK_DEBUG_SECTION_FLAGS, debug_s_data);
coff_obj_writer_push_section(obj_writer, str8_lit(".debug$S"), LNK_DEBUG_SECTION_FLAGS|COFF_SectionFlag_Align1Bytes, debug_symbols);
obj = coff_obj_writer_serialize(arena, obj_writer);
coff_obj_writer_release(&obj_writer);
}
+2 -2
View File
@@ -89,8 +89,8 @@
#define LNK_IDATA_SECTION_FLAGS LNK_DATA_SECTION_FLAGS
#define LNK_DEBUG_DIR_SECTION_FLAGS LNK_DATA_SECTION_FLAGS
#define LNK_RSRC_SECTION_FLAGS LNK_DATA_SECTION_FLAGS
#define LNK_RSRC1_SECTION_FLAGS (LNK_DATA_SECTION_FLAGS | COFF_SectionFlags_PackAlign(COFF_SectionAlign_4Bytes))
#define LNK_RSRC2_SECTION_FLAGS (LNK_DATA_SECTION_FLAGS | COFF_SectionFlags_PackAlign(COFF_SectionAlign_4Bytes))
#define LNK_RSRC1_SECTION_FLAGS (LNK_DATA_SECTION_FLAGS | COFF_SectionFlag_Align4Bytes)
#define LNK_RSRC2_SECTION_FLAGS (LNK_DATA_SECTION_FLAGS | COFF_SectionFlag_Align4Bytes)
#define LNK_XDATA_SECTION_FLAGS LNK_RDATA_SECTION_FLAGS
#define LNK_PDATA_SECTION_FLAGS LNK_RDATA_SECTION_FLAGS
#define LNK_EDATA_SECTION_FLAGS LNK_RDATA_SECTION_FLAGS
+111 -320
View File
@@ -536,352 +536,143 @@ lnk_build_lib(Arena *arena, COFF_MachineType machine, COFF_TimeStamp time_stamp,
return lib;
}
internal String8List
lnk_build_import_entry_obj(Arena *arena, String8 dll_name, COFF_MachineType machine)
internal String8
lnk_build_import_entry_obj(Arena *arena, String8 dll_name, COFF_TimeStamp time_stamp, COFF_MachineType machine)
{
ProfBeginFunction();
Temp scratch = scratch_begin(&arena, 1);
Assert(machine == COFF_MachineType_X64);
Assert(str8_match_lit("dll", str8_skip_last_dot(dll_name), StringMatchFlag_CaseInsensitive|StringMatchFlag_RightSideSloppy));
String8List list = {0};
COFF_FileHeader *file_header = push_array(arena, COFF_FileHeader, 1);
file_header->machine = machine;
str8_list_push(arena, &list, str8_struct(file_header));
file_header->section_count = 2;
COFF_SectionHeader *coff_sect_header_array = push_array(arena, COFF_SectionHeader, file_header->section_count);
str8_list_push(arena, &list, str8_array(coff_sect_header_array, file_header->section_count));
PE_ImportEntry *import_entry = push_array(arena, PE_ImportEntry, 1);
U64 import_entry_off = list.total_size;
str8_list_push(arena, &list, str8_struct(import_entry));
String8 dll_name_cstr = push_cstr(arena, dll_name);
U64 dll_name_off = list.total_size;
str8_list_push(arena, &list, dll_name_cstr);
U32 import_entry_reloc_count = 3;
COFF_Reloc *import_entry_reloc_array = push_array(arena, COFF_Reloc, import_entry_reloc_count);
U64 import_entry_reloc_off = list.total_size;
str8_list_push(arena, &list, str8_array(import_entry_reloc_array, import_entry_reloc_count));
file_header->symbol_count = 7;
COFF_Symbol16 *symbol_array = push_array(arena, COFF_Symbol16, file_header->symbol_count);
file_header->symbol_table_foff = safe_cast_u32(list.total_size);
str8_list_push(arena, &list, str8_array(symbol_array, file_header->symbol_count));
U64 string_table_base = list.total_size;
U32 *string_table_size_ptr = push_array(arena, U32, 1);
str8_list_push(arena, &list, str8_struct(string_table_size_ptr));
// PE_ImportEntry
String8 dll_name_no_ext = str8_chop_last_dot(dll_name);
COFF_ObjWriter *obj_writer = coff_obj_writer_alloc(time_stamp, machine);
String8 debug_symbols;
{
COFF_SectionHeader *sect = &coff_sect_header_array[0];
sect->name[0] = '.';
sect->name[1] = 'i';
sect->name[2] = 'd';
sect->name[3] = 'a';
sect->name[4] = 't';
sect->name[5] = 'a';
sect->name[6] = '$';
sect->name[7] = '2';
sect->fsize = sizeof(PE_ImportEntry);
sect->foff = import_entry_off;
sect->reloc_count = import_entry_reloc_count;
sect->relocs_foff = import_entry_reloc_off;
sect->flags = COFF_SectionFlag_CntInitializedData|(COFF_SectionAlign_4Bytes << COFF_SectionFlag_AlignShift)|COFF_SectionFlag_MemRead|COFF_SectionFlag_MemWrite;
CV_SymbolList symbol_list = { .signature = CV_Signature_C13 };
String8 comp3_data = lnk_make_linker_compile3(scratch.arena, machine);
cv_symbol_list_push_data(scratch.arena, &symbol_list, CV_SymKind_COMPILE3, comp3_data);
debug_symbols = lnk_make_debug_s(obj_writer->arena, symbol_list);
}
String8 dll_name_cstr = push_cstr(obj_writer->arena, dll_name);
COFF_ObjSection *debugs = coff_obj_writer_push_section(obj_writer, str8_lit(".debug$S"), LNK_DEBUG_SECTION_FLAGS|COFF_SectionFlag_Align1Bytes, debug_symbols);
COFF_ObjSection *idata2 = coff_obj_writer_push_section(obj_writer, str8_lit(".idata$2"), LNK_DATA_SECTION_FLAGS|COFF_SectionFlag_Align4Bytes, str8_zero());
COFF_ObjSection *idata6 = coff_obj_writer_push_section(obj_writer, str8_lit(".idata$6"), LNK_DATA_SECTION_FLAGS|COFF_SectionFlag_Align2Bytes, dll_name_cstr);
coff_obj_writer_push_symbol_abs(obj_writer, str8_lit("@comp.id"), 0x1018175, COFF_SymStorageClass_Static);
{
COFF_Reloc *lookup_table_voff_reloc = &import_entry_reloc_array[0];
lookup_table_voff_reloc->apply_off = OffsetOf(PE_ImportEntry, lookup_table_voff);
lookup_table_voff_reloc->isymbol = 3;
lookup_table_voff_reloc->type = COFF_Reloc_X64_Addr32Nb;
COFF_Reloc *name_voff_reloc = &import_entry_reloc_array[1];
name_voff_reloc->apply_off = OffsetOf(PE_ImportEntry, name_voff);
name_voff_reloc->isymbol = 2;
name_voff_reloc->type = COFF_Reloc_X64_Addr32Nb;
COFF_Reloc *import_addr_table_voff = &import_entry_reloc_array[2];
import_addr_table_voff->apply_off = OffsetOf(PE_ImportEntry, import_addr_table_voff);
import_addr_table_voff->isymbol = 4;
import_addr_table_voff->type = COFF_Reloc_X64_Addr32Nb;
}
// dll name
{
COFF_SectionHeader *sect = &coff_sect_header_array[1];
sect->name[0] = '.';
sect->name[1] = 'i';
sect->name[2] = 'd';
sect->name[3] = 'a';
sect->name[4] = 't';
sect->name[5] = 'a';
sect->name[6] = '$';
sect->name[7] = '6';
sect->fsize = dll_name_cstr.size;
sect->foff = dll_name_off;
sect->flags = COFF_SectionFlag_CntInitializedData|(COFF_SectionAlign_2Bytes << COFF_SectionFlag_AlignShift)|COFF_SectionFlag_MemRead|COFF_SectionFlag_MemWrite;
}
// import descriptor
{
String8 dll_name_no_ext = str8_substr(dll_name, r1u64(0, dll_name.size - 4));
String8 symbol_name = push_str8f(arena, "__IMPORT_DESCRIPTOR_%S", dll_name_no_ext);
U64 symbol_name_off = (list.total_size - string_table_base);
str8_list_push(arena, &list, push_cstr(arena, symbol_name));
COFF_Symbol16 *symbol = &symbol_array[0];
symbol->name.long_name.zeroes = 0;
symbol->name.long_name.string_table_offset = symbol_name_off;
symbol->section_number = 1;
symbol->storage_class = COFF_SymStorageClass_External;
coff_obj_writer_push_symbol_external(obj_writer, symbol_name, 0, idata2);
}
// .idata$2
COFF_ObjSymbol *idata2_symbol = coff_obj_writer_push_symbol_sect(obj_writer, idata2->name, idata2);
COFF_ObjSymbol *idata6_symbol = coff_obj_writer_push_symbol_static(obj_writer, idata6->name, 0, idata6);
COFF_ObjSymbol *idata4_symbol = coff_obj_writer_push_symbol_undef_sect(obj_writer, str8_lit(".idata$4"), COFF_SectionFlag_MemWrite|COFF_SectionFlag_MemRead|COFF_SectionFlag_CntInitializedData);
COFF_ObjSymbol *idata5_symbol = coff_obj_writer_push_symbol_undef_sect(obj_writer, str8_lit(".idata$5"), COFF_SectionFlag_MemWrite|COFF_SectionFlag_MemRead|COFF_SectionFlag_CntInitializedData);
coff_obj_writer_push_symbol_undef(obj_writer, str8_lit("__NULL_IMPORT_DESCRIPTOR"));
{
COFF_Symbol16 *symbol = &symbol_array[1];
symbol->name.short_name[0] = '.';
symbol->name.short_name[1] = 'i';
symbol->name.short_name[2] = 'd';
symbol->name.short_name[3] = 'a';
symbol->name.short_name[4] = 't';
symbol->name.short_name[5] = 'a';
symbol->name.short_name[6] = '$';
symbol->name.short_name[7] = '2';
symbol->section_number = 1;
symbol->storage_class = COFF_SymStorageClass_Section;
}
// .idata$6
{
COFF_Symbol16 *symbol = &symbol_array[2];
symbol->name.short_name[0] = '.';
symbol->name.short_name[1] = 'i';
symbol->name.short_name[2] = 'd';
symbol->name.short_name[3] = 'a';
symbol->name.short_name[4] = 't';
symbol->name.short_name[5] = 'a';
symbol->name.short_name[6] = '$';
symbol->name.short_name[7] = '6';
symbol->section_number = 2;
symbol->storage_class = COFF_SymStorageClass_Static;
}
// .idata$4
{
COFF_Symbol16 *symbol = &symbol_array[3];
symbol->name.short_name[0] = '.';
symbol->name.short_name[1] = 'i';
symbol->name.short_name[2] = 'd';
symbol->name.short_name[3] = 'a';
symbol->name.short_name[4] = 't';
symbol->name.short_name[5] = 'a';
symbol->name.short_name[6] = '$';
symbol->name.short_name[7] = '4';
symbol->section_number = COFF_Symbol_UndefinedSection;
symbol->storage_class = COFF_SymStorageClass_Section;
}
// .idata$5
{
COFF_Symbol16 *symbol = &symbol_array[4];
symbol->name.short_name[0] = '.';
symbol->name.short_name[1] = 'i';
symbol->name.short_name[2] = 'd';
symbol->name.short_name[3] = 'a';
symbol->name.short_name[4] = 't';
symbol->name.short_name[5] = 'a';
symbol->name.short_name[6] = '$';
symbol->name.short_name[7] = '5';
symbol->section_number = COFF_Symbol_UndefinedSection;
symbol->storage_class = COFF_SymStorageClass_Section;
}
// __NULL_IMPORT_DESCRIPTOR
{
U64 symbol_name_off = (list.total_size - string_table_base);
str8_list_push(arena, &list, push_cstr(arena, str8_lit("__NULL_IMPORT_DESCRIPTOR")));
COFF_Symbol16 *symbol = &symbol_array[5];
symbol->name.long_name.zeroes = 0;
symbol->name.long_name.string_table_offset = symbol_name_off;
symbol->section_number = COFF_Symbol_UndefinedSection;
symbol->storage_class = COFF_SymStorageClass_External;
}
// NULL_THUNK_DATA
{
String8 dll_name_no_ext = str8_substr(dll_name, r1u64(0, dll_name.size - 4));
String8 symbol_name = push_str8f(arena, "\x7f%S_NULL_THUNK_DATA", dll_name_no_ext);
U64 symbol_name_off = (list.total_size - string_table_base);
str8_list_push(arena, &list, push_cstr(arena, symbol_name));
COFF_Symbol16 *symbol = &symbol_array[6];
symbol->name.long_name.zeroes = 0;
symbol->name.long_name.string_table_offset = symbol_name_off;
symbol->section_number = COFF_Symbol_UndefinedSection;
symbol->storage_class = COFF_SymStorageClass_External;
coff_obj_writer_push_symbol_undef(obj_writer, symbol_name);
}
// update string table size
*string_table_size_ptr = (list.total_size - string_table_base);
{
PE_ImportEntry *import_entry = push_array(obj_writer->arena, PE_ImportEntry, 1);
str8_list_push(obj_writer->arena, &idata2->data, str8_struct(import_entry));
coff_obj_writer_section_push_reloc(obj_writer, idata2, OffsetOf(PE_ImportEntry, name_voff), idata6_symbol, COFF_Reloc_X64_Addr32Nb);
coff_obj_writer_section_push_reloc(obj_writer, idata2, OffsetOf(PE_ImportEntry, lookup_table_voff), idata4_symbol, COFF_Reloc_X64_Addr32Nb);
coff_obj_writer_section_push_reloc(obj_writer, idata2, OffsetOf(PE_ImportEntry, import_addr_table_voff), idata5_symbol, COFF_Reloc_X64_Addr32Nb);
}
String8 obj = coff_obj_writer_serialize(arena, obj_writer);
coff_obj_writer_release(&obj_writer);
scratch_end(scratch);
ProfEnd();
return list;
return obj;
}
internal String8List
lnk_build_null_import_descriptor_obj(Arena *arena, COFF_MachineType machine)
internal String8
lnk_build_null_import_descriptor_obj(Arena *arena, COFF_TimeStamp time_stamp, COFF_MachineType machine)
{
ProfBeginFunction();
String8List list = {0};
COFF_FileHeader *coff_header = push_array(arena, COFF_FileHeader, 1);
coff_header->machine = machine;
str8_list_push(arena, &list, str8_struct(coff_header));
coff_header->section_count = 1;
COFF_SectionHeader *coff_sect_header_array = push_array(arena, COFF_SectionHeader, coff_header->section_count);
str8_list_push(arena, &list, str8_array(coff_sect_header_array, coff_header->section_count));
U64 null_import_data_size = 20;
U8 *null_import_data = push_array(arena, U8, null_import_data_size);
U64 null_import_data_off = list.total_size;
str8_list_push(arena, &list, str8(null_import_data, null_import_data_size));
coff_header->symbol_count = 1;
COFF_Symbol16 *symbol_array = push_array(arena, COFF_Symbol16, coff_header->symbol_count);
coff_header->symbol_table_foff = safe_cast_u32(list.total_size);
str8_list_push(arena, &list, str8_array(symbol_array, coff_header->symbol_count));
U64 string_table_base = list.total_size;
U32 *string_table_size_ptr = push_array(arena, U32, 1);
str8_list_push(arena, &list, str8_struct(string_table_size_ptr));
Temp scratch = scratch_begin(&arena, 1);
COFF_ObjWriter *obj_writer = coff_obj_writer_alloc(time_stamp, machine);
String8 debug_symbols;
{
COFF_SectionHeader *sect = &coff_sect_header_array[0];
sect->name[0] = '.';
sect->name[1] = 'i';
sect->name[2] = 'd';
sect->name[3] = 'a';
sect->name[4] = 't';
sect->name[5] = 'a';
sect->name[6] = '$';
sect->name[7] = '3';
sect->fsize = null_import_data_size;
sect->foff = null_import_data_off;
sect->flags = COFF_SectionFlag_CntInitializedData|(COFF_SectionAlign_4Bytes << COFF_SectionFlag_AlignShift)|COFF_SectionFlag_MemRead|COFF_SectionFlag_MemWrite;
CV_SymbolList symbol_list = { .signature = CV_Signature_C13 };
String8 comp3_data = lnk_make_linker_compile3(scratch.arena, machine);
cv_symbol_list_push_data(scratch.arena, &symbol_list, CV_SymKind_COMPILE3, comp3_data);
debug_symbols = lnk_make_debug_s(obj_writer->arena, symbol_list);
}
{
U64 symbol_name_off = list.total_size - string_table_base;
str8_list_push(arena, &list, push_cstr(arena, str8_lit("__NULL_IMPORT_DESCRIPTOR")));
COFF_Symbol16 *symbol = &symbol_array[0];
symbol->name.long_name.zeroes = 0;
symbol->name.long_name.string_table_offset = symbol_name_off;
symbol->section_number = 1;
symbol->storage_class = COFF_SymStorageClass_External;
}
// update string table size
*string_table_size_ptr = (list.total_size - string_table_base);
PE_ImportEntry *import_desc = push_array(obj_writer->arena, PE_ImportEntry, 1);
COFF_ObjSection *debugs = coff_obj_writer_push_section(obj_writer, str8_lit(".debug$S"), LNK_DEBUG_SECTION_FLAGS|COFF_SectionFlag_Align1Bytes, debug_symbols);
COFF_ObjSection *idata3 = coff_obj_writer_push_section(obj_writer, str8_lit(".idata$3"), LNK_DATA_SECTION_FLAGS|COFF_SectionFlag_Align4Bytes, str8_struct(import_desc));
coff_obj_writer_push_symbol_abs(obj_writer, str8_lit("@comp.id"), 0x01018175, COFF_SymStorageClass_Static);
coff_obj_writer_push_symbol_external(obj_writer, str8_lit("__NULL_IMPORT_DESCRIPTOR"), 0, idata3);
String8 obj = coff_obj_writer_serialize(arena, obj_writer);
coff_obj_writer_release(&obj_writer);
scratch_end(scratch);
ProfEnd();
return list;
return obj;
}
internal String8List
lnk_build_null_thunk_data_obj(Arena *arena, String8 dll_name, COFF_MachineType machine)
internal String8
lnk_build_null_thunk_data_obj(Arena *arena, String8 dll_name, COFF_TimeStamp time_stamp, COFF_MachineType machine)
{
ProfBeginFunction();
Temp scratch = scratch_begin(&arena, 1);
Assert(str8_match_lit("dll", str8_skip_last_dot(dll_name), StringMatchFlag_CaseInsensitive|StringMatchFlag_RightSideSloppy));
String8List list = {0};
COFF_FileHeader *coff_header = push_array(arena, COFF_FileHeader, 1);
coff_header->machine = machine;
str8_list_push(arena, &list, str8_struct(coff_header));
coff_header->section_count = 2;
COFF_SectionHeader *coff_sect_header_array = push_array(arena, COFF_SectionHeader, coff_header->section_count);
str8_list_push(arena, &list, str8_array(coff_sect_header_array, coff_header->section_count));
U64 lookup_entry_data_size = 8;
U8 *lookup_entry_data = push_array(arena, U8, lookup_entry_data_size);
U64 lookup_entry_data_off = list.total_size;
str8_list_push(arena, &list, str8(lookup_entry_data, lookup_entry_data_size));
U64 null_thunk_data_size = 8;
U8 *null_thunk_data = push_array(arena, U8, null_thunk_data_size);
U64 null_thunk_data_off = list.total_size;
str8_list_push(arena, &list, str8(null_thunk_data, null_thunk_data_size));
coff_header->symbol_count = 1;
COFF_Symbol16 *symbol_array = push_array(arena, COFF_Symbol16, coff_header->symbol_count);
coff_header->symbol_table_foff = safe_cast_u32(list.total_size);
str8_list_push(arena, &list, str8_array(symbol_array, coff_header->symbol_count));
U64 string_table_base = list.total_size;
U32 *string_table_size_ptr = push_array(arena, U32, 1);
str8_list_push(arena, &list, str8_struct(string_table_size_ptr));
COFF_ObjWriter *obj_writer = coff_obj_writer_alloc(time_stamp, machine);
String8 debug_symbols;
{
COFF_SectionHeader *sect = &coff_sect_header_array[0];
sect->name[0] = '.';
sect->name[1] = 'i';
sect->name[2] = 'd';
sect->name[3] = 'a';
sect->name[4] = 't';
sect->name[5] = 'a';
sect->name[6] = '$';
sect->name[7] = '5';
sect->fsize = lookup_entry_data_size;
sect->foff = lookup_entry_data_off;
sect->flags = COFF_SectionFlag_CntInitializedData | (COFF_SectionAlign_8Bytes << COFF_SectionFlag_AlignShift)|(COFF_SectionFlag_MemRead|COFF_SectionFlag_MemWrite);
CV_SymbolList symbol_list = { .signature = CV_Signature_C13 };
String8 comp3_data = lnk_make_linker_compile3(scratch.arena, machine);
cv_symbol_list_push_data(scratch.arena, &symbol_list, CV_SymKind_COMPILE3, comp3_data);
debug_symbols = lnk_make_debug_s(obj_writer->arena, symbol_list);
}
COFF_ObjSection *debugs = coff_obj_writer_push_section(obj_writer, str8_lit(".debug$S"), LNK_DEBUG_SECTION_FLAGS|COFF_SectionFlag_Align1Bytes, debug_symbols);
COFF_ObjSection *idata4 = coff_obj_writer_push_section(obj_writer, str8_lit(".idata$4"), COFF_SectionFlag_CntInitializedData|COFF_SectionFlag_MemRead|COFF_SectionFlag_MemWrite, str8_zero());
COFF_ObjSection *idata5 = coff_obj_writer_push_section(obj_writer, str8_lit(".idata$5"), COFF_SectionFlag_CntInitializedData|COFF_SectionFlag_MemRead|COFF_SectionFlag_MemWrite, str8_zero());
U64 import_size = coff_word_size_from_machine(machine);
U8 *null_thunk = push_array(obj_writer->arena, U8, import_size);
U8 *null_lookup = push_array(obj_writer->arena, U8, import_size);
str8_list_push(obj_writer->arena, &idata5->data, str8_array(null_thunk, import_size));
str8_list_push(obj_writer->arena, &idata4->data, str8_array(null_lookup, import_size));
idata4->flags |= coff_section_flag_from_align_size(import_size);
idata5->flags |= coff_section_flag_from_align_size(import_size);
coff_obj_writer_push_symbol_abs(obj_writer, str8_lit("@comp.id"), 0x1018175, COFF_SymStorageClass_Static);
{
COFF_SectionHeader *sect = &coff_sect_header_array[1];
sect->name[0] = '.';
sect->name[1] = 'i';
sect->name[2] = 'd';
sect->name[3] = 'a';
sect->name[4] = 't';
sect->name[5] = 'a';
sect->name[6] = '$';
sect->name[7] = '4';
sect->fsize = null_thunk_data_size;
sect->foff = null_thunk_data_off;
sect->flags = COFF_SectionFlag_CntInitializedData|(COFF_SectionAlign_8Bytes << COFF_SectionFlag_AlignShift)|COFF_SectionFlag_MemRead|COFF_SectionFlag_MemWrite;
}
{
String8 dll_name_no_ext = str8_substr(dll_name, r1u64(0, dll_name.size - 4));
String8 dll_name_no_ext = str8_chop_last_dot(dll_name);
String8 symbol_name = push_str8f(arena, "\x7f%S_NULL_THUNK_DATA", dll_name_no_ext);
U64 symbol_name_off = list.total_size - string_table_base;
str8_list_push(arena, &list, push_cstr(arena, symbol_name));
COFF_Symbol16 *symbol = &symbol_array[0];
symbol->name.long_name.zeroes = 0;
symbol->name.long_name.string_table_offset = symbol_name_off;
symbol->section_number = 1;
symbol->storage_class = COFF_SymStorageClass_External;
coff_obj_writer_push_symbol_external(obj_writer, symbol_name, 0, idata5);
}
String8 obj = coff_obj_writer_serialize(arena, obj_writer);
// update string table size
*string_table_size_ptr = (list.total_size - string_table_base);
coff_obj_writer_release(&obj_writer);
scratch_end(scratch);
ProfEnd();
return list;
return obj;
}
internal String8
@@ -924,28 +715,28 @@ lnk_build_import_lib(TP_Context *tp, TP_Arena *arena, COFF_MachineType machine,
// These objects appear in first three members of any lib that linker produces with /dll.
// Objects are used by MSVC linker to build import table.
String8List import_obj_array[3];
import_obj_array[0] = lnk_build_import_entry_obj(scratch.arena, dll_name, machine);
import_obj_array[1] = lnk_build_null_import_descriptor_obj(scratch.arena, machine);
import_obj_array[2] = lnk_build_null_thunk_data_obj(scratch.arena, dll_name, machine);
String8 import_obj_array[3];
import_obj_array[0] = lnk_build_import_entry_obj(scratch.arena, dll_name, time_stamp, machine);
import_obj_array[1] = lnk_build_null_import_descriptor_obj(scratch.arena, time_stamp, machine);
import_obj_array[2] = lnk_build_null_thunk_data_obj(scratch.arena, dll_name, time_stamp, machine);
// build input list
LNK_InputObjList input_obj_list = {0};
for (U64 i = 0; i < ArrayCount(import_obj_array); ++i) {
LNK_InputObj *input = lnk_input_obj_list_push(scratch.arena, &input_obj_list);
input->data = str8_list_join(scratch.arena, &import_obj_array[i], 0);
input->data = import_obj_array[i];
input->path = dll_name;
input->lib_path = lib_name;
}
LNK_InputObj **inputs = lnk_array_from_input_obj_list(scratch.arena, input_obj_list);
LNK_SectionTable *sectab = lnk_section_table_alloc(0,0,0);
LNK_SectionTable *sectab = lnk_section_table_alloc(0,0,0);
LNK_ObjList obj_list = {0};
lnk_obj_list_push_parallel(tp, arena, &obj_list, sectab, 0, machine, input_obj_list.count, inputs);
LNK_LibBuild import_lib = lnk_build_lib(scratch.arena, machine, time_stamp, dll_name, obj_list, exptab);
B32 emit_second_member = 0; // MSVC linker refuses to link with lib that has the second member.
String8List coff_archive_data = lnk_coff_archive_from_lib_build(arena->v[0], &import_lib, emit_second_member, time_stamp, /* -rw-r--r-- */ 644);
B32 emit_second_member = 1;
String8List coff_archive_data = lnk_coff_archive_from_lib_build(arena->v[0], &import_lib, emit_second_member, COFF_TimeStamp_Max, 0);
// cleanup memory
lnk_section_table_release(&sectab);
+3 -3
View File
@@ -128,9 +128,9 @@ internal String8List lnk_coff_archive_from_lib_build(Arena *arena, LNK_LibBu
////////////////////////////////
internal LNK_LibBuild lnk_build_lib(Arena *arena, COFF_MachineType machine, COFF_TimeStamp time_stamp, String8 dll_name, LNK_ObjList obj_list, LNK_ExportTable *exptab);
internal String8List lnk_build_import_entry_obj(Arena *arena, String8 dll_name, COFF_MachineType machine);
internal String8List lnk_build_null_import_descriptor_obj(Arena *arena, COFF_MachineType machine);
internal String8List lnk_build_null_thunk_data_obj(Arena *arena, String8 dll_name, COFF_MachineType machine);
internal String8 lnk_build_import_entry_obj(Arena *arena, String8 dll_name, COFF_TimeStamp time_stamp, COFF_MachineType machine);
internal String8 lnk_build_null_import_descriptor_obj(Arena *arena, COFF_TimeStamp time_stamp, COFF_MachineType machine);
internal String8 lnk_build_null_thunk_data_obj(Arena *arena, String8 dll_name, COFF_TimeStamp time_stamp, COFF_MachineType machine);
internal String8 lnk_build_lib_member_header(Arena *arena, String8 name, COFF_TimeStamp time_stamp, U16 user_id, U16 group_id, U16 mode, U32 size);
internal String8List lnk_build_import_lib(TP_Context *tp, TP_Arena *arena, COFF_MachineType machine, COFF_TimeStamp time_stamp, String8 lib_name, String8 dll_name, LNK_ExportTable *exptab);
+131 -121
View File
@@ -751,12 +751,17 @@ lnk_symbol_array_from_coff(Arena *arena,
if (symbol.section_number == 0 || symbol.section_number > sect_count) {
lnk_error_with_loc(LNK_Error_IllData, obj_path, lib_path, "out ouf bounds section index in symbol \"%S (%u)\"", symbol.name, symbol.section_number);
}
if (symbol.value > section_table[symbol.section_number-1].fsize) {
lnk_error_with_loc(LNK_Error_IllData, obj_path, lib_path, "out of bounds section offset in symbol \"%S (%u)\"", symbol.name, symbol.value);
U32 section_offset = 0;
if (symbol.storage_class == COFF_SymStorageClass_External || symbol.storage_class == COFF_SymStorageClass_Static) {
section_offset = symbol.value;
}
if (section_offset > section_table[symbol.section_number-1].fsize) {
lnk_error_with_loc(LNK_Error_IllData, obj_path, lib_path, "out of bounds section offset in symbol \"%S (%u)\"", symbol.name, section_offset);
}
LNK_Chunk *chunk = chunk_table[symbol.section_number-1];
if (symbol.value > 0) {
if (section_offset > 0) {
// convert leaf to list
//
// there is no way to know up front how many splits we have,
@@ -796,7 +801,7 @@ lnk_symbol_array_from_coff(Arena *arena,
LNK_ChunkNode *current = chunk->u.list->last;
for (LNK_ChunkNode *c = chunk->u.list->first; c != 0; c = c->next) {
Assert(c->data->type == LNK_Chunk_Leaf);
if (offset_cursor + c->data->u.leaf.size >= symbol.value) {
if (offset_cursor + c->data->u.leaf.size >= section_offset) {
current = c;
break;
}
@@ -804,9 +809,9 @@ lnk_symbol_array_from_coff(Arena *arena,
}
Assert(current->data->type == LNK_Chunk_Leaf);
if (offset_cursor < symbol.value) {
if (offset_cursor < section_offset) {
// bifurcate chunk at symbol offset
U64 split_pos = symbol.value - offset_cursor;
U64 split_pos = section_offset - offset_cursor;
Rng1U64 left_data_range = rng_1u64(0, split_pos);
Rng1U64 right_data_range = rng_1u64(left_data_range.max, current->data->u.leaf.size);
String8 left_data = str8_substr(current->data->u.leaf, left_data_range);
@@ -865,142 +870,147 @@ lnk_symbol_array_from_coff(Arena *arena,
COFF_SymbolValueInterpType interp = coff_interp_symbol(parsed_symbol.section_number, parsed_symbol.value, parsed_symbol.storage_class);
switch (interp) {
case COFF_SymbolValueInterp_Regular: {
if (parsed_symbol.section_number == 0 || parsed_symbol.section_number > sect_count) {
lnk_error_with_loc(LNK_Error_IllData, obj_path, lib_path, "symbol %S (No. %llx) has out ouf bounds section index %x", parsed_symbol.name, symbol_idx, parsed_symbol.section_number);
}
if (parsed_symbol.value > section_table[parsed_symbol.section_number-1].fsize) {
lnk_error_with_loc(LNK_Error_IllData, obj_path, lib_path, "symbol %S (No. %llx) has out of bounds section offset %x into section %x", parsed_symbol.name, symbol_idx, parsed_symbol.value, parsed_symbol.section_number);
}
case COFF_SymbolValueInterp_Regular: {
if (parsed_symbol.section_number == 0 || parsed_symbol.section_number > sect_count) {
lnk_error_with_loc(LNK_Error_IllData, obj_path, lib_path, "symbol %S (No. %llx) has out ouf bounds section index %x", parsed_symbol.name, symbol_idx, parsed_symbol.section_number);
}
U32 section_offset = 0;
if (parsed_symbol.storage_class == COFF_SymStorageClass_External ||
parsed_symbol.storage_class == COFF_SymStorageClass_Static) {
section_offset = parsed_symbol.value;
}
if (section_offset > section_table[parsed_symbol.section_number-1].fsize) {
lnk_error_with_loc(LNK_Error_IllData, obj_path, lib_path, "symbol %S (No. %llx) has out of bounds section offset %x into section %x", parsed_symbol.name, symbol_idx, section_offset, parsed_symbol.section_number);
}
LNK_DefinedSymbolVisibility visibility = LNK_DefinedSymbolVisibility_Static;
if (parsed_symbol.storage_class == COFF_SymStorageClass_External) {
visibility = LNK_DefinedSymbolVisibility_Extern;
}
LNK_DefinedSymbolFlags flags = 0;
if (COFF_SymbolType_IsFunc(parsed_symbol.type)) {
flags |= LNK_DefinedSymbolFlag_IsFunc;
}
LNK_DefinedSymbolVisibility visibility = LNK_DefinedSymbolVisibility_Static;
if (parsed_symbol.storage_class == COFF_SymStorageClass_External) {
visibility = LNK_DefinedSymbolVisibility_Extern;
}
LNK_DefinedSymbolFlags flags = 0;
if (COFF_SymbolType_IsFunc(parsed_symbol.type)) {
flags |= LNK_DefinedSymbolFlag_IsFunc;
}
LNK_Chunk *chunk = chunk_table[parsed_symbol.section_number-1];
COFF_ComdatSelectType selection = COFF_ComdatSelect_Any;
U64 check_sum = 0;
LNK_Chunk *chunk = chunk_table[parsed_symbol.section_number-1];
U64 offset = parsed_symbol.value;
COFF_ComdatSelectType selection = COFF_ComdatSelect_Any;
U64 check_sum = 0;
B32 is_comdat = (section_table[parsed_symbol.section_number-1].flags & COFF_SectionFlag_LnkCOMDAT) &&
parsed_symbol.value == 0 &&
parsed_symbol.aux_symbol_count > 0 &&
parsed_symbol.type.u.lsb == COFF_SymType_Null &&
parsed_symbol.storage_class == COFF_SymStorageClass_Static;
if (is_comdat) {
COFF_SymbolSecDef *secdef = aux_symbols;
selection = secdef->selection;
check_sum = secdef->check_sum;
B32 is_comdat = (section_table[parsed_symbol.section_number-1].flags & COFF_SectionFlag_LnkCOMDAT) &&
parsed_symbol.value == 0 &&
parsed_symbol.aux_symbol_count > 0 &&
parsed_symbol.type.u.lsb == COFF_SymType_Null &&
parsed_symbol.storage_class == COFF_SymStorageClass_Static;
if (is_comdat) {
COFF_SymbolSecDef *secdef = aux_symbols;
// create association link between chunks
if (secdef->selection == COFF_ComdatSelect_Associative) {
U32 secdef_number = secdef->number_lo;
selection = secdef->selection;
check_sum = secdef->check_sum;
// promote secdef number to 32 bits
if (is_big_obj) {
secdef_number |= (U32)secdef->number_hi << 16;
}
// create association link between chunks
if (secdef->selection == COFF_ComdatSelect_Associative) {
U32 secdef_number = secdef->number_lo;
// promote secdef number to 32 bits
if (is_big_obj) {
secdef_number |= (U32)secdef->number_hi << 16;
}
// associate chunks
if (secdef_number > 0 && secdef_number <= sect_count) {
LNK_Chunk *head_chunk = chunk_table[secdef_number-1];
LNK_Chunk *associate_chunk = chunk_table[parsed_symbol.section_number-1];
lnk_chunk_associate(head_chunk, associate_chunk);
} else {
lnk_error_with_loc(LNK_Error_IllData, obj_path, lib_path, "symbol %S (No. %llx) has out of bounds section definition number %u", parsed_symbol.name, symbol_idx, secdef_number);
}
// associate chunks
if (secdef_number > 0 && secdef_number <= sect_count) {
LNK_Chunk *head_chunk = chunk_table[secdef_number-1];
LNK_Chunk *associate_chunk = chunk_table[parsed_symbol.section_number-1];
lnk_chunk_associate(head_chunk, associate_chunk);
} else {
lnk_error_with_loc(LNK_Error_IllData, obj_path, lib_path, "symbol %S (No. %llx) has out of bounds section definition number %u", parsed_symbol.name, symbol_idx, secdef_number);
}
}
}
if (chunk->type == LNK_Chunk_List) {
LNK_Chunk *closest_chunk = chunk->u.list->last->data;
U64 offset_cursor = 0;
for (LNK_ChunkNode *c = chunk->u.list->first; c != 0; c = c->next) {
if (offset_cursor + c->data->u.leaf.size > offset) {
closest_chunk = c->data;
break;
}
offset_cursor += c->data->u.leaf.size;
if (chunk->type == LNK_Chunk_List) {
LNK_Chunk *closest_chunk = chunk->u.list->last->data;
U64 offset_cursor = 0;
for (LNK_ChunkNode *c = chunk->u.list->first; c != 0; c = c->next) {
if (offset_cursor + c->data->u.leaf.size > section_offset) {
closest_chunk = c->data;
break;
}
Assert(offset >= offset_cursor);
offset -= offset_cursor;
chunk = closest_chunk;
offset_cursor += c->data->u.leaf.size;
}
Assert(chunk->type == LNK_Chunk_Leaf);
Assert(section_offset >= offset_cursor);
section_offset -= offset_cursor;
chunk = closest_chunk;
}
Assert(chunk->type == LNK_Chunk_Leaf);
lnk_init_defined_symbol_chunk(&symbol_array.v[symbol_idx], parsed_symbol.name, visibility, flags, chunk, offset, selection, check_sum);
symbol_array.v[symbol_idx].obj = obj;
} break;
case COFF_SymbolValueInterp_Weak: {
if (parsed_symbol.aux_symbol_count == 0) {
lnk_error_with_loc(LNK_Error_IllData, obj_path, lib_path, "weak symbol \"%S (%u)\" must at least one aux symbol", parsed_symbol.name, symbol_idx);
}
COFF_SymbolWeakExt *weak_ext = aux_symbols;
if (weak_ext->tag_index >= symbol_count) {
lnk_error_with_loc(LNK_Error_IllData, obj_path, lib_path, "weak symbol \"%S (%u)\" points to out of bounds symbol", parsed_symbol.name, symbol_idx);
}
lnk_init_defined_symbol_chunk(&symbol_array.v[symbol_idx], parsed_symbol.name, visibility, flags, chunk, section_offset, selection, check_sum);
symbol_array.v[symbol_idx].obj = obj;
} break;
case COFF_SymbolValueInterp_Weak: {
if (parsed_symbol.aux_symbol_count == 0) {
lnk_error_with_loc(LNK_Error_IllData, obj_path, lib_path, "weak symbol \"%S (%u)\" must at least one aux symbol", parsed_symbol.name, symbol_idx);
}
LNK_Symbol *symbol = &symbol_array.v[symbol_idx];
LNK_Symbol *fallback_symbol = &symbol_array.v[weak_ext->tag_index];
lnk_init_weak_symbol(symbol, parsed_symbol.name, weak_ext->characteristics, fallback_symbol);
COFF_SymbolWeakExt *weak_ext = aux_symbols;
if (weak_ext->tag_index >= symbol_count) {
lnk_error_with_loc(LNK_Error_IllData, obj_path, lib_path, "weak symbol \"%S (%u)\" points to out of bounds symbol", parsed_symbol.name, symbol_idx);
}
symbol->obj = obj;
fallback_symbol->obj = obj;
} break;
case COFF_SymbolValueInterp_Undefined: {
LNK_Symbol *symbol = &symbol_array.v[symbol_idx];
lnk_init_undefined_symbol(symbol, parsed_symbol.name, LNK_SymbolScopeFlag_Main);
symbol->obj = obj;
} break;
case COFF_SymbolValueInterp_Common: {
// :common_block
//
// TODO: sort chunks on size to reduce bss usage
LNK_Chunk *chunk = push_array(arena, LNK_Chunk, 1);
chunk->align = Min(32, u64_up_to_pow2(parsed_symbol.value)); // link.exe caps align at 32 bytes
chunk->type = LNK_Chunk_Leaf;
chunk->flags = master_common_block->flags;
chunk->u.leaf = str8(0, parsed_symbol.value);
chunk->obj = obj;
lnk_chunk_set_debugf(arena, chunk, "common block %S", parsed_symbol.name);
lnk_chunk_list_push(arena, master_common_block->u.list, chunk);
LNK_Symbol *symbol = &symbol_array.v[symbol_idx];
LNK_Symbol *fallback_symbol = &symbol_array.v[weak_ext->tag_index];
lnk_init_weak_symbol(symbol, parsed_symbol.name, weak_ext->characteristics, fallback_symbol);
LNK_DefinedSymbolFlags flags = 0;
if (COFF_SymbolType_IsFunc(parsed_symbol.type)) {
flags |= LNK_DefinedSymbolFlag_IsFunc;
}
symbol->obj = obj;
fallback_symbol->obj = obj;
} break;
case COFF_SymbolValueInterp_Undefined: {
LNK_Symbol *symbol = &symbol_array.v[symbol_idx];
lnk_init_undefined_symbol(symbol, parsed_symbol.name, LNK_SymbolScopeFlag_Main);
symbol->obj = obj;
} break;
case COFF_SymbolValueInterp_Common: {
// :common_block
//
// TODO: sort chunks on size to reduce bss usage
LNK_Chunk *chunk = push_array(arena, LNK_Chunk, 1);
chunk->align = Min(32, u64_up_to_pow2(parsed_symbol.value)); // link.exe caps align at 32 bytes
chunk->type = LNK_Chunk_Leaf;
chunk->flags = master_common_block->flags;
chunk->u.leaf = str8(0, parsed_symbol.value);
chunk->obj = obj;
lnk_chunk_set_debugf(arena, chunk, "common block %S", parsed_symbol.name);
lnk_chunk_list_push(arena, master_common_block->u.list, chunk);
LNK_Symbol *symbol = &symbol_array.v[symbol_idx];
lnk_init_defined_symbol_chunk(symbol, parsed_symbol.name, LNK_DefinedSymbolVisibility_Extern, flags, chunk, 0, COFF_ComdatSelect_Largest, 0);
symbol->obj = obj;
} break;
case COFF_SymbolValueInterp_Abs: {
// Never code or data, synthetic symbol. COFF spec says bits in value are used
// as flags in symbol @feat.00, other symbols like @comp.id and @vol.md are undocumented.
// LLVM uses undocumented mask 0x4800 on @feat.00 to tell if object was compiled with /guard:cf.
LNK_DefinedSymbolFlags flags = 0;
if (COFF_SymbolType_IsFunc(parsed_symbol.type)) {
flags |= LNK_DefinedSymbolFlag_IsFunc;
}
LNK_DefinedSymbolVisibility visibility = LNK_DefinedSymbolVisibility_Static;
if (parsed_symbol.storage_class == COFF_SymStorageClass_External) {
visibility = LNK_DefinedSymbolVisibility_Extern;
}
LNK_Symbol *symbol = &symbol_array.v[symbol_idx];
lnk_init_defined_symbol_chunk(symbol, parsed_symbol.name, LNK_DefinedSymbolVisibility_Extern, flags, chunk, 0, COFF_ComdatSelect_Largest, 0);
symbol->obj = obj;
} break;
case COFF_SymbolValueInterp_Abs: {
// Never code or data, synthetic symbol. COFF spec says bits in value are used
// as flags in symbol @feat.00, other symbols like @comp.id and @vol.md are undocumented.
// LLVM uses undocumented mask 0x4800 on @feat.00 to tell if object was compiled with /guard:cf.
LNK_Symbol *symbol = &symbol_array.v[symbol_idx];
lnk_init_defined_symbol_va(symbol, parsed_symbol.name, visibility, 0, parsed_symbol.value);
symbol->obj = obj;
} break;
case COFF_SymbolValueInterp_Debug: {
} break;
LNK_DefinedSymbolVisibility visibility = LNK_DefinedSymbolVisibility_Static;
if (parsed_symbol.storage_class == COFF_SymStorageClass_External) {
visibility = LNK_DefinedSymbolVisibility_Extern;
}
LNK_Symbol *symbol = &symbol_array.v[symbol_idx];
lnk_init_defined_symbol_va(symbol, parsed_symbol.name, visibility, 0, parsed_symbol.value);
symbol->obj = obj;
} break;
case COFF_SymbolValueInterp_Debug: {
} break;
}
}