Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

msvc subsystem option handling; added uefi os type #1855

Merged
merged 8 commits into from Dec 26, 2018
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
1 change: 1 addition & 0 deletions CMakeLists.txt
Expand Up @@ -590,6 +590,7 @@ set(ZIG_STD_FILES
"os/freebsd/x86_64.zig"
"os/path.zig"
"os/time.zig"
"os/uefi/index.zig"
"os/windows/advapi32.zig"
"os/windows/error.zig"
"os/windows/index.zig"
Expand Down
2 changes: 1 addition & 1 deletion src-self-hosted/target.zig
Expand Up @@ -520,7 +520,7 @@ pub const Target = union(enum) {
=> return 64,
},

builtin.Os.windows => switch (id) {
builtin.Os.windows, builtin.Os.uefi => switch (id) {
CInt.Id.Short,
CInt.Id.UShort,
=> return 16,
Expand Down
3 changes: 1 addition & 2 deletions src/all_types.hpp
Expand Up @@ -1754,8 +1754,7 @@ struct CodeGen {
bool strip_debug_symbols;
bool is_test_build;
bool is_native_target;
bool windows_subsystem_windows;
bool windows_subsystem_console;
ZigLLVM_MSVCSubsystemType msvc_subsystem;
bool linker_rdynamic;
bool no_rosegment_workaround;
bool each_lib_rpath;
Expand Down
12 changes: 6 additions & 6 deletions src/analyze.cpp
Expand Up @@ -3203,24 +3203,25 @@ void add_fn_export(CodeGen *g, ZigFn *fn_table_entry, Buf *symbol_name, GlobalLi
if (ccc) {
if (buf_eql_str(symbol_name, "main") && g->libc_link_lib != nullptr) {
g->have_c_main = true;
g->windows_subsystem_windows = false;
g->windows_subsystem_console = true;
g->msvc_subsystem = ZigLLVM_MSVC_CONSOLE;
} else if (buf_eql_str(symbol_name, "WinMain") &&
g->zig_target.os == OsWindows)
{
g->have_winmain = true;
g->windows_subsystem_windows = true;
g->windows_subsystem_console = false;
g->msvc_subsystem = ZigLLVM_MSVC_WINDOWS;
} else if (buf_eql_str(symbol_name, "WinMainCRTStartup") &&
g->zig_target.os == OsWindows)
{
g->have_winmain_crt_startup = true;
g->msvc_subsystem = ZigLLVM_MSVC_WINDOWS;
} else if (buf_eql_str(symbol_name, "DllMainCRTStartup") &&
g->zig_target.os == OsWindows)
{
g->have_dllmain_crt_startup = true;
g->msvc_subsystem = ZigLLVM_MSVC_WINDOWS;
}
}

FnExport *fn_export = fn_table_entry->export_list.add_one();
memset(fn_export, 0, sizeof(FnExport));
buf_init_from_buf(&fn_export->name, symbol_name);
Expand Down Expand Up @@ -4376,8 +4377,7 @@ ImportTableEntry *add_source_file(CodeGen *g, PackageTableEntry *package, Buf *r
if (is_pub && ok_cc) {
if (buf_eql_str(proto_name, "main")) {
g->have_pub_main = true;
g->windows_subsystem_windows = false;
g->windows_subsystem_console = true;
g->msvc_subsystem = ZigLLVM_MSVC_CONSOLE;
} else if (buf_eql_str(proto_name, "panic")) {
g->have_pub_panic = true;
}
Expand Down
14 changes: 4 additions & 10 deletions src/codegen.cpp
Expand Up @@ -291,11 +291,6 @@ void codegen_add_framework(CodeGen *g, const char *framework) {
g->darwin_frameworks.append(buf_create_from_str(framework));
}

void codegen_set_windows_subsystem(CodeGen *g, bool mwindows, bool mconsole) {
g->windows_subsystem_windows = mwindows;
g->windows_subsystem_console = mconsole;
}

void codegen_set_mmacosx_version_min(CodeGen *g, Buf *mmacosx_version_min) {
g->mmacosx_version_min = mmacosx_version_min;
}
Expand Down Expand Up @@ -7236,8 +7231,7 @@ static void init(CodeGen *g) {
}

if (g->is_test_build) {
g->windows_subsystem_windows = false;
g->windows_subsystem_console = true;
g->msvc_subsystem = ZigLLVM_MSVC_CONSOLE;
}

assert(g->root_out_name);
Expand Down Expand Up @@ -7273,7 +7267,7 @@ static void init(CodeGen *g) {
// LLVM creates invalid binaries on Windows sometimes.
// See https://github.com/ziglang/zig/issues/508
// As a workaround we do not use target native features on Windows.
if (g->zig_target.os == OsWindows) {
if (g->zig_target.os == OsWindows || g->zig_target.os == OsUefi) {
target_specific_cpu_args = "";
target_specific_features = "";
} else {
Expand Down Expand Up @@ -7519,6 +7513,7 @@ static void gen_root_source(CodeGen *g) {
report_errors_and_maybe_exit(g);

if (!g->is_test_build && g->zig_target.os != OsFreestanding &&
g->zig_target.os != OsZen && g->zig_target.os != OsUefi &&
!g->have_c_main && !g->have_winmain && !g->have_winmain_crt_startup &&
((g->have_pub_main && g->out_type == OutTypeObj) || g->out_type == OutTypeExe))
{
Expand Down Expand Up @@ -8079,8 +8074,7 @@ static Error check_cache(CodeGen *g, Buf *manifest_dir, Buf *digest) {
cache_bool(ch, g->strip_debug_symbols);
cache_bool(ch, g->is_test_build);
cache_bool(ch, g->is_native_target);
cache_bool(ch, g->windows_subsystem_windows);
cache_bool(ch, g->windows_subsystem_console);
cache_int(ch, g->msvc_subsystem);
cache_bool(ch, g->linker_rdynamic);
cache_bool(ch, g->no_rosegment_workaround);
cache_bool(ch, g->each_lib_rpath);
Expand Down
1 change: 0 additions & 1 deletion src/codegen.hpp
Expand Up @@ -33,7 +33,6 @@ void codegen_set_libc_include_dir(CodeGen *codegen, Buf *libc_include_dir);
void codegen_set_msvc_lib_dir(CodeGen *g, Buf *msvc_lib_dir);
void codegen_set_kernel32_lib_dir(CodeGen *codegen, Buf *kernel32_lib_dir);
void codegen_set_dynamic_linker(CodeGen *g, Buf *dynamic_linker);
void codegen_set_windows_subsystem(CodeGen *g, bool mwindows, bool mconsole);
void codegen_add_lib_dir(CodeGen *codegen, const char *dir);
void codegen_add_forbidden_lib(CodeGen *codegen, Buf *lib);
LinkLib *codegen_add_link_lib(CodeGen *codegen, Buf *lib);
Expand Down
8 changes: 7 additions & 1 deletion src/ir.cpp
Expand Up @@ -17872,7 +17872,13 @@ static IrInstruction *ir_analyze_instruction_c_import(IrAnalyze *ira, IrInstruct
if (type_is_invalid(cimport_result->value.type))
return ira->codegen->invalid_instruction;

find_libc_include_path(ira->codegen);
if (ira->codegen->msvc_subsystem != ZigLLVM_MSVC_EFI_APPLICATION &&
ira->codegen->msvc_subsystem != ZigLLVM_MSVC_EFI_BOOT_SERVICE_DRIVER &&
ira->codegen->msvc_subsystem != ZigLLVM_MSVC_EFI_ROM &&
ira->codegen->msvc_subsystem != ZigLLVM_MSVC_EFI_RUNTIME_DRIVER) {

find_libc_include_path(ira->codegen);
}

ImportTableEntry *child_import = allocate<ImportTableEntry>(1);
child_import->decls_scope = create_decls_scope(ira->codegen, node, nullptr, nullptr, child_import);
Expand Down
78 changes: 58 additions & 20 deletions src/link.cpp
Expand Up @@ -455,7 +455,7 @@ static void construct_linker_job_coff(LinkJob *lj) {

lj->args.append("-NOLOGO");

if (!g->strip_debug_symbols) {
if (!g->strip_debug_symbols && g->zig_target.os != Os::OsUefi) {
lj->args.append("-DEBUG");
}

Expand All @@ -466,11 +466,6 @@ static void construct_linker_job_coff(LinkJob *lj) {

coff_append_machine_arg(g, &lj->args);

if (g->windows_subsystem_windows) {
lj->args.append("/SUBSYSTEM:windows");
} else if (g->windows_subsystem_console) {
lj->args.append("/SUBSYSTEM:console");
}
// The commented out stuff is from when we linked with MinGW
// Now that we're linking with LLD it remains to be determined
// how to handle --target-environ gnu
Expand Down Expand Up @@ -499,18 +494,47 @@ static void construct_linker_job_coff(LinkJob *lj) {
// }
//}

lj->args.append(buf_ptr(buf_sprintf("-OUT:%s", buf_ptr(&g->output_file_path))));

if (g->libc_link_lib != nullptr) {
lj->args.append(buf_ptr(buf_sprintf("-LIBPATH:%s", buf_ptr(g->msvc_lib_dir))));
lj->args.append(buf_ptr(buf_sprintf("-LIBPATH:%s", buf_ptr(g->kernel32_lib_dir))));

lj->args.append(buf_ptr(buf_sprintf("-LIBPATH:%s", buf_ptr(g->libc_lib_dir))));
if (g->libc_static_lib_dir != nullptr) {
lj->args.append(buf_ptr(buf_sprintf("-LIBPATH:%s", buf_ptr(g->libc_static_lib_dir))));
}
}

// These are n actual command lines from LINK.EXE UEFI builds (app & driver) to be used as guidance cleaning
// up a bit for building the COFF linker args:
// /OUT:"J:\coding\nebulae\k\x64\Release\k.efi" /LTCG:incremental /Driver /PDB:"J:\coding\nebulae\k\x64\Release\k.pdb" "UefiApplicationEntryPoint.lib" "UefiRuntimeLib.lib" "UefiHiiLib.lib" "UefiHiiServicesLib.lib" "UefiSortLib.lib" "UefiShellLib.lib" "GlueLib.lib" "BaseLib.lib" "BaseDebugPrintErrorLevelLib.lib" "BasePrintLib.lib" "UefiLib.lib" "UefiBootServicesTableLib.lib" "UefiRuntimeServicesTableLib.lib" "UefiDevicePathLibDevicePathProtocol.lib" "UefiDebugLibConOut.lib" "UefiMemoryLib.lib" "UefiMemoryAllocationLib.lib" "BaseSynchronizationLib.lib" "UefiFileHandleLib.lib" /IMPLIB:"J:\coding\nebulae\k\x64\Release\k.lib" /DEBUG:FASTLINK /BASE:"0" /MACHINE:X64 /ENTRY:"EfiMain" /OPT:REF /SAFESEH:NO /SUBSYSTEM:EFI_APPLICATION /MERGE:".rdata=.data" /NOLOGO /ALIGN:32 /NODEFAULTLIB /SECTION:".xdata,D"
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It looks like this example outputs a pdb file, but earlier you disabled the /DEBUG flag for the UEFI subsystem. Is there a reason it has to be disabled, even when --strip is not passed?

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

There is no debugger at that point to make use of the pdb file, at least not without more work I should say. And the command lines were taken from example solution files provided with the VisualUefi toolkit; The inconsistency was overlooked on my part, but I did intentionally disable debugging on uefi targets.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

If the /DEBUG flag is given to the linker, does it break something for you? Or does it merely produce a useless .pdb file?

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

the latter.

// /OUT:"J:\coding\VisualUefi\samples\x64\Release\UefiDriver.efi" /LTCG:incremental /Driver /PDB:"J:\coding\VisualUefi\samples\x64\Release\UefiDriver.pdb" "UefiDriverEntryPoint.lib" "UefiHiiLib.lib" "UefiHiiServicesLib.lib" "UefiSortLib.lib" "UefiShellLib.lib" "GlueLib.lib" "BaseLib.lib" "BaseDebugPrintErrorLevelLib.lib" "BasePrintLib.lib" "UefiLib.lib" "UefiBootServicesTableLib.lib" "UefiRuntimeServicesTableLib.lib" "UefiDevicePathLibDevicePathProtocol.lib" "UefiDebugLibConOut.lib" "UefiMemoryLib.lib" "UefiMemoryAllocationLib.lib" "BaseSynchronizationLib.lib" "UefiFileHandleLib.lib" /IMPLIB:"J:\coding\VisualUefi\samples\x64\Release\UefiDriver.lib" /DEBUG:FASTLINK /BASE:"0" /MACHINE:X64 /ENTRY:"EfiMain" /OPT:REF /SAFESEH:NO /SUBSYSTEM:EFI_BOOT_SERVICE_DRIVER /MERGE:".rdata=.data" /NOLOGO /ALIGN:32 /NODEFAULTLIB /SECTION:".xdata,D"

// Sorry for the goto(s) :)
switch (g->msvc_subsystem) {
case ZigLLVM_MSVC_CONSOLE:
lj->args.append("/SUBSYSTEM:console");
goto building_nt;
case ZigLLVM_MSVC_EFI_APPLICATION:
lj->args.append("/SUBSYSTEM:efi_application");
goto building_uefi;
case ZigLLVM_MSVC_EFI_BOOT_SERVICE_DRIVER:
lj->args.append("/SUBSYSTEM:efi_boot_service_driver");
goto building_uefi;
case ZigLLVM_MSVC_EFI_ROM:
lj->args.append("/SUBSYSTEM:efi_rom");
goto building_uefi;
case ZigLLVM_MSVC_EFI_RUNTIME_DRIVER:
lj->args.append("/SUBSYSTEM:efi_runtime_driver");
goto building_uefi;
case ZigLLVM_MSVC_NATIVE:
lj->args.append("/SUBSYSTEM:native");
goto building_nt;
case ZigLLVM_MSVC_POSIX:
lj->args.append("/SUBSYSTEM:posix");
goto building_nt;
case ZigLLVM_MSVC_WINDOWS:
lj->args.append("/SUBSYSTEM:windows");
goto building_nt;
case ZigLLVM_MSVC_NONE:
goto continuing_build;
}

building_uefi:
lj->args.append("/BASE:\"0\" /ENTRY:\"EfiMain\" /OPT:REF /SAFESEH:NO /MERGE:\".rdata=.data\" /ALIGN:32 /NODEFAULTLIB /SECTION:\".xdata,D\"");
goto continuing_build;

building_nt:
if (lj->link_in_crt) {
const char *lib_str = g->is_static ? "lib" : "";
const char *d_str = (g->build_mode == BuildModeDebug) ? "d" : "";
Expand Down Expand Up @@ -547,16 +571,30 @@ static void construct_linker_job_coff(LinkJob *lj) {
// msvcrt depends on kernel32
lj->args.append("kernel32.lib");
} else {
lj->args.append("-NODEFAULTLIB");
lj->args.append("/NODEFAULTLIB");
if (!is_library) {
if (g->have_winmain) {
lj->args.append("-ENTRY:WinMain");
lj->args.append("/ENTRY:WinMain");
} else {
lj->args.append("-ENTRY:WinMainCRTStartup");
lj->args.append("/ENTRY:WinMainCRTStartup");
}
}
}

continuing_build:

lj->args.append(buf_ptr(buf_sprintf("-OUT:%s", buf_ptr(&g->output_file_path))));

if (g->libc_link_lib != nullptr) {
lj->args.append(buf_ptr(buf_sprintf("-LIBPATH:%s", buf_ptr(g->msvc_lib_dir))));
lj->args.append(buf_ptr(buf_sprintf("-LIBPATH:%s", buf_ptr(g->kernel32_lib_dir))));

lj->args.append(buf_ptr(buf_sprintf("-LIBPATH:%s", buf_ptr(g->libc_lib_dir))));
if (g->libc_static_lib_dir != nullptr) {
lj->args.append(buf_ptr(buf_sprintf("-LIBPATH:%s", buf_ptr(g->libc_static_lib_dir))));
}
}

if (is_library && !g->is_static) {
lj->args.append("-DLL");
}
Expand Down
42 changes: 38 additions & 4 deletions src/main.cpp
Expand Up @@ -16,6 +16,13 @@

#include <stdio.h>

#ifdef __GNUC__
#include <strings.h>
#define STRCASECMP strcasecmp
#else
#define STRCASECMP stricmp
#endif

static int print_error_usage(const char *arg0) {
fprintf(stderr, "See `%s help` for detailed usage information\n", arg0);
return EXIT_FAILURE;
Expand Down Expand Up @@ -90,9 +97,8 @@ static int print_full_usage(const char *arg0) {
" -rdynamic add all symbols to the dynamic symbol table\n"
" -rpath [path] add directory to the runtime library search path\n"
" --no-rosegment compromise security to workaround valgrind bug\n"
" -mconsole (windows) --subsystem console to the linker\n"
" -mwindows (windows) --subsystem windows to the linker\n"
" -framework [name] (darwin) link against framework\n"
" --msvc-subsystem [subsystem] (windows/uefi) /SUBSYSTEM:<subsystem> to the linker\n"
" -framework [name] (darwin) link against framework\n"
" -mios-version-min [ver] (darwin) set iOS deployment target\n"
" -mmacosx-version-min [ver] (darwin) set Mac OS X deployment target\n"
" --ver-major [ver] dynamic library semver major version\n"
Expand Down Expand Up @@ -395,6 +401,7 @@ int main(int argc, char **argv) {
int runtime_args_start = -1;
bool no_rosegment_workaround = false;
bool system_linker_hack = false;
ZigLLVM_MSVCSubsystemType msvc_subsystem_type = ZigLLVM_MSVC_NONE;

if (argc >= 2 && strcmp(argv[1], "build") == 0) {
Buf zig_exe_path_buf = BUF_INIT;
Expand Down Expand Up @@ -540,6 +547,32 @@ int main(int argc, char **argv) {
verbose_llvm_ir = true;
} else if (strcmp(arg, "--verbose-cimport") == 0) {
verbose_cimport = true;
} else if (strcmp(arg, "--msvc-subsystem") == 0) {
if (i + 1 >= argc) {
fprintf(stderr, "Expected 1 argument after --msvc-subsystem\n");
return print_error_usage(arg0);
}
i += 1;
if (STRCASECMP(argv[i], "CONSOLE") == 0) {
msvc_subsystem_type = ZigLLVM_MSVC_CONSOLE;
} else if (STRCASECMP(argv[i], "WINDOWS") == 0) {
msvc_subsystem_type = ZigLLVM_MSVC_WINDOWS;
} else if (STRCASECMP(argv[i], "POSIX") == 0) {
msvc_subsystem_type = ZigLLVM_MSVC_POSIX;
} else if (STRCASECMP(argv[i], "NATIVE") == 0) {
msvc_subsystem_type = ZigLLVM_MSVC_NATIVE;
} else if (STRCASECMP(argv[i], "EFI_APPLICATION") == 0) {
msvc_subsystem_type = ZigLLVM_MSVC_EFI_APPLICATION;
} else if (STRCASECMP(argv[i], "EFI_BOOT_SERVICE_DRIVER") == 0) {
msvc_subsystem_type = ZigLLVM_MSVC_EFI_BOOT_SERVICE_DRIVER;
} else if (STRCASECMP(argv[i], "EFI_ROM") == 0) {
msvc_subsystem_type = ZigLLVM_MSVC_EFI_ROM;
} else if (STRCASECMP(argv[i], "EFI_RUNTIME_DRIVER") == 0) {
msvc_subsystem_type = ZigLLVM_MSVC_EFI_RUNTIME_DRIVER;
} else {
fprintf(stderr, "Unknown format %s for --msvc-subsystem argument\n", argv[i]);
return EXIT_FAILURE;
}
} else if (strcmp(arg, "-mwindows") == 0) {
mwindows = true;
} else if (strcmp(arg, "-mconsole") == 0) {
Expand Down Expand Up @@ -849,6 +882,8 @@ int main(int argc, char **argv) {
buf_out_name = buf_create_from_str("run");
}
CodeGen *g = codegen_create(zig_root_source_file, target, out_type, build_mode, get_zig_lib_dir());
g->msvc_subsystem = msvc_subsystem_type;

if (disable_pic) {
if (out_type != OutTypeLib || !is_static) {
fprintf(stderr, "--disable-pic only applies to static libraries");
Expand Down Expand Up @@ -909,7 +944,6 @@ int main(int argc, char **argv) {
codegen_add_rpath(g, rpath_list.at(i));
}

codegen_set_windows_subsystem(g, mwindows, mconsole);
codegen_set_rdynamic(g, rdynamic);
g->no_rosegment_workaround = no_rosegment_workaround;
if (mmacosx_version_min && mios_version_min) {
Expand Down
12 changes: 10 additions & 2 deletions src/target.cpp
Expand Up @@ -174,6 +174,7 @@ static const Os os_list[] = {
OsContiki,
OsAMDPAL,
OsZen,
OsUefi,
};

// Coordinate with zig_llvm.h
Expand Down Expand Up @@ -315,6 +316,8 @@ ZigLLVM_OSType get_llvm_os_type(Os os_type) {
return ZigLLVM_Contiki;
case OsAMDPAL:
return ZigLLVM_AMDPAL;
case OsUefi:
return ZigLLVM_Uefi;
}
zig_unreachable();
}
Expand Down Expand Up @@ -394,6 +397,8 @@ const char *get_target_os_name(Os os_type) {
return "freestanding";
case OsZen:
return "zen";
case OsUefi:
return "uefi";
case OsAnanas:
case OsCloudABI:
case OsDragonFly:
Expand Down Expand Up @@ -756,6 +761,7 @@ uint32_t target_c_type_size_in_bits(const ZigTarget *target, CIntType id) {
case CIntTypeCount:
zig_unreachable();
}
case OsUefi:
case OsWindows:
switch (id) {
case CIntTypeShort:
Expand Down Expand Up @@ -803,7 +809,7 @@ uint32_t target_c_type_size_in_bits(const ZigTarget *target, CIntType id) {
}

const char *target_o_file_ext(ZigTarget *target) {
if (target->env_type == ZigLLVM_MSVC || target->os == OsWindows) {
if (target->env_type == ZigLLVM_MSVC || (target->os == OsWindows || target->os == OsUefi)) {
return ".obj";
} else {
return ".o";
Expand All @@ -821,13 +827,15 @@ const char *target_llvm_ir_file_ext(ZigTarget *target) {
const char *target_exe_file_ext(ZigTarget *target) {
if (target->os == OsWindows) {
return ".exe";
} else if (target->os == OsUefi) {
return ".efi";
} else {
return "";
}
}

const char *target_lib_file_ext(ZigTarget *target, bool is_static, size_t version_major, size_t version_minor, size_t version_patch) {
if (target->os == OsWindows) {
if (target->os == OsWindows || target->os == OsUefi) {
if (is_static) {
return ".lib";
} else {
Expand Down