diff --git a/src/linker/lnk_symbol_table.c b/src/linker/lnk_symbol_table.c index 81bd8e92..4e7a6a98 100644 --- a/src/linker/lnk_symbol_table.c +++ b/src/linker/lnk_symbol_table.c @@ -150,18 +150,16 @@ lnk_can_replace_symbol(LNK_SymbolScope scope, LNK_Symbol *dst, LNK_Symbol *src) LNK_Symbol *weak, *undef; COFF_ParsedSymbol weak_parsed; if (dst_interp == COFF_SymbolValueInterp_Weak) { - weak = dst; - undef = src; + weak = dst, undef = src; weak_parsed = dst_parsed; } else { - weak = src; - undef = dst; + weak = src, undef = dst; weak_parsed = src_parsed; } COFF_SymbolWeakExt *weak_ext = coff_parse_weak_tag(weak_parsed, weak->u.defined.obj->header.is_big_obj); if (weak_ext->characteristics == COFF_WeakExt_SearchLibrary) { - can_replace = lnk_symbol_defined_is_before(weak, undef); + can_replace = dst_interp == COFF_SymbolValueInterp_Weak; } else if (weak_ext->characteristics == COFF_WeakExt_NoLibrary) { can_replace = dst_interp == COFF_SymbolValueInterp_Weak; } else if (weak_ext->characteristics == COFF_WeakExt_SearchAlias) { @@ -218,22 +216,22 @@ lnk_can_replace_symbol(LNK_SymbolScope scope, LNK_Symbol *dst, LNK_Symbol *src) } // weak vs weak else if (dst_interp == COFF_SymbolValueInterp_Weak && src_interp == COFF_SymbolValueInterp_Weak) { - COFF_ParsedSymbol dst_parsed = lnk_parsed_symbol_from_defined(dst); - COFF_ParsedSymbol src_parsed = lnk_parsed_symbol_from_defined(src); COFF_SymbolWeakExt *dst_ext = coff_parse_weak_tag(dst_parsed, dst->u.defined.obj->header.is_big_obj); COFF_SymbolWeakExt *src_ext = coff_parse_weak_tag(src_parsed, src->u.defined.obj->header.is_big_obj); - if (dst_ext->characteristics == COFF_WeakExt_SearchAlias && src_ext->characteristics == COFF_WeakExt_SearchAlias) { - // TODO: test - lnk_error_multiply_defined_symbol(dst, src); - } else if (dst_ext->characteristics == COFF_WeakExt_SearchAlias && src_ext->characteristics != COFF_WeakExt_SearchAlias) { - // TODO: test - can_replace = 0; + if ((dst_ext->characteristics == COFF_WeakExt_SearchAlias && src_ext->characteristics != COFF_WeakExt_SearchAlias)) { + if (lnk_symbol_defined_is_before(dst, src) || src_ext->characteristics == COFF_WeakExt_AntiDependency) { + can_replace = 0; + } else { + lnk_error_multiply_defined_symbol(dst, src); + } } else if (dst_ext->characteristics != COFF_WeakExt_SearchAlias && src_ext->characteristics == COFF_WeakExt_SearchAlias) { - // TODO: test - can_replace = 1; - } else if (dst_ext->characteristics == COFF_WeakExt_NoLibrary && src_ext->characteristics == COFF_WeakExt_AntiDependency) { - can_replace = 1; - can_replace = lnk_symbol_defined_is_before(src, dst); + if (lnk_symbol_defined_is_before(src, dst) || dst_ext->characteristics == COFF_WeakExt_AntiDependency) { + can_replace = 1; + } else { + lnk_error_multiply_defined_symbol(dst, src); + } + } else if (dst_ext->characteristics == COFF_WeakExt_SearchAlias && src_ext->characteristics == COFF_WeakExt_SearchAlias) { + lnk_error_multiply_defined_symbol(dst, src); } else { can_replace = lnk_symbol_defined_is_before(src, dst); } diff --git a/src/torture/torture.c b/src/torture/torture.c index cd01bbf3..d5cd912f 100644 --- a/src/torture/torture.c +++ b/src/torture/torture.c @@ -823,7 +823,7 @@ t_link_unref_undef(void) } internal T_Result -t_weak_vs_weak(void) +t_weak_lib_vs_weak_lib(void) { Temp scratch = scratch_begin(0,0); T_Result result = T_Result_Fail; @@ -831,23 +831,11 @@ t_weak_vs_weak(void) String8 a_obj; { COFF_ObjWriter *obj_writer = coff_obj_writer_alloc(0, COFF_MachineType_X64); - COFF_ObjSection *sect = coff_obj_writer_push_section(obj_writer, str8_lit(".a"), PE_DATA_SECTION_FLAGS, str8_lit("a")); - COFF_ObjSymbol *sect_symbol = coff_obj_writer_push_symbol_static(obj_writer, str8_lit("_a"), 0, sect); - coff_obj_writer_push_symbol_weak(obj_writer, str8_lit("w"), COFF_WeakExt_SearchLibrary, sect_symbol); + COFF_ObjSymbol *q = coff_obj_writer_push_symbol_abs(obj_writer, str8_lit("q"), 0x111, COFF_SymStorageClass_External); + coff_obj_writer_push_symbol_weak(obj_writer, str8_lit("w"), COFF_WeakExt_SearchLibrary, q); a_obj = coff_obj_writer_serialize(scratch.arena, obj_writer); coff_obj_writer_release(&obj_writer); } - - String8 b_obj; - { - COFF_ObjWriter *obj_writer = coff_obj_writer_alloc(0, COFF_MachineType_X64); - COFF_ObjSection *sect = coff_obj_writer_push_section(obj_writer, str8_lit(".b"), PE_DATA_SECTION_FLAGS, str8_lit("b")); - COFF_ObjSymbol *sect_symbol = coff_obj_writer_push_symbol_static(obj_writer, str8_lit("_b"), 0, sect); - coff_obj_writer_push_symbol_weak(obj_writer, str8_lit("w"), COFF_WeakExt_SearchLibrary, sect_symbol); - b_obj = coff_obj_writer_serialize(scratch.arena, obj_writer); - coff_obj_writer_release(&obj_writer); - } - String8 entry_obj; { @@ -858,19 +846,888 @@ t_weak_vs_weak(void) }; COFF_ObjSection *sect = coff_obj_writer_push_section(obj_writer, str8_lit(".text"), PE_TEXT_SECTION_FLAGS, str8_array_fixed(text)); coff_obj_writer_push_symbol_extern(obj_writer, str8_lit("entry"), 0, sect); - COFF_ObjSymbol *symbol = coff_obj_writer_push_symbol_undef(obj_writer, str8_lit("w")); - coff_obj_writer_section_push_reloc_voff(obj_writer, sect, 0, symbol); + COFF_ObjSymbol *e = coff_obj_writer_push_symbol_abs(obj_writer, str8_lit("e"), 0x222, COFF_SymStorageClass_External); + COFF_ObjSymbol *sym = coff_obj_writer_push_symbol_weak(obj_writer, str8_lit("w"), COFF_WeakExt_SearchLibrary, e); + coff_obj_writer_section_push_reloc_addr32(obj_writer, sect, 3, sym); entry_obj = coff_obj_writer_serialize(scratch.arena, obj_writer); coff_obj_writer_release(&obj_writer); } - if (!t_write_file(str8_lit("a.obj"), a_obj)) { goto exit; } - if (!t_write_file(str8_lit("b.obj"), b_obj)) { goto exit; } + if (!t_write_file(str8_lit("a.obj"), a_obj)) { goto exit; } + if (!t_write_file(str8_lit("entry.obj"), entry_obj)) { goto exit; } + + int linker_exit_code; + + // linker must pick weak symbol from a.obj + linker_exit_code = t_invoke_linkerf("/subsystem:console /entry:entry /out:a.exe a.obj entry.obj"); + if (linker_exit_code != 0) { goto exit; } + + { + String8 exe = t_read_file(scratch.arena, str8_lit("a.exe")); + PE_BinInfo pe = pe_bin_info_from_data(scratch.arena, exe); + COFF_SectionHeader *section_table = (COFF_SectionHeader *)str8_substr(exe, pe.section_table_range).str; + String8 string_table = str8_substr(exe, pe.string_table_range); + COFF_SectionHeader *text_sect = t_coff_section_header_from_name(string_table, section_table, pe.section_count, str8_lit(".text")); + if (text_sect == 0) { goto exit; } + String8 text_data = str8_substr(exe, rng_1u64(text_sect->foff, text_sect->foff + text_sect->vsize)); + String8 imm = str8_substr(text_data, rng_1u64(3, 7)); + U32 expected = 0x111; + if (!str8_match(imm, str8_struct(&expected), 0)) { goto exit; } + } + + // linker must pick weak symbol from entry.obj + linker_exit_code = t_invoke_linkerf("/subsystem:console /entry:entry /out:a.exe entry.obj a.obj"); + if (linker_exit_code != 0) { goto exit; } + + { + String8 exe = t_read_file(scratch.arena, str8_lit("a.exe")); + PE_BinInfo pe = pe_bin_info_from_data(scratch.arena, exe); + COFF_SectionHeader *section_table = (COFF_SectionHeader *)str8_substr(exe, pe.section_table_range).str; + String8 string_table = str8_substr(exe, pe.string_table_range); + COFF_SectionHeader *text_sect = t_coff_section_header_from_name(string_table, section_table, pe.section_count, str8_lit(".text")); + if (text_sect == 0) { goto exit; } + String8 text_data = str8_substr(exe, rng_1u64(text_sect->foff, text_sect->foff + text_sect->vsize)); + String8 imm = str8_substr(text_data, rng_1u64(3, 7)); + U32 expected = 0x222; + if (!str8_match(imm, str8_struct(&expected), 0)) { goto exit; } + } + + result = T_Result_Pass; +exit:; + scratch_end(scratch); + return result; +} + +internal T_Result +t_weak_lib_vs_weak_nolib(void) +{ + Temp scratch = scratch_begin(0,0); + T_Result result = T_Result_Fail; + + String8 a_obj; + { + COFF_ObjWriter *obj_writer = coff_obj_writer_alloc(0, COFF_MachineType_X64); + COFF_ObjSymbol *q = coff_obj_writer_push_symbol_abs(obj_writer, str8_lit("q"), 0x111, COFF_SymStorageClass_External); + coff_obj_writer_push_symbol_weak(obj_writer, str8_lit("w"), COFF_WeakExt_NoLibrary, q); + a_obj = coff_obj_writer_serialize(scratch.arena, obj_writer); + coff_obj_writer_release(&obj_writer); + } + + String8 entry_obj; + { + COFF_ObjWriter *obj_writer = coff_obj_writer_alloc(0, COFF_MachineType_X64); + U8 text[] = { + 0x48, 0xC7, 0xC0, 0x00, 0x00, 0x00, 0x00, // mov rax, $imm + 0xC3 // ret + }; + COFF_ObjSection *sect = coff_obj_writer_push_section(obj_writer, str8_lit(".text"), PE_TEXT_SECTION_FLAGS, str8_array_fixed(text)); + coff_obj_writer_push_symbol_extern(obj_writer, str8_lit("entry"), 0, sect); + COFF_ObjSymbol *e = coff_obj_writer_push_symbol_abs(obj_writer, str8_lit("e"), 0x222, COFF_SymStorageClass_External); + COFF_ObjSymbol *sym = coff_obj_writer_push_symbol_weak(obj_writer, str8_lit("w"), COFF_WeakExt_SearchLibrary, e); + coff_obj_writer_section_push_reloc_addr32(obj_writer, sect, 3, sym); + entry_obj = coff_obj_writer_serialize(scratch.arena, obj_writer); + coff_obj_writer_release(&obj_writer); + } + + if (!t_write_file(str8_lit("a.obj"), a_obj)) { goto exit; } + if (!t_write_file(str8_lit("entry.obj"), entry_obj)) { goto exit; } + + // linker must pick weak symbol from entry.obj + int linker_exit_code = t_invoke_linkerf("/subsystem:console /entry:entry /out:a.exe entry.obj a.obj"); + if (linker_exit_code != 0) { goto exit; } + + { + String8 exe = t_read_file(scratch.arena, str8_lit("a.exe")); + PE_BinInfo pe = pe_bin_info_from_data(scratch.arena, exe); + COFF_SectionHeader *section_table = (COFF_SectionHeader *)str8_substr(exe, pe.section_table_range).str; + String8 string_table = str8_substr(exe, pe.string_table_range); + COFF_SectionHeader *text_sect = t_coff_section_header_from_name(string_table, section_table, pe.section_count, str8_lit(".text")); + if (text_sect == 0) { goto exit; } + String8 text_data = str8_substr(exe, rng_1u64(text_sect->foff, text_sect->foff + text_sect->vsize)); + String8 imm = str8_substr(text_data, rng_1u64(3, 7)); + U32 expected = 0x222; + if (!str8_match(imm, str8_struct(&expected), 0)) { goto exit; } + } + + result = T_Result_Pass; +exit:; + scratch_end(scratch); + return result; +} + +internal T_Result +t_weak_lib_vs_weak_alias(void) +{ + Temp scratch = scratch_begin(0,0); + T_Result result = T_Result_Fail; + + String8 a_obj; + { + COFF_ObjWriter *obj_writer = coff_obj_writer_alloc(0, COFF_MachineType_X64); + COFF_ObjSymbol *q = coff_obj_writer_push_symbol_abs(obj_writer, str8_lit("q"), 0x111, COFF_SymStorageClass_External); + coff_obj_writer_push_symbol_weak(obj_writer, str8_lit("w"), COFF_WeakExt_SearchAlias, q); + a_obj = coff_obj_writer_serialize(scratch.arena, obj_writer); + coff_obj_writer_release(&obj_writer); + } + + String8 entry_obj; + { + COFF_ObjWriter *obj_writer = coff_obj_writer_alloc(0, COFF_MachineType_X64); + U8 text[] = { + 0x48, 0xC7, 0xC0, 0x00, 0x00, 0x00, 0x00, // mov rax, $imm + 0xC3 // ret + }; + COFF_ObjSection *sect = coff_obj_writer_push_section(obj_writer, str8_lit(".text"), PE_TEXT_SECTION_FLAGS, str8_array_fixed(text)); + coff_obj_writer_push_symbol_extern(obj_writer, str8_lit("entry"), 0, sect); + COFF_ObjSymbol *e = coff_obj_writer_push_symbol_abs(obj_writer, str8_lit("e"), 0x222, COFF_SymStorageClass_External); + COFF_ObjSymbol *sym = coff_obj_writer_push_symbol_weak(obj_writer, str8_lit("w"), COFF_WeakExt_SearchLibrary, e); + coff_obj_writer_section_push_reloc_addr32(obj_writer, sect, 3, sym); + entry_obj = coff_obj_writer_serialize(scratch.arena, obj_writer); + coff_obj_writer_release(&obj_writer); + } + + if (!t_write_file(str8_lit("a.obj"), a_obj)) { goto exit; } + if (!t_write_file(str8_lit("entry.obj"), entry_obj)) { goto exit; } + + // linker must pick weak symbol from entry.obj + int linker_exit_code = t_invoke_linkerf("/subsystem:console /entry:entry /out:a.exe entry.obj a.obj"); + if (linker_exit_code != LNK_Error_MultiplyDefinedSymbol) { goto exit; } + + result = T_Result_Pass; +exit:; + scratch_end(scratch); + return result; +} + +internal T_Result +t_weak_lib_vs_weak_antidep(void) +{ + Temp scratch = scratch_begin(0,0); + T_Result result = T_Result_Fail; + + String8 a_obj; + { + COFF_ObjWriter *obj_writer = coff_obj_writer_alloc(0, COFF_MachineType_X64); + COFF_ObjSymbol *q = coff_obj_writer_push_symbol_abs(obj_writer, str8_lit("q"), 0x111, COFF_SymStorageClass_External); + coff_obj_writer_push_symbol_weak(obj_writer, str8_lit("w"), COFF_WeakExt_AntiDependency, q); + a_obj = coff_obj_writer_serialize(scratch.arena, obj_writer); + coff_obj_writer_release(&obj_writer); + } + + String8 entry_obj; + { + COFF_ObjWriter *obj_writer = coff_obj_writer_alloc(0, COFF_MachineType_X64); + U8 text[] = { + 0x48, 0xC7, 0xC0, 0x00, 0x00, 0x00, 0x00, // mov rax, $imm + 0xC3 // ret + }; + COFF_ObjSection *sect = coff_obj_writer_push_section(obj_writer, str8_lit(".text"), PE_TEXT_SECTION_FLAGS, str8_array_fixed(text)); + coff_obj_writer_push_symbol_extern(obj_writer, str8_lit("entry"), 0, sect); + COFF_ObjSymbol *e = coff_obj_writer_push_symbol_abs(obj_writer, str8_lit("e"), 0x222, COFF_SymStorageClass_External); + COFF_ObjSymbol *sym = coff_obj_writer_push_symbol_weak(obj_writer, str8_lit("w"), COFF_WeakExt_SearchLibrary, e); + coff_obj_writer_section_push_reloc_addr32(obj_writer, sect, 3, sym); + entry_obj = coff_obj_writer_serialize(scratch.arena, obj_writer); + coff_obj_writer_release(&obj_writer); + } + + if (!t_write_file(str8_lit("a.obj"), a_obj)) { goto exit; } + if (!t_write_file(str8_lit("entry.obj"), entry_obj)) { goto exit; } + + // linker must pick weak symbol from a.obj + int linker_exit_code = t_invoke_linkerf("/subsystem:console /entry:entry /out:a.exe entry.obj a.obj"); + if (linker_exit_code != 0) { goto exit; } + + { + String8 exe = t_read_file(scratch.arena, str8_lit("a.exe")); + PE_BinInfo pe = pe_bin_info_from_data(scratch.arena, exe); + COFF_SectionHeader *section_table = (COFF_SectionHeader *)str8_substr(exe, pe.section_table_range).str; + String8 string_table = str8_substr(exe, pe.string_table_range); + COFF_SectionHeader *text_sect = t_coff_section_header_from_name(string_table, section_table, pe.section_count, str8_lit(".text")); + if (text_sect == 0) { goto exit; } + String8 text_data = str8_substr(exe, rng_1u64(text_sect->foff, text_sect->foff + text_sect->vsize)); + String8 imm = str8_substr(text_data, rng_1u64(3, 7)); + U32 expected = 0x222; + if (!str8_match(imm, str8_struct(&expected), 0)) { goto exit; } + } + + result = T_Result_Pass; +exit:; + scratch_end(scratch); + return result; +} + +internal T_Result +t_weak_alias_vs_weak_alias(void) +{ + Temp scratch = scratch_begin(0,0); + T_Result result = T_Result_Fail; + + String8 a; + { + COFF_ObjWriter *obj_writer = coff_obj_writer_alloc(0, COFF_MachineType_X64); + COFF_ObjSymbol *qwe = coff_obj_writer_push_symbol_abs(obj_writer, str8_lit("qwe"), 0x111, COFF_SymStorageClass_External); + coff_obj_writer_push_symbol_weak(obj_writer, str8_lit("sym"), COFF_WeakExt_SearchAlias, qwe); + a = coff_obj_writer_serialize(scratch.arena, obj_writer); + coff_obj_writer_release(&obj_writer); + } + + String8 b; + { + COFF_ObjWriter *obj_writer = coff_obj_writer_alloc(0, COFF_MachineType_X64); + COFF_ObjSymbol *ewq = coff_obj_writer_push_symbol_abs(obj_writer, str8_lit("ewq"), 0x222, COFF_SymStorageClass_External); + coff_obj_writer_push_symbol_weak(obj_writer, str8_lit("sym"), COFF_WeakExt_SearchAlias, ewq); + b = coff_obj_writer_serialize(scratch.arena, obj_writer); + coff_obj_writer_release(&obj_writer); + } + + String8 entry_obj; + { + COFF_ObjWriter *obj_writer = coff_obj_writer_alloc(0, COFF_MachineType_X64); + U8 text[] = { + 0x48, 0xC7, 0xC0, 0x00, 0x00, 0x00, 0x00, // mov rax, $imm + 0xC3 // ret + }; + COFF_ObjSection *sect = coff_obj_writer_push_section(obj_writer, str8_lit(".text"), PE_TEXT_SECTION_FLAGS, str8_array_fixed(text)); + coff_obj_writer_push_symbol_extern(obj_writer, str8_lit("entry"), 0, sect); + COFF_ObjSymbol *sym = coff_obj_writer_push_symbol_undef(obj_writer, str8_lit("sym")); + coff_obj_writer_section_push_reloc_addr32(obj_writer, sect, 3, sym); + entry_obj = coff_obj_writer_serialize(scratch.arena, obj_writer); + coff_obj_writer_release(&obj_writer); + } + + if (!t_write_file(str8_lit("a.obj"), a)) { goto exit; } + if (!t_write_file(str8_lit("b.obj"), b)) { goto exit; } if (!t_write_file(str8_lit("entry.obj"), entry_obj)) { goto exit; } int linker_exit_code = t_invoke_linkerf("/subsystem:console /entry:entry /out:a.exe a.obj b.obj entry.obj"); + if (linker_exit_code != LNK_Error_MultiplyDefinedSymbol) { goto exit; } + + result = T_Result_Pass; +exit:; + scratch_end(scratch); + return result; +} + +internal T_Result +t_weak_alias_vs_weak_lib(void) +{ + Temp scratch = scratch_begin(0,0); + T_Result result = T_Result_Fail; + + String8 a_obj; + { + COFF_ObjWriter *obj_writer = coff_obj_writer_alloc(0, COFF_MachineType_X64); + COFF_ObjSymbol *q = coff_obj_writer_push_symbol_abs(obj_writer, str8_lit("q"), 0x111, COFF_SymStorageClass_External); + coff_obj_writer_push_symbol_weak(obj_writer, str8_lit("w"), COFF_WeakExt_AntiDependency, q); + a_obj = coff_obj_writer_serialize(scratch.arena, obj_writer); + coff_obj_writer_release(&obj_writer); + } + + String8 entry_obj; + { + COFF_ObjWriter *obj_writer = coff_obj_writer_alloc(0, COFF_MachineType_X64); + U8 text[] = { + 0x48, 0xC7, 0xC0, 0x00, 0x00, 0x00, 0x00, // mov rax, $imm + 0xC3 // ret + }; + COFF_ObjSection *sect = coff_obj_writer_push_section(obj_writer, str8_lit(".text"), PE_TEXT_SECTION_FLAGS, str8_array_fixed(text)); + coff_obj_writer_push_symbol_extern(obj_writer, str8_lit("entry"), 0, sect); + COFF_ObjSymbol *e = coff_obj_writer_push_symbol_abs(obj_writer, str8_lit("e"), 0x222, COFF_SymStorageClass_External); + COFF_ObjSymbol *sym = coff_obj_writer_push_symbol_weak(obj_writer, str8_lit("w"), COFF_WeakExt_SearchAlias, e); + coff_obj_writer_section_push_reloc_addr32(obj_writer, sect, 3, sym); + entry_obj = coff_obj_writer_serialize(scratch.arena, obj_writer); + coff_obj_writer_release(&obj_writer); + } + + if (!t_write_file(str8_lit("a.obj"), a_obj)) { goto exit; } + if (!t_write_file(str8_lit("entry.obj"), entry_obj)) { goto exit; } + + // linker must pick weak symbol from entry.obj + int linker_exit_code = t_invoke_linkerf("/subsystem:console /entry:entry /out:a.exe entry.obj a.obj"); if (linker_exit_code != 0) { goto exit; } + { + String8 exe = t_read_file(scratch.arena, str8_lit("a.exe")); + PE_BinInfo pe = pe_bin_info_from_data(scratch.arena, exe); + COFF_SectionHeader *section_table = (COFF_SectionHeader *)str8_substr(exe, pe.section_table_range).str; + String8 string_table = str8_substr(exe, pe.string_table_range); + COFF_SectionHeader *text_sect = t_coff_section_header_from_name(string_table, section_table, pe.section_count, str8_lit(".text")); + if (text_sect == 0) { goto exit; } + String8 text_data = str8_substr(exe, rng_1u64(text_sect->foff, text_sect->foff + text_sect->vsize)); + String8 imm = str8_substr(text_data, rng_1u64(3, 7)); + U32 expected = 0x222; + if (!str8_match(imm, str8_struct(&expected), 0)) { goto exit; } + } + + result = T_Result_Pass; +exit:; + scratch_end(scratch); + return result; +} + +internal T_Result +t_weak_alias_vs_weak_nolib(void) +{ + Temp scratch = scratch_begin(0,0); + T_Result result = T_Result_Fail; + + String8 a_obj; + { + COFF_ObjWriter *obj_writer = coff_obj_writer_alloc(0, COFF_MachineType_X64); + COFF_ObjSymbol *q = coff_obj_writer_push_symbol_abs(obj_writer, str8_lit("q"), 0x111, COFF_SymStorageClass_External); + coff_obj_writer_push_symbol_weak(obj_writer, str8_lit("w"), COFF_WeakExt_NoLibrary, q); + a_obj = coff_obj_writer_serialize(scratch.arena, obj_writer); + coff_obj_writer_release(&obj_writer); + } + + String8 entry_obj; + { + COFF_ObjWriter *obj_writer = coff_obj_writer_alloc(0, COFF_MachineType_X64); + U8 text[] = { + 0x48, 0xC7, 0xC0, 0x00, 0x00, 0x00, 0x00, // mov rax, $imm + 0xC3 // ret + }; + COFF_ObjSection *sect = coff_obj_writer_push_section(obj_writer, str8_lit(".text"), PE_TEXT_SECTION_FLAGS, str8_array_fixed(text)); + coff_obj_writer_push_symbol_extern(obj_writer, str8_lit("entry"), 0, sect); + COFF_ObjSymbol *e = coff_obj_writer_push_symbol_abs(obj_writer, str8_lit("e"), 0x222, COFF_SymStorageClass_External); + COFF_ObjSymbol *sym = coff_obj_writer_push_symbol_weak(obj_writer, str8_lit("w"), COFF_WeakExt_SearchAlias, e); + coff_obj_writer_section_push_reloc_addr32(obj_writer, sect, 3, sym); + entry_obj = coff_obj_writer_serialize(scratch.arena, obj_writer); + coff_obj_writer_release(&obj_writer); + } + + if (!t_write_file(str8_lit("a.obj"), a_obj)) { goto exit; } + if (!t_write_file(str8_lit("entry.obj"), entry_obj)) { goto exit; } + + // linker must pick weak symbol from entry.obj + int linker_exit_code = t_invoke_linkerf("/subsystem:console /entry:entry /out:a.exe entry.obj a.obj"); + if (linker_exit_code != 0) { goto exit; } + + { + String8 exe = t_read_file(scratch.arena, str8_lit("a.exe")); + PE_BinInfo pe = pe_bin_info_from_data(scratch.arena, exe); + COFF_SectionHeader *section_table = (COFF_SectionHeader *)str8_substr(exe, pe.section_table_range).str; + String8 string_table = str8_substr(exe, pe.string_table_range); + COFF_SectionHeader *text_sect = t_coff_section_header_from_name(string_table, section_table, pe.section_count, str8_lit(".text")); + if (text_sect == 0) { goto exit; } + String8 text_data = str8_substr(exe, rng_1u64(text_sect->foff, text_sect->foff + text_sect->vsize)); + String8 imm = str8_substr(text_data, rng_1u64(3, 7)); + U32 expected = 0x222; + if (!str8_match(imm, str8_struct(&expected), 0)) { goto exit; } + } + + result = T_Result_Pass; +exit:; + scratch_end(scratch); + return result; +} + +internal T_Result +t_weak_alias_vs_weak_antidep(void) +{ + Temp scratch = scratch_begin(0,0); + T_Result result = T_Result_Fail; + + String8 a_obj; + { + COFF_ObjWriter *obj_writer = coff_obj_writer_alloc(0, COFF_MachineType_X64); + COFF_ObjSymbol *q = coff_obj_writer_push_symbol_abs(obj_writer, str8_lit("q"), 0x111, COFF_SymStorageClass_External); + coff_obj_writer_push_symbol_weak(obj_writer, str8_lit("w"), COFF_WeakExt_AntiDependency, q); + a_obj = coff_obj_writer_serialize(scratch.arena, obj_writer); + coff_obj_writer_release(&obj_writer); + } + + String8 entry_obj; + { + COFF_ObjWriter *obj_writer = coff_obj_writer_alloc(0, COFF_MachineType_X64); + U8 text[] = { + 0x48, 0xC7, 0xC0, 0x00, 0x00, 0x00, 0x00, // mov rax, $imm + 0xC3 // ret + }; + COFF_ObjSection *sect = coff_obj_writer_push_section(obj_writer, str8_lit(".text"), PE_TEXT_SECTION_FLAGS, str8_array_fixed(text)); + coff_obj_writer_push_symbol_extern(obj_writer, str8_lit("entry"), 0, sect); + COFF_ObjSymbol *e = coff_obj_writer_push_symbol_abs(obj_writer, str8_lit("e"), 0x222, COFF_SymStorageClass_External); + COFF_ObjSymbol *sym = coff_obj_writer_push_symbol_weak(obj_writer, str8_lit("w"), COFF_WeakExt_SearchAlias, e); + coff_obj_writer_section_push_reloc_addr32(obj_writer, sect, 3, sym); + entry_obj = coff_obj_writer_serialize(scratch.arena, obj_writer); + coff_obj_writer_release(&obj_writer); + } + + if (!t_write_file(str8_lit("a.obj"), a_obj)) { goto exit; } + if (!t_write_file(str8_lit("entry.obj"), entry_obj)) { goto exit; } + + // linker must pick weak symbol from entry.obj + int linker_exit_code = t_invoke_linkerf("/subsystem:console /entry:entry /out:a.exe entry.obj a.obj"); + if (linker_exit_code != 0) { goto exit; } + + { + String8 exe = t_read_file(scratch.arena, str8_lit("a.exe")); + PE_BinInfo pe = pe_bin_info_from_data(scratch.arena, exe); + COFF_SectionHeader *section_table = (COFF_SectionHeader *)str8_substr(exe, pe.section_table_range).str; + String8 string_table = str8_substr(exe, pe.string_table_range); + COFF_SectionHeader *text_sect = t_coff_section_header_from_name(string_table, section_table, pe.section_count, str8_lit(".text")); + if (text_sect == 0) { goto exit; } + String8 text_data = str8_substr(exe, rng_1u64(text_sect->foff, text_sect->foff + text_sect->vsize)); + String8 imm = str8_substr(text_data, rng_1u64(3, 7)); + U32 expected = 0x222; + if (!str8_match(imm, str8_struct(&expected), 0)) { goto exit; } + } + + result = T_Result_Pass; +exit:; + scratch_end(scratch); + return result; +} + +internal T_Result +t_weak_nolib_vs_weak_nolib(void) +{ + Temp scratch = scratch_begin(0,0); + T_Result result = T_Result_Fail; + + String8 a_obj; + { + COFF_ObjWriter *obj_writer = coff_obj_writer_alloc(0, COFF_MachineType_X64); + COFF_ObjSymbol *q = coff_obj_writer_push_symbol_abs(obj_writer, str8_lit("q"), 0x111, COFF_SymStorageClass_External); + coff_obj_writer_push_symbol_weak(obj_writer, str8_lit("w"), COFF_WeakExt_NoLibrary, q); + a_obj = coff_obj_writer_serialize(scratch.arena, obj_writer); + coff_obj_writer_release(&obj_writer); + } + + String8 entry_obj; + { + COFF_ObjWriter *obj_writer = coff_obj_writer_alloc(0, COFF_MachineType_X64); + U8 text[] = { + 0x48, 0xC7, 0xC0, 0x00, 0x00, 0x00, 0x00, // mov rax, $imm + 0xC3 // ret + }; + COFF_ObjSection *sect = coff_obj_writer_push_section(obj_writer, str8_lit(".text"), PE_TEXT_SECTION_FLAGS, str8_array_fixed(text)); + coff_obj_writer_push_symbol_extern(obj_writer, str8_lit("entry"), 0, sect); + COFF_ObjSymbol *e = coff_obj_writer_push_symbol_abs(obj_writer, str8_lit("e"), 0x222, COFF_SymStorageClass_External); + COFF_ObjSymbol *sym = coff_obj_writer_push_symbol_weak(obj_writer, str8_lit("w"), COFF_WeakExt_NoLibrary, e); + coff_obj_writer_section_push_reloc_addr32(obj_writer, sect, 3, sym); + entry_obj = coff_obj_writer_serialize(scratch.arena, obj_writer); + coff_obj_writer_release(&obj_writer); + } + + if (!t_write_file(str8_lit("a.obj"), a_obj)) { goto exit; } + if (!t_write_file(str8_lit("entry.obj"), entry_obj)) { goto exit; } + + int linker_exit_code = t_invoke_linkerf("/subsystem:console /entry:entry /out:a.exe entry.obj a.obj"); + if (linker_exit_code != 0) { goto exit; } + + { + String8 exe = t_read_file(scratch.arena, str8_lit("a.exe")); + PE_BinInfo pe = pe_bin_info_from_data(scratch.arena, exe); + COFF_SectionHeader *section_table = (COFF_SectionHeader *)str8_substr(exe, pe.section_table_range).str; + String8 string_table = str8_substr(exe, pe.string_table_range); + COFF_SectionHeader *text_sect = t_coff_section_header_from_name(string_table, section_table, pe.section_count, str8_lit(".text")); + if (text_sect == 0) { goto exit; } + String8 text_data = str8_substr(exe, rng_1u64(text_sect->foff, text_sect->foff + text_sect->vsize)); + String8 imm = str8_substr(text_data, rng_1u64(3, 7)); + U32 expected = 0x222; + if (!str8_match(imm, str8_struct(&expected), 0)) { goto exit; } + } + + result = T_Result_Pass; +exit:; + scratch_end(scratch); + return result; +} + +internal T_Result +t_weak_nolib_vs_weak_lib(void) +{ + Temp scratch = scratch_begin(0,0); + T_Result result = T_Result_Fail; + + String8 a_obj; + { + COFF_ObjWriter *obj_writer = coff_obj_writer_alloc(0, COFF_MachineType_X64); + COFF_ObjSymbol *q = coff_obj_writer_push_symbol_abs(obj_writer, str8_lit("q"), 0x111, COFF_SymStorageClass_External); + coff_obj_writer_push_symbol_weak(obj_writer, str8_lit("w"), COFF_WeakExt_SearchLibrary, q); + a_obj = coff_obj_writer_serialize(scratch.arena, obj_writer); + coff_obj_writer_release(&obj_writer); + } + + String8 entry_obj; + { + COFF_ObjWriter *obj_writer = coff_obj_writer_alloc(0, COFF_MachineType_X64); + U8 text[] = { + 0x48, 0xC7, 0xC0, 0x00, 0x00, 0x00, 0x00, // mov rax, $imm + 0xC3 // ret + }; + COFF_ObjSection *sect = coff_obj_writer_push_section(obj_writer, str8_lit(".text"), PE_TEXT_SECTION_FLAGS, str8_array_fixed(text)); + coff_obj_writer_push_symbol_extern(obj_writer, str8_lit("entry"), 0, sect); + COFF_ObjSymbol *e = coff_obj_writer_push_symbol_abs(obj_writer, str8_lit("e"), 0x222, COFF_SymStorageClass_External); + COFF_ObjSymbol *sym = coff_obj_writer_push_symbol_weak(obj_writer, str8_lit("w"), COFF_WeakExt_NoLibrary, e); + coff_obj_writer_section_push_reloc_addr32(obj_writer, sect, 3, sym); + entry_obj = coff_obj_writer_serialize(scratch.arena, obj_writer); + coff_obj_writer_release(&obj_writer); + } + + if (!t_write_file(str8_lit("a.obj"), a_obj)) { goto exit; } + if (!t_write_file(str8_lit("entry.obj"), entry_obj)) { goto exit; } + + int linker_exit_code = t_invoke_linkerf("/subsystem:console /entry:entry /out:a.exe entry.obj a.obj"); + if (linker_exit_code != 0) { goto exit; } + + { + String8 exe = t_read_file(scratch.arena, str8_lit("a.exe")); + PE_BinInfo pe = pe_bin_info_from_data(scratch.arena, exe); + COFF_SectionHeader *section_table = (COFF_SectionHeader *)str8_substr(exe, pe.section_table_range).str; + String8 string_table = str8_substr(exe, pe.string_table_range); + COFF_SectionHeader *text_sect = t_coff_section_header_from_name(string_table, section_table, pe.section_count, str8_lit(".text")); + if (text_sect == 0) { goto exit; } + String8 text_data = str8_substr(exe, rng_1u64(text_sect->foff, text_sect->foff + text_sect->vsize)); + String8 imm = str8_substr(text_data, rng_1u64(3, 7)); + U32 expected = 0x222; + if (!str8_match(imm, str8_struct(&expected), 0)) { goto exit; } + } + + result = T_Result_Pass; +exit:; + scratch_end(scratch); + return result; +} + +internal T_Result +t_weak_nolib_vs_weak_alias(void) +{ + Temp scratch = scratch_begin(0,0); + T_Result result = T_Result_Fail; + + String8 a_obj; + { + COFF_ObjWriter *obj_writer = coff_obj_writer_alloc(0, COFF_MachineType_X64); + COFF_ObjSymbol *q = coff_obj_writer_push_symbol_abs(obj_writer, str8_lit("q"), 0x111, COFF_SymStorageClass_External); + coff_obj_writer_push_symbol_weak(obj_writer, str8_lit("w"), COFF_WeakExt_SearchAlias, q); + a_obj = coff_obj_writer_serialize(scratch.arena, obj_writer); + coff_obj_writer_release(&obj_writer); + } + + String8 entry_obj; + { + COFF_ObjWriter *obj_writer = coff_obj_writer_alloc(0, COFF_MachineType_X64); + U8 text[] = { + 0x48, 0xC7, 0xC0, 0x00, 0x00, 0x00, 0x00, // mov rax, $imm + 0xC3 // ret + }; + COFF_ObjSection *sect = coff_obj_writer_push_section(obj_writer, str8_lit(".text"), PE_TEXT_SECTION_FLAGS, str8_array_fixed(text)); + coff_obj_writer_push_symbol_extern(obj_writer, str8_lit("entry"), 0, sect); + COFF_ObjSymbol *e = coff_obj_writer_push_symbol_abs(obj_writer, str8_lit("e"), 0x222, COFF_SymStorageClass_External); + COFF_ObjSymbol *sym = coff_obj_writer_push_symbol_weak(obj_writer, str8_lit("w"), COFF_WeakExt_NoLibrary, e); + coff_obj_writer_section_push_reloc_addr32(obj_writer, sect, 3, sym); + entry_obj = coff_obj_writer_serialize(scratch.arena, obj_writer); + coff_obj_writer_release(&obj_writer); + } + + if (!t_write_file(str8_lit("a.obj"), a_obj)) { goto exit; } + if (!t_write_file(str8_lit("entry.obj"), entry_obj)) { goto exit; } + + int linker_exit_code = t_invoke_linkerf("/subsystem:console /entry:entry /out:a.exe entry.obj a.obj"); + if (linker_exit_code != LNK_Error_MultiplyDefinedSymbol) { goto exit; } + + result = T_Result_Pass; +exit:; + scratch_end(scratch); + return result; +} + +internal T_Result +t_weak_nolib_vs_weak_antidep(void) +{ + Temp scratch = scratch_begin(0,0); + T_Result result = T_Result_Fail; + + String8 a_obj; + { + COFF_ObjWriter *obj_writer = coff_obj_writer_alloc(0, COFF_MachineType_X64); + COFF_ObjSymbol *q = coff_obj_writer_push_symbol_abs(obj_writer, str8_lit("q"), 0x111, COFF_SymStorageClass_External); + coff_obj_writer_push_symbol_weak(obj_writer, str8_lit("w"), COFF_WeakExt_AntiDependency, q); + a_obj = coff_obj_writer_serialize(scratch.arena, obj_writer); + coff_obj_writer_release(&obj_writer); + } + + String8 entry_obj; + { + COFF_ObjWriter *obj_writer = coff_obj_writer_alloc(0, COFF_MachineType_X64); + U8 text[] = { + 0x48, 0xC7, 0xC0, 0x00, 0x00, 0x00, 0x00, // mov rax, $imm + 0xC3 // ret + }; + COFF_ObjSection *sect = coff_obj_writer_push_section(obj_writer, str8_lit(".text"), PE_TEXT_SECTION_FLAGS, str8_array_fixed(text)); + coff_obj_writer_push_symbol_extern(obj_writer, str8_lit("entry"), 0, sect); + COFF_ObjSymbol *e = coff_obj_writer_push_symbol_abs(obj_writer, str8_lit("e"), 0x222, COFF_SymStorageClass_External); + COFF_ObjSymbol *sym = coff_obj_writer_push_symbol_weak(obj_writer, str8_lit("w"), COFF_WeakExt_NoLibrary, e); + coff_obj_writer_section_push_reloc_addr32(obj_writer, sect, 3, sym); + entry_obj = coff_obj_writer_serialize(scratch.arena, obj_writer); + coff_obj_writer_release(&obj_writer); + } + + if (!t_write_file(str8_lit("a.obj"), a_obj)) { goto exit; } + if (!t_write_file(str8_lit("entry.obj"), entry_obj)) { goto exit; } + + int linker_exit_code = t_invoke_linkerf("/subsystem:console /entry:entry /out:a.exe entry.obj a.obj"); + if (linker_exit_code != 0) { goto exit; } + + { + String8 exe = t_read_file(scratch.arena, str8_lit("a.exe")); + PE_BinInfo pe = pe_bin_info_from_data(scratch.arena, exe); + COFF_SectionHeader *section_table = (COFF_SectionHeader *)str8_substr(exe, pe.section_table_range).str; + String8 string_table = str8_substr(exe, pe.string_table_range); + COFF_SectionHeader *text_sect = t_coff_section_header_from_name(string_table, section_table, pe.section_count, str8_lit(".text")); + if (text_sect == 0) { goto exit; } + String8 text_data = str8_substr(exe, rng_1u64(text_sect->foff, text_sect->foff + text_sect->vsize)); + String8 imm = str8_substr(text_data, rng_1u64(3, 7)); + U32 expected = 0x222; + if (!str8_match(imm, str8_struct(&expected), 0)) { goto exit; } + } + + result = T_Result_Pass; +exit:; + scratch_end(scratch); + return result; +} + +internal T_Result +t_weak_antidep_vs_weak_antidep(void) +{ + Temp scratch = scratch_begin(0,0); + T_Result result = T_Result_Fail; + + String8 a_obj; + { + COFF_ObjWriter *obj_writer = coff_obj_writer_alloc(0, COFF_MachineType_X64); + COFF_ObjSymbol *q = coff_obj_writer_push_symbol_abs(obj_writer, str8_lit("q"), 0x111, COFF_SymStorageClass_External); + coff_obj_writer_push_symbol_weak(obj_writer, str8_lit("w"), COFF_WeakExt_AntiDependency, q); + a_obj = coff_obj_writer_serialize(scratch.arena, obj_writer); + coff_obj_writer_release(&obj_writer); + } + + String8 entry_obj; + { + COFF_ObjWriter *obj_writer = coff_obj_writer_alloc(0, COFF_MachineType_X64); + U8 text[] = { + 0x48, 0xC7, 0xC0, 0x00, 0x00, 0x00, 0x00, // mov rax, $imm + 0xC3 // ret + }; + COFF_ObjSection *sect = coff_obj_writer_push_section(obj_writer, str8_lit(".text"), PE_TEXT_SECTION_FLAGS, str8_array_fixed(text)); + coff_obj_writer_push_symbol_extern(obj_writer, str8_lit("entry"), 0, sect); + COFF_ObjSymbol *e = coff_obj_writer_push_symbol_abs(obj_writer, str8_lit("e"), 0x222, COFF_SymStorageClass_External); + COFF_ObjSymbol *sym = coff_obj_writer_push_symbol_weak(obj_writer, str8_lit("w"), COFF_WeakExt_AntiDependency, e); + coff_obj_writer_section_push_reloc_addr32(obj_writer, sect, 3, sym); + entry_obj = coff_obj_writer_serialize(scratch.arena, obj_writer); + coff_obj_writer_release(&obj_writer); + } + + if (!t_write_file(str8_lit("a.obj"), a_obj)) { goto exit; } + if (!t_write_file(str8_lit("entry.obj"), entry_obj)) { goto exit; } + + int linker_exit_code; + + // linker must pick weak symbol from a.obj + linker_exit_code = t_invoke_linkerf("/subsystem:console /entry:entry /out:a.exe a.obj entry.obj"); + if (linker_exit_code != 0) { goto exit; } + + { + String8 exe = t_read_file(scratch.arena, str8_lit("a.exe")); + PE_BinInfo pe = pe_bin_info_from_data(scratch.arena, exe); + COFF_SectionHeader *section_table = (COFF_SectionHeader *)str8_substr(exe, pe.section_table_range).str; + String8 string_table = str8_substr(exe, pe.string_table_range); + COFF_SectionHeader *text_sect = t_coff_section_header_from_name(string_table, section_table, pe.section_count, str8_lit(".text")); + if (text_sect == 0) { goto exit; } + String8 text_data = str8_substr(exe, rng_1u64(text_sect->foff, text_sect->foff + text_sect->vsize)); + String8 imm = str8_substr(text_data, rng_1u64(3, 7)); + U32 expected = 0x111; + if (!str8_match(imm, str8_struct(&expected), 0)) { goto exit; } + } + + // linker must pick weak symbol from entry.obj + linker_exit_code = t_invoke_linkerf("/subsystem:console /entry:entry /out:a.exe entry.obj a.obj"); + if (linker_exit_code != 0) { goto exit; } + + { + String8 exe = t_read_file(scratch.arena, str8_lit("a.exe")); + PE_BinInfo pe = pe_bin_info_from_data(scratch.arena, exe); + COFF_SectionHeader *section_table = (COFF_SectionHeader *)str8_substr(exe, pe.section_table_range).str; + String8 string_table = str8_substr(exe, pe.string_table_range); + COFF_SectionHeader *text_sect = t_coff_section_header_from_name(string_table, section_table, pe.section_count, str8_lit(".text")); + if (text_sect == 0) { goto exit; } + String8 text_data = str8_substr(exe, rng_1u64(text_sect->foff, text_sect->foff + text_sect->vsize)); + String8 imm = str8_substr(text_data, rng_1u64(3, 7)); + U32 expected = 0x222; + if (!str8_match(imm, str8_struct(&expected), 0)) { goto exit; } + } + + result = T_Result_Pass; +exit:; + scratch_end(scratch); + return result; +} + +internal T_Result +t_weak_antidep_vs_weak_nolib(void) +{ + Temp scratch = scratch_begin(0,0); + T_Result result = T_Result_Fail; + + String8 a_obj; + { + COFF_ObjWriter *obj_writer = coff_obj_writer_alloc(0, COFF_MachineType_X64); + COFF_ObjSymbol *q = coff_obj_writer_push_symbol_abs(obj_writer, str8_lit("q"), 0x111, COFF_SymStorageClass_External); + coff_obj_writer_push_symbol_weak(obj_writer, str8_lit("w"), COFF_WeakExt_NoLibrary, q); + a_obj = coff_obj_writer_serialize(scratch.arena, obj_writer); + coff_obj_writer_release(&obj_writer); + } + + String8 entry_obj; + { + COFF_ObjWriter *obj_writer = coff_obj_writer_alloc(0, COFF_MachineType_X64); + U8 text[] = { + 0x48, 0xC7, 0xC0, 0x00, 0x00, 0x00, 0x00, // mov rax, $imm + 0xC3 // ret + }; + COFF_ObjSection *sect = coff_obj_writer_push_section(obj_writer, str8_lit(".text"), PE_TEXT_SECTION_FLAGS, str8_array_fixed(text)); + coff_obj_writer_push_symbol_extern(obj_writer, str8_lit("entry"), 0, sect); + COFF_ObjSymbol *e = coff_obj_writer_push_symbol_abs(obj_writer, str8_lit("e"), 0x222, COFF_SymStorageClass_External); + COFF_ObjSymbol *sym = coff_obj_writer_push_symbol_weak(obj_writer, str8_lit("w"), COFF_WeakExt_AntiDependency, e); + coff_obj_writer_section_push_reloc_addr32(obj_writer, sect, 3, sym); + entry_obj = coff_obj_writer_serialize(scratch.arena, obj_writer); + coff_obj_writer_release(&obj_writer); + } + + if (!t_write_file(str8_lit("a.obj"), a_obj)) { goto exit; } + if (!t_write_file(str8_lit("entry.obj"), entry_obj)) { goto exit; } + + int linker_exit_code = t_invoke_linkerf("/subsystem:console /entry:entry /out:a.exe entry.obj a.obj"); + if (linker_exit_code != 0) { goto exit; } + + { + String8 exe = t_read_file(scratch.arena, str8_lit("a.exe")); + PE_BinInfo pe = pe_bin_info_from_data(scratch.arena, exe); + COFF_SectionHeader *section_table = (COFF_SectionHeader *)str8_substr(exe, pe.section_table_range).str; + String8 string_table = str8_substr(exe, pe.string_table_range); + COFF_SectionHeader *text_sect = t_coff_section_header_from_name(string_table, section_table, pe.section_count, str8_lit(".text")); + if (text_sect == 0) { goto exit; } + String8 text_data = str8_substr(exe, rng_1u64(text_sect->foff, text_sect->foff + text_sect->vsize)); + String8 imm = str8_substr(text_data, rng_1u64(3, 7)); + U32 expected = 0x222; + if (!str8_match(imm, str8_struct(&expected), 0)) { goto exit; } + } + + result = T_Result_Pass; +exit:; + scratch_end(scratch); + return result; +} + +internal T_Result +t_weak_antidep_vs_weak_lib(void) +{ + Temp scratch = scratch_begin(0,0); + T_Result result = T_Result_Fail; + + String8 a_obj; + { + COFF_ObjWriter *obj_writer = coff_obj_writer_alloc(0, COFF_MachineType_X64); + COFF_ObjSymbol *q = coff_obj_writer_push_symbol_abs(obj_writer, str8_lit("q"), 0x111, COFF_SymStorageClass_External); + coff_obj_writer_push_symbol_weak(obj_writer, str8_lit("w"), COFF_WeakExt_SearchLibrary, q); + a_obj = coff_obj_writer_serialize(scratch.arena, obj_writer); + coff_obj_writer_release(&obj_writer); + } + + String8 entry_obj; + { + COFF_ObjWriter *obj_writer = coff_obj_writer_alloc(0, COFF_MachineType_X64); + U8 text[] = { + 0x48, 0xC7, 0xC0, 0x00, 0x00, 0x00, 0x00, // mov rax, $imm + 0xC3 // ret + }; + COFF_ObjSection *sect = coff_obj_writer_push_section(obj_writer, str8_lit(".text"), PE_TEXT_SECTION_FLAGS, str8_array_fixed(text)); + coff_obj_writer_push_symbol_extern(obj_writer, str8_lit("entry"), 0, sect); + COFF_ObjSymbol *e = coff_obj_writer_push_symbol_abs(obj_writer, str8_lit("e"), 0x222, COFF_SymStorageClass_External); + COFF_ObjSymbol *sym = coff_obj_writer_push_symbol_weak(obj_writer, str8_lit("w"), COFF_WeakExt_AntiDependency, e); + coff_obj_writer_section_push_reloc_addr32(obj_writer, sect, 3, sym); + entry_obj = coff_obj_writer_serialize(scratch.arena, obj_writer); + coff_obj_writer_release(&obj_writer); + } + + if (!t_write_file(str8_lit("a.obj"), a_obj)) { goto exit; } + if (!t_write_file(str8_lit("entry.obj"), entry_obj)) { goto exit; } + + int linker_exit_code = t_invoke_linkerf("/subsystem:console /entry:entry /out:a.exe entry.obj a.obj"); + if (linker_exit_code != 0) { goto exit; } + + { + String8 exe = t_read_file(scratch.arena, str8_lit("a.exe")); + PE_BinInfo pe = pe_bin_info_from_data(scratch.arena, exe); + COFF_SectionHeader *section_table = (COFF_SectionHeader *)str8_substr(exe, pe.section_table_range).str; + String8 string_table = str8_substr(exe, pe.string_table_range); + COFF_SectionHeader *text_sect = t_coff_section_header_from_name(string_table, section_table, pe.section_count, str8_lit(".text")); + if (text_sect == 0) { goto exit; } + String8 text_data = str8_substr(exe, rng_1u64(text_sect->foff, text_sect->foff + text_sect->vsize)); + String8 imm = str8_substr(text_data, rng_1u64(3, 7)); + U32 expected = 0x222; + if (!str8_match(imm, str8_struct(&expected), 0)) { goto exit; } + } + + result = T_Result_Pass; +exit:; + scratch_end(scratch); + return result; +} + +internal T_Result +t_weak_antidep_vs_weak_alias(void) +{ + Temp scratch = scratch_begin(0,0); + T_Result result = T_Result_Fail; + + String8 a_obj; + { + COFF_ObjWriter *obj_writer = coff_obj_writer_alloc(0, COFF_MachineType_X64); + COFF_ObjSymbol *q = coff_obj_writer_push_symbol_abs(obj_writer, str8_lit("q"), 0x111, COFF_SymStorageClass_External); + coff_obj_writer_push_symbol_weak(obj_writer, str8_lit("w"), COFF_WeakExt_SearchAlias, q); + a_obj = coff_obj_writer_serialize(scratch.arena, obj_writer); + coff_obj_writer_release(&obj_writer); + } + + String8 entry_obj; + { + COFF_ObjWriter *obj_writer = coff_obj_writer_alloc(0, COFF_MachineType_X64); + U8 text[] = { + 0x48, 0xC7, 0xC0, 0x00, 0x00, 0x00, 0x00, // mov rax, $imm + 0xC3 // ret + }; + COFF_ObjSection *sect = coff_obj_writer_push_section(obj_writer, str8_lit(".text"), PE_TEXT_SECTION_FLAGS, str8_array_fixed(text)); + coff_obj_writer_push_symbol_extern(obj_writer, str8_lit("entry"), 0, sect); + COFF_ObjSymbol *e = coff_obj_writer_push_symbol_abs(obj_writer, str8_lit("e"), 0x222, COFF_SymStorageClass_External); + COFF_ObjSymbol *sym = coff_obj_writer_push_symbol_weak(obj_writer, str8_lit("w"), COFF_WeakExt_AntiDependency, e); + coff_obj_writer_section_push_reloc_addr32(obj_writer, sect, 3, sym); + entry_obj = coff_obj_writer_serialize(scratch.arena, obj_writer); + coff_obj_writer_release(&obj_writer); + } + + if (!t_write_file(str8_lit("a.obj"), a_obj)) { goto exit; } + if (!t_write_file(str8_lit("entry.obj"), entry_obj)) { goto exit; } + + int linker_exit_code = t_invoke_linkerf("/subsystem:console /entry:entry /out:a.exe entry.obj a.obj"); + if (linker_exit_code != 0) { goto exit; } + + { + String8 exe = t_read_file(scratch.arena, str8_lit("a.exe")); + PE_BinInfo pe = pe_bin_info_from_data(scratch.arena, exe); + COFF_SectionHeader *section_table = (COFF_SectionHeader *)str8_substr(exe, pe.section_table_range).str; + String8 string_table = str8_substr(exe, pe.string_table_range); + COFF_SectionHeader *text_sect = t_coff_section_header_from_name(string_table, section_table, pe.section_count, str8_lit(".text")); + if (text_sect == 0) { goto exit; } + String8 text_data = str8_substr(exe, rng_1u64(text_sect->foff, text_sect->foff + text_sect->vsize)); + String8 imm = str8_substr(text_data, rng_1u64(3, 7)); + U32 expected = 0x111; + if (!str8_match(imm, str8_struct(&expected), 0)) { goto exit; } + } + result = T_Result_Pass; exit:; scratch_end(scratch); @@ -1179,7 +2036,46 @@ exit:; } internal T_Result -t_undef_weak(void) +t_undef_weak_lib(void) +{ + Temp scratch = scratch_begin(0,0); + T_Result result = T_Result_Fail; + + String8 weak; + { + COFF_ObjWriter *obj_writer = coff_obj_writer_alloc(0,COFF_MachineType_X64); + COFF_ObjSymbol *b = coff_obj_writer_push_symbol_abs(obj_writer, str8_lit("b"), 0xc3000000, COFF_SymStorageClass_External); + coff_obj_writer_push_symbol_weak(obj_writer, str8_lit("a"), COFF_WeakExt_SearchLibrary, b); + weak = coff_obj_writer_serialize(scratch.arena, obj_writer); + coff_obj_writer_release(&obj_writer); + } + + String8 entry; + { + COFF_ObjWriter *obj_writer = coff_obj_writer_alloc(0,COFF_MachineType_X64); + COFF_ObjSymbol *sym = coff_obj_writer_push_symbol_undef(obj_writer, str8_lit("a")); + U8 text[4] = {0}; + COFF_ObjSection *sect = coff_obj_writer_push_section(obj_writer, str8_lit(".text"), PE_TEXT_SECTION_FLAGS, str8_array_fixed(text)); + coff_obj_writer_section_push_reloc_voff(obj_writer, sect, 0, sym); + coff_obj_writer_push_symbol_extern(obj_writer, str8_lit("entry"), 0, sect); + entry = coff_obj_writer_serialize(scratch.arena, obj_writer); + } + + if (!t_write_file(str8_lit("weak.obj"), weak)) { goto exit; } + if (!t_write_file(str8_lit("entry.obj"), entry)) { goto exit; } + + // undefined symbol must always replace weak symbol with search library + int linker_exit_code = t_invoke_linkerf("/subsystem:console /out:a.exe /entry:entry entry.obj weak.obj"); + if (linker_exit_code != LNK_Error_UnresolvedSymbol) { goto exit; } + + result = T_Result_Pass; +exit:; + scratch_end(scratch); + return result; +} + +internal T_Result +t_undef_weak_search_alias(void) { Temp scratch = scratch_begin(0,0); T_Result result = T_Result_Fail; @@ -3967,54 +4863,70 @@ entry_point(CmdLine *cmdline) static struct { char *label; T_Result (*r)(void); } target_array[] = { - { "simple_link_test", t_simple_link_test }, - { "machine_compat_check", t_machine_compat_check }, - { "out_of_bounds_section_number", t_out_of_bounds_section_number }, - { "merge", t_merge }, - { "undef_section", t_undef_section }, - { "undef_reloc_section", t_undef_reloc_section }, - { "link_undef", t_link_undef }, - { "link_unref_undef", t_link_unref_undef }, - { "weak_vs_weak", t_weak_vs_weak }, - { "weak_vs_common", t_weak_vs_common }, - { "abs_vs_weak", t_abs_vs_weak }, - { "abs_vs_regular", t_abs_vs_regular }, - { "abs_vs_common", t_abs_vs_common }, - { "abs_vs_abs", t_abs_vs_abs }, - { "undef_weak", t_undef_weak }, - { "sect_symbol", t_sect_symbol }, - { "weak_cycle", t_weak_cycle }, - { "weak_tag", t_weak_tag }, - { "find_merged_pdata", t_find_merged_pdata }, - { "section_sort", t_section_sort }, - { "flag_conf", t_flag_conf }, - { "invalid_bss", t_invalid_bss }, - { "common_block", t_common_block }, - { "base_relocs", t_base_relocs }, - { "simple_lib_test", t_simple_lib_test }, - { "sect_align", t_sect_align }, - { "image_base", t_image_base }, - { "comdat_any", t_comdat_any }, - { "comdat_no_duplicates", t_comdat_no_duplicates }, - { "comdat_same_size", t_comdat_same_size }, - { "comdat_exact_match", t_comdat_exact_match }, - { "comdat_largest", t_comdat_largest }, - { "comdat_associative", t_comdat_associative }, - { "comdat_associative_loop", t_comdat_associative_loop }, - { "comdat_associative_non_comdat", t_comdat_associative_non_comdat }, - { "comdat_associative_out_of_bounds", t_comdat_associative_out_of_bounds }, - { "comdat_with_offset", t_comdat_with_offset }, - { "reloc_against_removed_comdat", t_reloc_against_removed_comdat }, - { "alt_name", t_alt_name }, - { "include", t_include }, - { "communal_var_vs_regular_comdat", t_communal_var_vs_regular_comdat }, - { "communal_var_vs_regular", t_communal_var_vs_regular }, - { "import_kernel32", t_import_kernel32 }, - { "delay_import_user32", t_delay_import_user32 }, - { "delay_import", t_delay_import }, - { "empty_section", t_empty_section }, - { "removed_section", t_removed_section }, - { "function_pad_min", t_function_pad_min }, + { "simple_link_test", t_simple_link_test }, + { "machine_compat_check", t_machine_compat_check }, + { "out_of_bounds_section_number", t_out_of_bounds_section_number }, + { "merge", t_merge }, + { "undef_section", t_undef_section }, + { "undef_reloc_section", t_undef_reloc_section }, + { "link_undef", t_link_undef }, + { "link_unref_undef", t_link_unref_undef }, + { "weak_lib_vs_weak_lib", t_weak_lib_vs_weak_lib }, + { "weak_lib_vs_weak_nolib", t_weak_lib_vs_weak_nolib }, + { "weak_lib_vs_weak_alias", t_weak_lib_vs_weak_alias }, + { "weak_lib_vs_weak_antidep", t_weak_lib_vs_weak_antidep }, + { "weak_alias_vs_weak_alias", t_weak_alias_vs_weak_alias }, + { "weak_alias_vs_weak_lib", t_weak_alias_vs_weak_lib }, + { "weak_alias_vs_weak_nolib", t_weak_alias_vs_weak_nolib }, + { "weak_alias_vs_weak_antidep", t_weak_alias_vs_weak_antidep }, + { "weak_nolib_vs_weak_nolib", t_weak_nolib_vs_weak_nolib }, + { "weak_nolib_vs_weak_lib", t_weak_nolib_vs_weak_lib }, + { "weak_nolib_vs_weak_alias", t_weak_nolib_vs_weak_alias }, + { "weak_nolib_vs_weak_antidep", t_weak_nolib_vs_weak_antidep }, + { "weak_antidep_vs_weak_antidep", t_weak_antidep_vs_weak_antidep }, + { "weak_antidep_vs_weak_nolib", t_weak_antidep_vs_weak_nolib }, + { "weak_antidep_vs_weak_lib", t_weak_antidep_vs_weak_lib }, + { "weak_antidep_vs_weak_alias", t_weak_antidep_vs_weak_alias }, + { "weak_vs_common", t_weak_vs_common }, + { "abs_vs_weak", t_abs_vs_weak }, + { "abs_vs_regular", t_abs_vs_regular }, + { "abs_vs_common", t_abs_vs_common }, + { "abs_vs_abs", t_abs_vs_abs }, + { "undef_weak_lib", t_undef_weak_lib }, + { "undef_weak_search_alias", t_undef_weak_search_alias }, + { "sect_symbol", t_sect_symbol }, + { "weak_cycle", t_weak_cycle }, + { "weak_tag", t_weak_tag }, + { "find_merged_pdata", t_find_merged_pdata }, + { "section_sort", t_section_sort }, + { "flag_conf", t_flag_conf }, + { "invalid_bss", t_invalid_bss }, + { "common_block", t_common_block }, + { "base_relocs", t_base_relocs }, + { "simple_lib_test", t_simple_lib_test }, + { "sect_align", t_sect_align }, + { "image_base", t_image_base }, + { "comdat_any", t_comdat_any }, + { "comdat_no_duplicates", t_comdat_no_duplicates }, + { "comdat_same_size", t_comdat_same_size }, + { "comdat_exact_match", t_comdat_exact_match }, + { "comdat_largest", t_comdat_largest }, + { "comdat_associative", t_comdat_associative }, + { "comdat_associative_loop", t_comdat_associative_loop }, + { "comdat_associative_non_comdat", t_comdat_associative_non_comdat }, + { "comdat_associative_out_of_bounds", t_comdat_associative_out_of_bounds }, + { "comdat_with_offset", t_comdat_with_offset }, + { "reloc_against_removed_comdat", t_reloc_against_removed_comdat }, + { "alt_name", t_alt_name }, + { "include", t_include }, + { "communal_var_vs_regular_comdat", t_communal_var_vs_regular_comdat }, + { "communal_var_vs_regular", t_communal_var_vs_regular }, + { "import_kernel32", t_import_kernel32 }, + { "delay_import_user32", t_delay_import_user32 }, + { "delay_import", t_delay_import }, + { "empty_section", t_empty_section }, + { "removed_section", t_removed_section }, + { "function_pad_min", t_function_pad_min }, }; //