Skip to content
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.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 4 additions & 2 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -61,8 +61,8 @@ For Windows i686 and Linux i686 it builds at least.
- For Linux: LLVM, if using `--clang` (default). Must be installed in `/usr/bin`.
- For Linux: GCC, if using `--no-clang`
- For Linux: GNU Binutils
- For Windows: Visual Studio
- For Windows: MinGW
- For Windows, if using MSVC: Visual Studio
Comment thread
illwieckz marked this conversation as resolved.


## SCons usage
Expand Down Expand Up @@ -135,13 +135,15 @@ appropriate architecture (the latter is solely used for the assembler). Python m
python -m pip install scons pywin32
```

You can use the traditional MSVC compiler with `--no-clang`, or `clang-cl` with `--clang`.
When using Visual Studio, you can use the traditional MSVC compiler with `--no-clang`, or `clang-cl` with `--clang`.
Specify the path to the MinGW installation with `mingw_dir=...`. For example:

```
python -m SCons --mode=nacl,opt-windows --no-clang saigo=1 werror=0 mingw_dir=C:\mingw\x86_64-msvcrt-12.2.0 platform=x86-64 sel_ldr irt_core`
```

When using MinGW, you must pass `mingw=1` and `--no-clang`. You can locate the toolchain by either
passing `mingw_dir=...` or putting it in the PATH. MinGW only works with `platform=x86_64`.

### ARM testing

Expand Down
41 changes: 31 additions & 10 deletions SConstruct
Original file line number Diff line number Diff line change
Expand Up @@ -272,6 +272,9 @@ def SetUpArgumentBits(env):
BitFromArgument(env, 'bitcode', default=False,
desc='We are building bitcode')

BitFromArgument(env, 'mingw', default=False,
desc='Use MinGW toolchain for trusted build')

BitFromArgument(env, 'pnacl_native_clang_driver', default=False,
desc='Use the (experimental) native PNaCl Clang driver')

Expand Down Expand Up @@ -1881,6 +1884,10 @@ def CommandTest(env, name, command, size='small', direct_emulation=True,
command = ['${PYTHON}', test_script] + script_flags + command
if 'test_wrapper' in ARGUMENTS:
command = ApplyTestWrapperCommand(command, extra_deps)
if env.Bit('mingw') and 'mingw_dir' in ARGUMENTS:
# get DLLs needed at runtime
env = env.Clone()
env.PrependENVPath('PATH', os.path.join(ARGUMENTS['mingw_dir'], 'bin'))
return env.AutoDepsCommand(name, command,
extra_deps=extra_deps, posix_path=posix_path,
disabled=env.Bit('do_not_run_tests'))
Expand Down Expand Up @@ -2323,8 +2330,9 @@ def MakeWindowsEnv(platform=None):
# Windows /SAFESEH linking requires either an .sxdata section be
# present or that @feat.00 be defined as a local, absolute symbol
# with an odd value.
ASCOM = ('$ASPPCOM /E /D__ASSEMBLER__ | '
'$WINASM -defsym @feat.00=1 -o $TARGET'),
ASCOM = '$ASPPCOM -D__ASSEMBLER__ -Wa,-defsym,@feat.00=1' if base_env.Bit('mingw')
else '$ASPPCOM /E /D__ASSEMBLER__ | '
'$WINASM -defsym @feat.00=1 -o $TARGET',
PDB = '${TARGET.base}.pdb',
# Strict doesn't currently work for Windows since some of the system
# libraries like wsock32 are magical.
Expand All @@ -2344,25 +2352,38 @@ def MakeWindowsEnv(platform=None):
# would conflict with Winsock 1.x included by windows.h.
['WIN32_LEAN_AND_MEAN', ''],
],
LIBS = ['ws2_32', 'advapi32'],
# TODO(bsy) remove 4355 once cross-repo
# NACL_ALLOW_THIS_IN_INITIALIZER_LIST changes go in.
CCFLAGS = ['/EHsc', '/wd4355', '/wd4800']
LIBS = ['ws2_32', 'advapi32', 'winmm'],
)
if windows_env.Bit('mingw'):
# Some C++-using binaries are linked with the C compiler
windows_env.Append(LIBS = ['stdc++'])
else:
# TODO(bsy) remove 4355 once cross-repo
# NACL_ALLOW_THIS_IN_INITIALIZER_LIST changes go in.
windows_env.Append(CCFLAGS = ['/EHsc', '/wd4355', '/wd4800'])

