mirror of
https://github.com/Ed94/raddebugger.git
synced 2026-11-14 02:03:27 -08:00
radlink: implement /NOENTRY
This commit is contained in:
1 parent
4663d1a89a
commit
5b646344eb
5 files changed
+234
-49
No files matched your search
+43
-43
@@ -166,20 +166,20 @@ coff_section_header_array_from_name(Arena *arena, String8 string_table, COFF_Sec
|
||||
}
|
||||
|
||||
|
||||
internal COFF_ParsedSymbol
|
||||
coff_parse_symbol32(String8 string_table, COFF_Symbol32 *sym32)
|
||||
{
|
||||
COFF_ParsedSymbol result = coff_parse_symbol32_no_name(sym32);
|
||||
result.name = coff_read_symbol_name(string_table, &sym32->name);
|
||||
return result;
|
||||
}
|
||||
|
||||
internal force_inline COFF_ParsedSymbol
|
||||
coff_parse_symbol32_no_name(COFF_Symbol32 *sym32)
|
||||
{
|
||||
COFF_ParsedSymbol result = {0};
|
||||
result.value = sym32->value;
|
||||
result.section_number = sym32->section_number;
|
||||
internal COFF_ParsedSymbol
|
||||
coff_parse_symbol32(String8 string_table, COFF_Symbol32 *sym32)
|
||||
{
|
||||
COFF_ParsedSymbol result = coff_parse_symbol32_no_name(sym32);
|
||||
result.name = coff_read_symbol_name(string_table, &sym32->name);
|
||||
return result;
|
||||
}
|
||||
|
||||
internal force_inline COFF_ParsedSymbol
|
||||
coff_parse_symbol32_no_name(COFF_Symbol32 *sym32)
|
||||
{
|
||||
COFF_ParsedSymbol result = {0};
|
||||
result.value = sym32->value;
|
||||
result.section_number = sym32->section_number;
|
||||
result.type = sym32->type;
|
||||
result.storage_class = sym32->storage_class;
|
||||
result.aux_symbol_count = sym32->aux_symbol_count;
|
||||
@@ -187,19 +187,19 @@ coff_parse_symbol32_no_name(COFF_Symbol32 *sym32)
|
||||
return result;
|
||||
}
|
||||
|
||||
internal COFF_ParsedSymbol
|
||||
coff_parse_symbol16(String8 string_table, COFF_Symbol16 *sym16)
|
||||
{
|
||||
COFF_ParsedSymbol result = coff_parse_symbol16_no_name(sym16);
|
||||
result.name = coff_read_symbol_name(string_table, &sym16->name);
|
||||
return result;
|
||||
}
|
||||
|
||||
internal force_inline COFF_ParsedSymbol
|
||||
coff_parse_symbol16_no_name(COFF_Symbol16 *sym16)
|
||||
{
|
||||
COFF_ParsedSymbol result = {0};
|
||||
result.value = sym16->value;
|
||||
internal COFF_ParsedSymbol
|
||||
coff_parse_symbol16(String8 string_table, COFF_Symbol16 *sym16)
|
||||
{
|
||||
COFF_ParsedSymbol result = coff_parse_symbol16_no_name(sym16);
|
||||
result.name = coff_read_symbol_name(string_table, &sym16->name);
|
||||
return result;
|
||||
}
|
||||
|
||||
internal force_inline COFF_ParsedSymbol
|
||||
coff_parse_symbol16_no_name(COFF_Symbol16 *sym16)
|
||||
{
|
||||
COFF_ParsedSymbol result = {0};
|
||||
result.value = sym16->value;
|
||||
if (sym16->section_number == COFF_Symbol_DebugSection16) {
|
||||
result.section_number = COFF_Symbol_DebugSection32;
|
||||
} else if (sym16->section_number == COFF_Symbol_AbsSection16) {
|
||||
@@ -214,8 +214,8 @@ coff_parse_symbol16_no_name(COFF_Symbol16 *sym16)
|
||||
return result;
|
||||
}
|
||||
|
||||
internal COFF_ParsedSymbol
|
||||
coff_parse_symbol(COFF_FileHeaderInfo header, String8 string_table, String8 symbol_table, U32 symbol_idx)
|
||||
internal COFF_ParsedSymbol
|
||||
coff_parse_symbol(COFF_FileHeaderInfo header, String8 string_table, String8 symbol_table, U32 symbol_idx)
|
||||
{
|
||||
COFF_ParsedSymbol symbol;
|
||||
if (header.is_big_obj) {
|
||||
@@ -223,20 +223,20 @@ coff_parse_symbol(COFF_FileHeaderInfo header, String8 string_table, String8 symb
|
||||
} else {
|
||||
symbol = coff_parse_symbol16(string_table, (COFF_Symbol16 *)symbol_table.str + symbol_idx);
|
||||
}
|
||||
return symbol;
|
||||
}
|
||||
|
||||
internal force_inline COFF_ParsedSymbol
|
||||
coff_parse_symbol_no_name(COFF_FileHeaderInfo header, String8 symbol_table, U32 symbol_idx)
|
||||
{
|
||||
COFF_ParsedSymbol symbol;
|
||||
if (header.is_big_obj) {
|
||||
symbol = coff_parse_symbol32_no_name((COFF_Symbol32 *)symbol_table.str + symbol_idx);
|
||||
} else {
|
||||
symbol = coff_parse_symbol16_no_name((COFF_Symbol16 *)symbol_table.str + symbol_idx);
|
||||
}
|
||||
return symbol;
|
||||
}
|
||||
return symbol;
|
||||
}
|
||||
|
||||
internal force_inline COFF_ParsedSymbol
|
||||
coff_parse_symbol_no_name(COFF_FileHeaderInfo header, String8 symbol_table, U32 symbol_idx)
|
||||
{
|
||||
COFF_ParsedSymbol symbol;
|
||||
if (header.is_big_obj) {
|
||||
symbol = coff_parse_symbol32_no_name((COFF_Symbol32 *)symbol_table.str + symbol_idx);
|
||||
} else {
|
||||
symbol = coff_parse_symbol16_no_name((COFF_Symbol16 *)symbol_table.str + symbol_idx);
|
||||
}
|
||||
return symbol;
|
||||
}
|
||||
|
||||
internal COFF_Symbol32Array
|
||||
coff_symbol_array_from_data_16(Arena *arena, String8 raw_coff, U64 symbol_array_off, U64 symbol_count)
|
||||
|
||||
+10
-6
@@ -1366,13 +1366,13 @@ lnk_load_inputs(TP_Context *tp, TP_Arena *arena, LNK_Config *config, LNK_Inputer
|
||||
// load new libs
|
||||
lnk_load_libs(tp, arena, config, inputer, link);
|
||||
|
||||
// resolve entry point
|
||||
// resolve entry point and subsystem
|
||||
if (link->try_to_resolve_entry_point) {
|
||||
B32 is_entry_point_name_inferred = config->entry_point_name.size == 0;
|
||||
|
||||
// loop over all possible subsystems and entry point names and pick
|
||||
// subsystem that has a defined entry point symbol
|
||||
if (config->entry_point_name.size == 0) {
|
||||
if (config->no_entry == 0 && config->entry_point_name.size == 0) {
|
||||
PE_WindowsSubsystem subsys_first = config->subsystem;
|
||||
PE_WindowsSubsystem subsys_last = config->subsystem == PE_WindowsSubsystem_UNKNOWN ? PE_WindowsSubsystem_COUNT : config->subsystem+1;
|
||||
LNK_Symbol *entry_point_symbol = 0;
|
||||
@@ -1391,7 +1391,7 @@ lnk_load_inputs(TP_Context *tp, TP_Arena *arena, LNK_Config *config, LNK_Inputer
|
||||
}
|
||||
|
||||
// search for entry point in libs
|
||||
if (config->entry_point_name.size == 0 && config->subsystem != PE_WindowsSubsystem_UNKNOWN) {
|
||||
if (config->no_entry == 0 && config->entry_point_name.size == 0 && config->subsystem != PE_WindowsSubsystem_UNKNOWN) {
|
||||
String8Array entry_points = pe_get_entry_point_names(config->machine, config->subsystem, config->file_characteristics);
|
||||
for EachIndex(entry_idx, entry_points.count) {
|
||||
for (LNK_LibNode *lib_n = link->libs.first; lib_n != 0; lib_n = lib_n->next) {
|
||||
@@ -1427,7 +1427,9 @@ lnk_load_inputs(TP_Context *tp, TP_Arena *arena, LNK_Config *config, LNK_Inputer
|
||||
}
|
||||
|
||||
// generate undefined symbol for entry point
|
||||
lnk_include_symbol(config, config->entry_point_name, 0);
|
||||
if (config->entry_point_name.size) {
|
||||
lnk_include_symbol(config, config->entry_point_name, 0);
|
||||
}
|
||||
|
||||
// do we have a subsystem?
|
||||
if (config->subsystem != PE_WindowsSubsystem_UNKNOWN) {
|
||||
@@ -2271,7 +2273,7 @@ lnk_link_image(TP_Context *tp, TP_Arena *arena, LNK_Config *config, LNK_Inputer
|
||||
//
|
||||
// was entry point resolved?
|
||||
//
|
||||
if (config->entry_point_name.size == 0 || link->try_to_resolve_entry_point) {
|
||||
if (config->no_entry == 0 && (config->entry_point_name.size == 0 || link->try_to_resolve_entry_point)) {
|
||||
String8 machine_str = coff_string_from_machine_type(config->machine);
|
||||
String8 subsystem_str = pe_string_from_subsystem(config->subsystem);
|
||||
String8Array entry_points = pe_get_entry_point_names(config->machine, config->subsystem, config->file_characteristics);
|
||||
@@ -5635,7 +5637,7 @@ lnk_build_win32_header(Arena *arena, LNK_SymbolTable *symtab, LNK_Config *config
|
||||
//
|
||||
// entry point
|
||||
//
|
||||
{
|
||||
if (config->no_entry == 0) {
|
||||
Temp scratch = scratch_begin(&arena, 1);
|
||||
|
||||
COFF_SectionHeader **section_table = push_array(arena, COFF_SectionHeader *, coff_section_table_count + 1);
|
||||
@@ -7076,6 +7078,8 @@ entry_point(CmdLine *cmdline)
|
||||
case LNK_BootMode_TypeServer: lnk_run_type_server(tp, tp_arena, config); break;
|
||||
}
|
||||
|
||||
// Stop workers before tearing down linker state.
|
||||
tp_release(tp);
|
||||
lnk_log_end();
|
||||
scratch_end(scratch);
|
||||
}
|
||||
@@ -50,6 +50,7 @@ global LNK_CmdSwitch g_cmd_switch_map[] =
|
||||
{ LNK_CmdSwitch_Natvis, 0, LNK_CmdValueKind_Scalar, "NATVIS", ":FILENAME", "NATVIS to embed in the PDB." },
|
||||
{ LNK_CmdSwitch_NoDefaultLib, 1, LNK_CmdValueKind_Scalar, "NODEFAULTLIB", ":LIBNAME", "Ignore a /DEFAULTLIB." },
|
||||
{ LNK_CmdSwitch_NoDefaultLib, 0, LNK_CmdValueKind_Scalar, "NOD", ":LIBNAME", "Alias for /NODEFAULTLIB." },
|
||||
{ LNK_CmdSwitch_NoEntry, 0, LNK_CmdValueKind_Null, "NOENTRY", "", "Link to a DLL without an entry point." },
|
||||
{ LNK_CmdSwitch_NoExp, 0, LNK_CmdValueKind_Null, "NOEXP", "", "No support." },
|
||||
{ LNK_CmdSwitch_NoImpLib, 0, LNK_CmdValueKind_Null, "NOIMPLIB", "", "Do not create the import library." },
|
||||
{ LNK_CmdSwitch_NxCompat, 0, LNK_CmdValueKind_Scalar, "NXCOMPAT", "[:NO]", "Image is compatible with data execution prevention." },
|
||||
@@ -1362,6 +1363,7 @@ lnk_apply_cmd_option_to_config(LNK_Config *config, String8 cmd_name, String8 val
|
||||
}
|
||||
|
||||
config->entry_point_name = new_entry_point_name;
|
||||
config->no_entry = 0;
|
||||
} break;
|
||||
|
||||
case LNK_CmdSwitch_Export: {
|
||||
@@ -1701,6 +1703,10 @@ lnk_apply_cmd_option_to_config(LNK_Config *config, String8 cmd_name, String8 val
|
||||
}
|
||||
} break;
|
||||
|
||||
case LNK_CmdSwitch_NoEntry: {
|
||||
config->no_entry = 1;
|
||||
} break;
|
||||
|
||||
case LNK_CmdSwitch_NoExp: {
|
||||
config->build_exp = 0;
|
||||
} break;
|
||||
@@ -3190,6 +3196,10 @@ lnk_config_init(U64 argc, char **argv)
|
||||
lnk_apply_write_temp_files(arena, config);
|
||||
}
|
||||
|
||||
if (config->no_entry && (config->file_characteristics & PE_ImageFileCharacteristic_DLL) == 0) {
|
||||
lnk_error_cmd_switch(LNK_Error_IncomatibleCmdOptions, 0, LNK_CmdSwitch_NoEntry, "cannot link current image without an entry point; please use /DLL");
|
||||
}
|
||||
|
||||
scratch_end(scratch);
|
||||
ProfEnd();
|
||||
return config;
|
||||
|
||||
@@ -82,6 +82,7 @@ typedef enum
|
||||
LNK_CmdSwitch_Merge,
|
||||
LNK_CmdSwitch_Natvis,
|
||||
LNK_CmdSwitch_NoDefaultLib,
|
||||
LNK_CmdSwitch_NoEntry,
|
||||
LNK_CmdSwitch_NoExp,
|
||||
LNK_CmdSwitch_NoImpLib,
|
||||
LNK_CmdSwitch_NxCompat,
|
||||
@@ -425,6 +426,7 @@ typedef struct LNK_Config
|
||||
LNK_SwitchState type_server;
|
||||
LNK_SwitchState sort_imports;
|
||||
LNK_SwitchState llvm_addrsig;
|
||||
B32 no_entry;
|
||||
} LNK_Config;
|
||||
|
||||
// --- MSVC Error Codes --------------------------------------------------------
|
||||
|
||||
@@ -637,6 +637,175 @@ TEST(simple_link_test)
|
||||
T_Ok(opt->loader_flags == 0);
|
||||
}
|
||||
|
||||
TEST(entry_point)
|
||||
{
|
||||
// Give the user entry, CRT startup, and custom entry distinct offsets so that
|
||||
// the PE header tells us which symbol was selected, including CRT redirection.
|
||||
struct {
|
||||
char *user_entry;
|
||||
char *crt_entry;
|
||||
} entries[] = {
|
||||
{ "main", "mainCRTStartup" },
|
||||
{ "wmain", "wmainCRTStartup" },
|
||||
{ "WinMain", "WinMainCRTStartup" },
|
||||
{ "wWinMain", "wWinMainCRTStartup" },
|
||||
{ "DllMain", "_DllMainCRTStartup" },
|
||||
};
|
||||
for EachElement(i, entries) {
|
||||
T_COFF_DefObj obj = {
|
||||
.machine = T_COFF_DefSetMachine(X64),
|
||||
.sections = (T_COFF_DefSection[]){
|
||||
{ "text", ".text", str8_lit_comp("\xc3\xc3\xc3"), .flags = "rx:code@1" },
|
||||
{0}
|
||||
},
|
||||
.symbols = (T_COFF_DefSymbol[]){
|
||||
T_COFF_DefSymbol_ExternFunc(entries[i].user_entry, "text", 0),
|
||||
T_COFF_DefSymbol_ExternFunc(entries[i].crt_entry, "text", 1),
|
||||
T_COFF_DefSymbol_ExternFunc("custom_entry", "text", 2),
|
||||
{0}
|
||||
}
|
||||
};
|
||||
T_Ok(t_write_def_obj((char *)str8f(arena, "%s.obj", entries[i].user_entry).str, obj));
|
||||
T_Ok(t_write_def_lib((char *)str8f(arena, "%s.lib", entries[i].user_entry).str, (T_COFF_DefLib){
|
||||
.members = (T_COFF_DefLibMember[]){
|
||||
{ .type = T_COFF_DefLibMember_Obj, .obj = obj },
|
||||
{0}
|
||||
}
|
||||
}));
|
||||
}
|
||||
|
||||
// Keep a real input section even when no startup object is needed.
|
||||
T_Ok(t_write_def_obj("data.obj", (T_COFF_DefObj){
|
||||
.sections = (T_COFF_DefSection[]){
|
||||
{ "data", ".data", str8_lit("data"), .flags = "rw:data" },
|
||||
{0}
|
||||
}
|
||||
}));
|
||||
T_Ok(t_write_def_obj("crt.obj", (T_COFF_DefObj){
|
||||
.sections = (T_COFF_DefSection[]){
|
||||
{ "text", ".text", str8_lit_comp("\xc3"), .flags = "rx:code@1" },
|
||||
{0}
|
||||
},
|
||||
.symbols = (T_COFF_DefSymbol[]){
|
||||
T_COFF_DefSymbol_ExternFunc("mainCRTStartup", "text", 0),
|
||||
{0}
|
||||
}
|
||||
}));
|
||||
|
||||
// /NOENTRY must not extract this member just to resolve DLL startup. Without /NOENTRY,
|
||||
// the missing dependency proves that the member was extracted.
|
||||
T_Ok(t_write_def_lib("bad_startup.lib", (T_COFF_DefLib){
|
||||
.members = (T_COFF_DefLibMember[]){
|
||||
{ .type = T_COFF_DefLibMember_Obj, .obj = {
|
||||
.sections = (T_COFF_DefSection[]){
|
||||
{ "text", ".text", str8_lit_comp("\xe8\0\0\0\0\xc3"), .flags = "rx:code@1",
|
||||
.relocs = (T_COFF_DefReloc[]){
|
||||
T_COFF_DefReloc(X64_Rel32, 1, "missing_dependency"),
|
||||
{0}
|
||||
}
|
||||
},
|
||||
{0}
|
||||
},
|
||||
.symbols = (T_COFF_DefSymbol[]){
|
||||
T_COFF_DefSymbol_ExternFunc("_DllMainCRTStartup", "text", 0),
|
||||
T_COFF_DefSymbol_UndefFunc("missing_dependency"),
|
||||
{0}
|
||||
}
|
||||
} },
|
||||
{0}
|
||||
}
|
||||
}));
|
||||
|
||||
struct {
|
||||
char *options;
|
||||
char *inputs;
|
||||
PE_WindowsSubsystem subsystem;
|
||||
S32 entry_off; // -1 means no entry point.
|
||||
LNK_ErrorCode error;
|
||||
} cases[] = {
|
||||
// Explicit /ENTRY bypasses CRT redirection and overrides default startup.
|
||||
{ "/subsystem:console /entry:custom_entry", "main.obj", PE_WindowsSubsystem_WINDOWS_CUI, 2 },
|
||||
{ "/subsystem:console /entry:main", "main.obj", PE_WindowsSubsystem_WINDOWS_CUI, 0 },
|
||||
{ "/entry:main", "main.obj", PE_WindowsSubsystem_WINDOWS_CUI, 0 },
|
||||
{ "/dll /entry:custom_entry", "DllMain.obj", PE_WindowsSubsystem_WINDOWS_GUI, 2 },
|
||||
{ "/subsystem:console /entry:custom_entry", "main.lib", PE_WindowsSubsystem_WINDOWS_CUI, 2 },
|
||||
|
||||
// Infer the subsystem and redirect each user entry to its CRT startup.
|
||||
{ "", "main.obj", PE_WindowsSubsystem_WINDOWS_CUI, 1 },
|
||||
{ "", "wmain.obj", PE_WindowsSubsystem_WINDOWS_CUI, 1 },
|
||||
{ "", "WinMain.obj", PE_WindowsSubsystem_WINDOWS_GUI, 1 },
|
||||
{ "", "wWinMain.obj", PE_WindowsSubsystem_WINDOWS_GUI, 1 },
|
||||
{ "/subsystem:console", "main.obj", PE_WindowsSubsystem_WINDOWS_CUI, 1 },
|
||||
{ "/subsystem:console", "wmain.obj", PE_WindowsSubsystem_WINDOWS_CUI, 1 },
|
||||
{ "/subsystem:windows", "WinMain.obj", PE_WindowsSubsystem_WINDOWS_GUI, 1 },
|
||||
{ "/subsystem:windows", "wWinMain.obj", PE_WindowsSubsystem_WINDOWS_GUI, 1 },
|
||||
{ "/subsystem:console", "crt.obj", PE_WindowsSubsystem_WINDOWS_CUI, 0 },
|
||||
|
||||
// Resolve startup from a library, or use the default DLL entry/subsystem.
|
||||
{ "/subsystem:console", "main.lib", PE_WindowsSubsystem_WINDOWS_CUI, 1 },
|
||||
{ "/subsystem:console /entry:wmainCRTStartup", "wmain.lib", PE_WindowsSubsystem_WINDOWS_CUI, 1 },
|
||||
{ "/subsystem:windows", "WinMain.lib", PE_WindowsSubsystem_WINDOWS_GUI, 1 },
|
||||
{ "/subsystem:windows /entry:wWinMainCRTStartup", "wWinMain.lib", PE_WindowsSubsystem_WINDOWS_GUI, 1 },
|
||||
{ "/dll", "DllMain.obj", PE_WindowsSubsystem_WINDOWS_GUI, 1 },
|
||||
{ "/dll", "DllMain.lib", PE_WindowsSubsystem_WINDOWS_GUI, 1 },
|
||||
{ "/dll /subsystem:console", "DllMain.obj", PE_WindowsSubsystem_WINDOWS_CUI, 1 },
|
||||
|
||||
// /NOENTRY leaves a zero RVA even when default startup symbols are available.
|
||||
{ "/dll /noentry", "", PE_WindowsSubsystem_WINDOWS_GUI, -1 },
|
||||
{ "/noentry /dll", "", PE_WindowsSubsystem_WINDOWS_GUI, -1 },
|
||||
{ "/dll /noentry", "DllMain.obj", PE_WindowsSubsystem_WINDOWS_GUI, -1 },
|
||||
{ "/dll /noentry", "DllMain.lib", PE_WindowsSubsystem_WINDOWS_GUI, -1 },
|
||||
{ "/dll /noentry", "bad_startup.lib", PE_WindowsSubsystem_WINDOWS_GUI, -1 },
|
||||
{ "/dll /noentry /subsystem:console", "", PE_WindowsSubsystem_WINDOWS_CUI, -1 },
|
||||
|
||||
// Match LINK: the last /ENTRY or /NOENTRY wins, including undefined entries.
|
||||
{ "/dll /entry:custom_entry /noentry", "DllMain.obj", PE_WindowsSubsystem_WINDOWS_GUI, -1 },
|
||||
{ "/dll /noentry /entry:custom_entry", "DllMain.obj", PE_WindowsSubsystem_WINDOWS_GUI, 2 },
|
||||
{ "/dll /entry:missing_entry /noentry", "", PE_WindowsSubsystem_WINDOWS_GUI, -1, LNK_Error_UnresolvedSymbol },
|
||||
{ "/dll /noentry /entry:missing_entry", "", 0, -1, LNK_Error_UnresolvedSymbol },
|
||||
{ "/noentry /subsystem:console /entry:main", "main.obj", PE_WindowsSubsystem_WINDOWS_CUI, 0 },
|
||||
|
||||
// Missing startup, unresolved explicit entry, and invalid /NOENTRY usage.
|
||||
{ "/subsystem:console", "", 0, 0, LNK_Error_EntryPoint },
|
||||
{ "/dll", "", 0, 0, LNK_Error_EntryPoint },
|
||||
{ "/subsystem:console /entry:missing_entry", "main.obj", 0, 0, LNK_Error_UnresolvedSymbol },
|
||||
{ "/dll", "bad_startup.lib", 0, 0, LNK_Error_UnresolvedSymbol },
|
||||
{ "/noentry /subsystem:console", "", 0, 0, LNK_Error_IncomatibleCmdOptions },
|
||||
{ "/subsystem:console /entry:main /noentry", "main.obj", 0, 0, LNK_Error_IncomatibleCmdOptions },
|
||||
};
|
||||
|
||||
for EachElement(i, cases) {
|
||||
String8 out_name = str8f(arena, "entry_%u.dll", i);
|
||||
test_outf("entry configuration %u: %s data.obj %s\n", i, cases[i].options, cases[i].inputs);
|
||||
T_Ok(t_invoke_linkerf("/machine:x64 /nod /manifest:no /opt:ref /opt:noicf /out:%S %s data.obj %s", out_name, cases[i].options, cases[i].inputs));
|
||||
|
||||
if (cases[i].error) {
|
||||
T_Ok(g_last_exit_code != 0);
|
||||
|
||||
if (t_id_linker() == Linker_radlink) {
|
||||
T_Ok(g_last_exit_code == cases[i].error);
|
||||
}
|
||||
} else {
|
||||
T_Ok(g_last_exit_code == 0);
|
||||
|
||||
String8 image = t_read_file(arena, out_name);
|
||||
PE_BinInfo pe = pe_bin_info_from_data(arena, image);
|
||||
T_Ok(pe.arch == Arch_x64);
|
||||
T_Ok(pe.subsystem == cases[i].subsystem);
|
||||
|
||||
if (cases[i].entry_off < 0) {
|
||||
T_Ok(pe.entry_point == 0);
|
||||
} else {
|
||||
COFF_SectionHeader *sections = (COFF_SectionHeader *)str8_substr(image, pe.section_table_range).str;
|
||||
String8 strings = str8_substr(image, pe.string_table_range);
|
||||
COFF_SectionHeader *text = coff_section_header_from_name(strings, sections, pe.section_count, str8_lit(".text"));
|
||||
T_Ok(text);
|
||||
T_Ok(pe.entry_point == text->voff + cases[i].entry_off);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
TEST(map)
|
||||
{
|
||||
T_Ok(t_write_def_obj("map.obj", (T_COFF_DefObj){
|
||||
|
||||
Reference in new issue
Block a user