if windows_env.Bit('werror'):
windows_env.Append(CCFLAGS = '/WX')
if windows_env.Bit('mingw'):
windows_env.Append(CCFLAGS='-Werror')
else:
windows_env.Append(CCFLAGS = '/WX')

# This linker option allows us to ensure our builds are compatible with
# Chromium, which uses it.
if windows_env.Bit('build_x86_32'):
windows_env.Append(LINKFLAGS = "/safeseh")

mingw_dir = os.path.abspath(ARGUMENTS.get('mingw_dir', 'You.must.provide.the.mingw_dir.argument'))
windows_env['MINGW_BIN'] = os.path.join(mingw_dir, 'bin')
if 'mingw_dir' in ARGUMENTS:
assert os.path.isdir(ARGUMENTS['mingw_dir'])
windows_env.PrependENVPath('PATH', windows_env['MINGW_BIN'])

# We use the GNU assembler (gas) on Windows so that we can use the
# same .S assembly files on all platforms. Microsoft's assembler uses
# a completely different syntax for x86 code.
mingw_dir = os.path.abspath(ARGUMENTS.get('mingw_dir', 'You.must.provide.the.mingw_dir.argument'))
windows_env['MINGW_BIN'] = os.path.join(mingw_dir, 'bin')
windows_env['WINASM'] = os.path.join(windows_env['MINGW_BIN'], 'as.exe')
if not windows_env.Bit('mingw'):
windows_env.Replace(WINASM = os.path.join(windows_env['MINGW_BIN'], 'as.exe'))

return windows_env

Expand Down
17 changes: 0 additions & 17 deletions site_scons/site_tools/component_builders.py
Original file line number Diff line number Diff line change
Expand Up @@ -120,11 +120,6 @@ def _ComponentPlatformSetup(env, builder_name, **kwargs):
for k, v in kwargs.items():
env[k] = v

# Add compiler flags for included headers, if any
env['INCLUDES'] = env.Flatten(env.subst_list(['$INCLUDES']))
for h in env['INCLUDES']:
env.Append(CCFLAGS=['${CCFLAG_INCLUDE}%s' % h])

# This supports a NaCl convention that was previously supported with a
# modification to SCons. Previously, EXTRA_LIBS was interpolated into LIBS
# using the ${EXTRA_LIBS} syntax. It appears, however, that SCons naturally
Expand Down Expand Up @@ -239,9 +234,6 @@ def ComponentObject(self, *args, **kwargs):
else:
o = env.SharedObject(*args, **kwargs)

# Add dependencies on includes
env.Depends(o, env['INCLUDES'])

return o

#------------------------------------------------------------------------------
Expand Down Expand Up @@ -272,9 +264,6 @@ def ComponentLibrary(self, lib_name, *args, **kwargs):
# BUG: http://code.google.com/p/nativeclient/issues/detail?id=2424
env.FilterOut(LINKFLAGS=['-static'])

# Add dependencies on includes
env.Depends(lib_outputs, env['INCLUDES'])

# Scan library outputs for files we need to link against this library, and
# files we need to run executables linked against this library.
need_for_link = []
Expand Down Expand Up @@ -409,9 +398,6 @@ def ComponentTestProgram(self, prog_name, *args, **kwargs):
# Call env.Program()
out_nodes = env.Program(prog_name, *args, **kwargs)

# Add dependencies on includes
env.Depends(out_nodes, env['INCLUDES'])

# Publish output
env.Publish(prog_name, 'run', out_nodes[0])
env.Publish(prog_name, 'debug', out_nodes[1:])
Expand Down Expand Up @@ -484,9 +470,6 @@ def ComponentProgram(self, prog_name, *args, **kwargs):
# Call env.Program()
out_nodes = env.Program(prog_name, *args, **kwargs)

# Add dependencies on includes
env.Depends(out_nodes, env['INCLUDES'])

# Add dependencies on libraries marked as implicitly included in the link.
# These are libraries that are not passed on the command line, but are
# always linked in by the toolchain, i.e. startup files and -lc and such.
Expand Down
4 changes: 4 additions & 0 deletions site_scons/site_tools/library_deps.py
Original file line number Diff line number Diff line change
Expand Up @@ -172,4 +172,8 @@ def VisitLibrary(library):
VisitLibrary(library)

closure.reverse()
if env.Bit('mingw'):
# There are circular dependencies such as gio <-> platform.
# How does this work for any other compiler?
closure *= 2
return closure
1 change: 0 additions & 1 deletion site_scons/site_tools/target_platform_linux.py
Original file line number Diff line number Diff line change
Expand Up @@ -50,7 +50,6 @@ def generate(env):
env.Replace(
TARGET_PLATFORM='LINUX',
COMPONENT_PLATFORM_SETUP=ComponentPlatformSetup,
CCFLAG_INCLUDE='-include', # Command line option to include a header

# Code coverage related.
COVERAGE_CCFLAGS=['-ftest-coverage', '-fprofile-arcs', '-DCOVERAGE'],
Expand Down
1 change: 0 additions & 1 deletion site_scons/site_tools/target_platform_mac.py
Original file line number Diff line number Diff line change
Expand Up @@ -116,7 +116,6 @@ def generate(env):
env.Replace(
TARGET_PLATFORM='MAC',
COMPONENT_PLATFORM_SETUP=ComponentPlatformSetup,
CCFLAG_INCLUDE='-include', # Command line option to include a header

# Code coverage related.
COVERAGE_CCFLAGS=['--coverage', '-DCOVERAGE'],
Expand Down
25 changes: 19 additions & 6 deletions site_scons/site_tools/target_platform_windows.py
Original file line number Diff line number Diff line change
Expand Up @@ -244,6 +244,7 @@ def generate(env):
# itself. A more principled fix would be nice.

use_msvc_tools = (env['PLATFORM'] in ('win32', 'cygwin')
and not env.Bit('mingw')
and not env.Bit('built_elsewhere')
and not env.Bit('force_no_trusted_build'))

Expand All @@ -264,14 +265,16 @@ def generate(env):
env.Tool('as')
env.Tool('msvs')
env.Tool('windows_hard_link')
elif env.Bit('mingw'):
env.Tool('mingw')

pre_msvc_env = env['ENV'].copy()

if use_msvc_tools:
env.Tool('msvc')
env.Tool('mslib')
env.Tool('mslink')
else:
elif not env.Bit('mingw'):
# Make sure we have all the builders even when MSVC is not available.
# Without these (fake) builders, SCons cannot be run on a Windows bot
# that does not have MSVC installed - even if MSVC is never invoked.
Expand Down Expand Up @@ -309,10 +312,7 @@ def RES(*argv, **karg):
'$MSVSSCONSCOM "$MSVSBUILDTARGET"']),
)

env.SetDefault(
# Command line option to include a header
CCFLAG_INCLUDE='/FI',

if not env.Bit('mingw'): env.SetDefault(
# Generate PDBs matching target name by default.
PDB='${TARGET.base}.pdb',

Expand Down Expand Up @@ -378,7 +378,20 @@ def RES(*argv, **karg):
SHMANIFEST_COMSTR='$SHMANIFEST_COM',
)

env.Append(
# TODO: manifests for mingw
if env.Bit('mingw'): env.Append(
CCFLAGS_DEBUG=['-g'],
#CCFLAGS_OPTIMIZED=['-Os'], # doesn't link?
CCFLAGS_OPTIMIZED=['-O1'],

CPPDEFINES=[
['_FORTIFY_SOURCE', '2']
],

COMPONENT_LIBRARY_LINK_SUFFIXES=['.a'],
COMPONENT_LIBRARY_DEBUG_SUFFIXES=[],
)
else: env.Append(
# Turn up the warning level
CCFLAGS=['/W3'],

Expand Down
6 changes: 3 additions & 3 deletions src/shared/platform/build.scons
Original file line number Diff line number Diff line change
Expand Up @@ -54,9 +54,9 @@ if env.Bit('windows'):
time_slop_args += [ '-s', '10' ]
# Needed for rand_s().
env.Append(
CCFLAGS = ['/D_CRT_RAND_S',
'/D_UNICODE',
'/DUNICODE'],
CPPDEFINES = ['_CRT_RAND_S',
'_UNICODE',
'UNICODE'],
)
elif env.Bit('linux'):
platform_inputs += [
Expand Down
76 changes: 76 additions & 0 deletions src/trusted/service_runtime/arch/x86_64/nacl_switch_unwind_win.S
Original file line number Diff line number Diff line change
@@ -0,0 +1,76 @@
// Ported to GNU syntax from nacl_switch_unwind_win.asm
// used this random GCC assembly dump from reddit as a template for SEH directives...
// https://www.reddit.com/r/Assembly_language/comments/1cc94of/what_do_the_seh_tags_mean/

// Copyright (c) 2012 The Native Client Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

#include "native_client/src/include/nacl_asm.h"

#define push_reg(R) push R; .seh_pushreg R;

.text

// This routine passes control on to NaClSwitch(), after setting up a
// trusted stack that will later be used for running
// NaClSyscallCSegHook(). The stack is set up so that it can be
// unwound, which involves storing a return address with unwind info.
// To generate unwind info, we need to use Microsoft's x86-64
// assembler.
//
// We want to make the stack unwindable so that a last-chance exception
// handler registered with SetUnhandledExceptionFilter() -- in
// particular, Breakpad's handler -- will get called when a hardware
// exception occurs. x86-64 Windows uses stack unwinding to find
// exception handlers, and the last-chance handler is not guaranteed to
// get called if the stack is malformed. For background, see:
// http://code.google.com/p/nativeclient/issues/detail?id=2237
// http://code.google.com/p/nativeclient/issues/detail?id=2414

// Arg 1 (rcx): user_context (&natp->user), passed on to NaClSwitch()
// Arg 2 (rdx): address of natp->user.trusted_stack_ptr
.seh_proc NaclSwitchSavingStackPtr
DEFINE_GLOBAL_HIDDEN_FUNCTION(NaClSwitchSavingStackPtr):
// Save all callee-saved registers. This is necessary in case
// the caller is using a frame pointer. The Windows ABI
// permits the caller to use any callee-saved register as a
// frame pointer, not just rbp, so we have to save them all.
push_reg(%rbp)
push_reg(%r12)
push_reg(%r13)
push_reg(%r14)
push_reg(%r15)
push_reg(%rdi)
push_reg(%rsi)
push_reg(%rbx)
// Allocate 0x20 bytes for the shadow space, plus an additional
// 8 bytes to align the stack pointer.
sub $0x28, %rsp
.seh_stackalloc 0x28
.seh_endprologue
// Save rsp-8 in struct NaClThreadContext.
// i.e. Save the value of rsp as it will appear after the
// return address is pushed by the 'call' instruction.
mov %rsp, %r12
sub $8, %r12
mov %r12, 0(%rdx)

call *IDENTIFIER(NaClSwitch)(%rip)

// We get here after returning from a system call.
// NaClSyscallCSegHook returned the struct NaClThreadContext
// pointer. Now make that the argument to the NaClSwitch
// function. Note that the address of this instruction, pushed
// by the call above as its return address, stays at the top of
// the trusted stack. It will be reused again and again, as
// the return address when NaClSyscallCSegHook returns after
// each system call. Hence it's important to use a jmp rather
// than a call here, so that this return address is not clobbered.
// The NaClSwitch functions never look at the incoming
// (trusted) stack--they immediately switch the rsp to the
// untrusted stack pointer--so they don't care whether they're
// entered via call or jmp.
mov %rax, %rcx
jmp *IDENTIFIER(NaClSwitch)(%rip)
.seh_endproc
14 changes: 9 additions & 5 deletions src/trusted/service_runtime/build.scons
Original file line number Diff line number Diff line change
Expand Up @@ -96,18 +96,22 @@ elif env.Bit('build_x86_64'):
'arch/x86_64/tramp_64.S',
]
if env.Bit('windows'):
# We assemble the .asm assembly file with the Microsoft assembler
# because we need to generate x86-64 Windows unwind info, which
# the GNU assembler we use elsewhere does not support.
win64_asm_env = env.Clone(ASCOM='ml64 $ASFLAGS /c /Fo$TARGET $SOURCES')
# Back in ~2012 the GNU assembler did not support x86-64 Windows unwind info, which
# is why a .asm assembly file with the Microsoft assembler is used.
# But now the GNU assembler can handler it so we have an equivalent .S version.
# Some test targets that exercise the unwind info:
# run_crash_in_syscall_test run_log_fatal_in_syscall_test run_check_failure_in_syscall_test run_jump_to_zero_in_syscall_test run_jump_into_sandbox_in_syscall_crash_test
ldr_inputs += [
'arch/x86_64/sel_addrspace_win_x86_64.c',
'arch/x86_64/fnstcw.S',
'arch/x86_64/fxsaverstor.S']
if not env.Bit('force_no_trusted_build'):
if env.Bit('mingw'):
ldr_inputs += ['arch/x86_64/nacl_switch_unwind_win.S']
elif not env.Bit('force_no_trusted_build'):
# This use of win64_asm_env causes an invocation of MSVC, even if sel_ldr
# would not otherwise be actually built. So don't include it if we aren't
# actually building sel_ldr
win64_asm_env = env.Clone(ASCOM='ml64 $ASFLAGS /c /Fo$TARGET $SOURCES')
ldr_inputs += [
win64_asm_env.ComponentObject('arch/x86_64/nacl_switch_unwind_win.asm')]
else:
Expand Down
11 changes: 6 additions & 5 deletions tests/run_py/nacl.scons
Original file line number Diff line number Diff line change
Expand Up @@ -21,11 +21,6 @@ elif env.Bit('nacl_glibc'):
# With the new glibc port, it won't work at all.
Return()

if 'TRUSTED_ENV' in env and env['TRUSTED_ENV'].Bit('windows'):
# To find readelf. Saigo also has a readelf but it's named x86_64-nacl-readelf (etc.)
env = env.Clone()
env.PrependENVPath('PATH', env['TRUSTED_ENV']['MINGW_BIN'])

sel_ldr = env.GetSelLdr()
if sel_ldr is None:
print('WARNING: no sel_ldr found. Skipping test %s' % name)
Expand All @@ -48,6 +43,12 @@ run_py_options = [
'--loader', sel_ldr,
'--elf_loader', elf_ldr,
]

if 'TRUSTED_ENV' in env and env['TRUSTED_ENV'].Bit('windows'):
# To find readelf. Saigo also has a readelf but it's named x86_64-nacl-readelf (etc.)
env = env.Clone()
env.PrependENVPath('PATH', env['TRUSTED_ENV']['MINGW_BIN'])

node = env.CommandTest(
name,
command=['${PYTHON}', '${SCONSTRUCT_DIR}/run.py'] + run_py_options + [exe],
Expand Down
2 changes: 1 addition & 1 deletion tests/trusted_crash/crash_in_syscall/nacl.scons
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,7 @@ trusted_env = env['TRUSTED_ENV']

extra_libs = []
if trusted_env.Bit('windows'):
extra_libs.append('dbghelp.lib')
extra_libs.append('dbghelp' if trusted_env.Bit('mingw') else 'dbghelp.lib')
runner = trusted_env.ComponentProgram(
'test_host', ['test_host.c'],
EXTRA_LIBS=['sel'] + extra_libs)
Expand Down