jit: port libgccjit to Windows
2020-05-28 Nicolas Bértolo <nicolasbertolo@gmail.com> /ChangeLog: * configure.ac: Don't require --enable-host-shared when building for Mingw. * configure: Regenerate. 2020-05-28 Nicolas Bértolo <nicolasbertolo@gmail.com> gcc/ChangeLog: * Makefile.in: don't look for libiberty in the "pic" subdirectory when building for Mingw. Add dependency on xgcc with the proper extension. 2020-05-28 Nicolas Bértolo <nicolasbertolo@gmail.com> gcc/c/ChangeLog: * Make-lang.in: Remove extra slash. 2020-05-28 Nicolas Bértolo <nicolasbertolo@gmail.com> gcc/jit/ChangeLog: * Make-lang.in: Remove extra slash. Build libgccjit.dll and its import library in Windows. * config-lang.in: Update comment about --enable-host-shared. * jit-w32.h: New file. * jit-w32.c: New file. (print_last_error): New function that prints the error string corresponding to GetLastError(). (get_TOKEN_USER_current_user): Helper function used for getting the SID belonging to the current user. (create_directory_for_current_user): Helper function to create a directory with permissions such that only the current user can access it. (win_mkdtemp): Create a temporary directory using Windows APIs. * jit-playback.c: Do not chmod files in Windows. Use LoadLibrary, FreeLibrary and GetProcAddress instead of libdl. * jit-result.h, jit-result.c: Introduce result::handle_t to abstract over the types used for dynamic library handles. * jit-tempdir.c: Do not use mkdtemp() in Windows, use win_mkdtemp().
This commit is contained in:
parent
ccf4e86dc0
commit
c83027f32d
32
configure
vendored
32
configure
vendored
@ -6489,9 +6489,13 @@ $as_echo "$as_me: WARNING: GNAT is required to build $language" >&2;}
|
||||
esac
|
||||
|
||||
# Disable jit if -enable-host-shared not specified
|
||||
case ${add_this_lang}:${language}:${host_shared} in
|
||||
yes:jit:no)
|
||||
# PR jit/64780: explicitly specify --enable-host-shared
|
||||
# but not if building for Mingw
|
||||
case $target in
|
||||
*mingw*) ;;
|
||||
*)
|
||||
case ${add_this_lang}:${language}:${host_shared} in
|
||||
yes:jit:no)
|
||||
# PR jit/64780: explicitly specify --enable-host-shared
|
||||
as_fn_error $? "
|
||||
Enabling language \"jit\" requires --enable-host-shared.
|
||||
|
||||
@ -6502,17 +6506,19 @@ If you want to build both the jit and the regular compiler, it is often
|
||||
best to do this via two separate configure/builds, in separate
|
||||
directories, to avoid imposing the performance cost of
|
||||
--enable-host-shared on the regular compiler." "$LINENO" 5
|
||||
;;
|
||||
all:jit:no)
|
||||
{ $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: --enable-host-shared required to build $language" >&5
|
||||
;;
|
||||
all:jit:no)
|
||||
{ $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: --enable-host-shared required to build $language" >&5
|
||||
$as_echo "$as_me: WARNING: --enable-host-shared required to build $language" >&2;}
|
||||
add_this_lang=unsupported
|
||||
;;
|
||||
*:jit:no)
|
||||
# Silently disable.
|
||||
add_this_lang=unsupported
|
||||
;;
|
||||
esac
|
||||
add_this_lang=unsupported
|
||||
;;
|
||||
*:jit:no)
|
||||
# Silently disable.
|
||||
add_this_lang=unsupported
|
||||
;;
|
||||
esac
|
||||
;;
|
||||
esac
|
||||
|
||||
# Disable a language that is unsupported by the target.
|
||||
case "${add_this_lang}: $unsupported_languages " in
|
||||
|
33
configure.ac
33
configure.ac
@ -2079,9 +2079,14 @@ if test -d ${srcdir}/gcc; then
|
||||
esac
|
||||
|
||||
# Disable jit if -enable-host-shared not specified
|
||||
case ${add_this_lang}:${language}:${host_shared} in
|
||||
yes:jit:no)
|
||||
# PR jit/64780: explicitly specify --enable-host-shared
|
||||
# but not if building for Mingw. All code in Windows
|
||||
# is position independent code (PIC).
|
||||
case $target in
|
||||
*mingw*) ;;
|
||||
*)
|
||||
case ${add_this_lang}:${language}:${host_shared} in
|
||||
yes:jit:no)
|
||||
# PR jit/64780: explicitly specify --enable-host-shared
|
||||
AC_MSG_ERROR([
|
||||
Enabling language "jit" requires --enable-host-shared.
|
||||
|
||||
@ -2092,16 +2097,18 @@ If you want to build both the jit and the regular compiler, it is often
|
||||
best to do this via two separate configure/builds, in separate
|
||||
directories, to avoid imposing the performance cost of
|
||||
--enable-host-shared on the regular compiler.])
|
||||
;;
|
||||
all:jit:no)
|
||||
AC_MSG_WARN([--enable-host-shared required to build $language])
|
||||
add_this_lang=unsupported
|
||||
;;
|
||||
*:jit:no)
|
||||
# Silently disable.
|
||||
add_this_lang=unsupported
|
||||
;;
|
||||
esac
|
||||
;;
|
||||
all:jit:no)
|
||||
AC_MSG_WARN([--enable-host-shared required to build $language])
|
||||
add_this_lang=unsupported
|
||||
;;
|
||||
*:jit:no)
|
||||
# Silently disable.
|
||||
add_this_lang=unsupported
|
||||
;;
|
||||
esac
|
||||
;;
|
||||
esac
|
||||
|
||||
# Disable a language that is unsupported by the target.
|
||||
case "${add_this_lang}: $unsupported_languages " in
|
||||
|
@ -1046,10 +1046,12 @@ ALL_LINKERFLAGS = $(ALL_CXXFLAGS)
|
||||
|
||||
# Build and host support libraries.
|
||||
|
||||
# Use the "pic" build of libiberty if --enable-host-shared.
|
||||
# Use the "pic" build of libiberty if --enable-host-shared, unless we are
|
||||
# building for mingw.
|
||||
LIBIBERTY_PICDIR=$(if $(findstring mingw,$(target)),,pic)
|
||||
ifeq ($(enable_host_shared),yes)
|
||||
LIBIBERTY = ../libiberty/pic/libiberty.a
|
||||
BUILD_LIBIBERTY = $(build_libobjdir)/libiberty/pic/libiberty.a
|
||||
LIBIBERTY = ../libiberty/$(LIBIBERTY_PICDIR)/libiberty.a
|
||||
BUILD_LIBIBERTY = $(build_libobjdir)/libiberty/$(LIBIBERTY_PICDIR)/libiberty.a
|
||||
else
|
||||
LIBIBERTY = ../libiberty/libiberty.a
|
||||
BUILD_LIBIBERTY = $(build_libobjdir)/libiberty/libiberty.a
|
||||
@ -1726,7 +1728,7 @@ MOSTLYCLEANFILES = insn-flags.h insn-config.h insn-codes.h \
|
||||
# This symlink makes the full installation name of the driver be available
|
||||
# from within the *build* directory, for use when running the JIT library
|
||||
# from there (e.g. when running its testsuite).
|
||||
$(FULL_DRIVER_NAME): ./xgcc
|
||||
$(FULL_DRIVER_NAME): ./xgcc$(exeext)
|
||||
rm -f $@
|
||||
$(LN_S) $< $@
|
||||
|
||||
|
@ -162,7 +162,7 @@ c.install-plugin: installdirs
|
||||
# Install import library.
|
||||
ifeq ($(plugin_implib),yes)
|
||||
$(mkinstalldirs) $(DESTDIR)$(plugin_resourcesdir)
|
||||
$(INSTALL_DATA) cc1$(exeext).a $(DESTDIR)/$(plugin_resourcesdir)/cc1$(exeext).a
|
||||
$(INSTALL_DATA) cc1$(exeext).a $(DESTDIR)$(plugin_resourcesdir)/cc1$(exeext).a
|
||||
endif
|
||||
|
||||
c.uninstall:
|
||||
|
@ -40,10 +40,19 @@
|
||||
# into the jit rule, but that needs a little bit of work
|
||||
# to do the right thing within all.cross.
|
||||
|
||||
ifneq (,$(findstring mingw,$(target)))
|
||||
LIBGCCJIT_FILENAME = libgccjit.dll
|
||||
|
||||
jit: $(LIBGCCJIT_FILENAME) \
|
||||
$(FULL_DRIVER_NAME)
|
||||
|
||||
else
|
||||
|
||||
LIBGCCJIT_LINKER_NAME = libgccjit.so
|
||||
LIBGCCJIT_VERSION_NUM = 0
|
||||
LIBGCCJIT_MINOR_NUM = 0
|
||||
LIBGCCJIT_RELEASE_NUM = 1
|
||||
|
||||
LIBGCCJIT_SONAME = $(LIBGCCJIT_LINKER_NAME).$(LIBGCCJIT_VERSION_NUM)
|
||||
LIBGCCJIT_FILENAME = \
|
||||
$(LIBGCCJIT_SONAME).$(LIBGCCJIT_MINOR_NUM).$(LIBGCCJIT_RELEASE_NUM)
|
||||
@ -68,6 +77,7 @@ jit: $(LIBGCCJIT_FILENAME) \
|
||||
$(LIBGCCJIT_SYMLINK) \
|
||||
$(LIBGCCJIT_LINKER_NAME_SYMLINK) \
|
||||
$(FULL_DRIVER_NAME)
|
||||
endif
|
||||
|
||||
# Tell GNU make to ignore these if they exist.
|
||||
.PHONY: jit
|
||||
@ -84,9 +94,21 @@ jit_OBJS = attribs.o \
|
||||
jit/jit-spec.o \
|
||||
gcc.o
|
||||
|
||||
ifneq (,$(findstring mingw,$(target)))
|
||||
jit_OBJS += jit/jit-w32.o
|
||||
endif
|
||||
|
||||
# Use strict warnings for this front end.
|
||||
jit-warn = $(STRICT_WARN)
|
||||
|
||||
ifneq (,$(findstring mingw,$(target)))
|
||||
# Create import library libgccjit.dll.a
|
||||
LIBGCCJIT_EXTRA_OPTS = -Wl,--out-implib,$(LIBGCCJIT_FILENAME).a
|
||||
else
|
||||
LIBGCCJIT_EXTRA_OPTS = $(LIBGCCJIT_VERSION_SCRIPT_OPTION) \
|
||||
$(LIBGCCJIT_SONAME_OPTION)
|
||||
endif
|
||||
|
||||
# We avoid using $(BACKEND) from Makefile.in in order to avoid pulling
|
||||
# in main.o
|
||||
$(LIBGCCJIT_FILENAME): $(jit_OBJS) \
|
||||
@ -98,14 +120,16 @@ $(LIBGCCJIT_FILENAME): $(jit_OBJS) \
|
||||
$(jit_OBJS) libbackend.a libcommon-target.a libcommon.a \
|
||||
$(CPPLIB) $(LIBDECNUMBER) $(EXTRA_GCC_LIBS) $(LIBS) $(BACKENDLIBS) \
|
||||
$(EXTRA_GCC_OBJS) \
|
||||
$(LIBGCCJIT_VERSION_SCRIPT_OPTION) \
|
||||
$(LIBGCCJIT_SONAME_OPTION)
|
||||
$(LIBGCCJIT_EXTRA_OPTS)
|
||||
|
||||
# Create symlinks when not building for Windows
|
||||
ifeq (,$(findstring mingw,$(target)))
|
||||
$(LIBGCCJIT_SONAME_SYMLINK): $(LIBGCCJIT_FILENAME)
|
||||
ln -sf $(LIBGCCJIT_FILENAME) $(LIBGCCJIT_SONAME_SYMLINK)
|
||||
|
||||
$(LIBGCCJIT_LINKER_NAME_SYMLINK): $(LIBGCCJIT_SONAME_SYMLINK)
|
||||
ln -sf $(LIBGCCJIT_SONAME_SYMLINK) $(LIBGCCJIT_LINKER_NAME_SYMLINK)
|
||||
endif
|
||||
|
||||
#
|
||||
# Build hooks:
|
||||
@ -275,19 +299,31 @@ selftest-jit:
|
||||
|
||||
#
|
||||
# Install hooks:
|
||||
jit.install-common: installdirs
|
||||
jit.install-headers:
|
||||
$(INSTALL_DATA) $(srcdir)/jit/libgccjit.h \
|
||||
$(DESTDIR)$(includedir)/libgccjit.h
|
||||
$(INSTALL_DATA) $(srcdir)/jit/libgccjit++.h \
|
||||
$(DESTDIR)$(includedir)/libgccjit++.h
|
||||
|
||||
ifneq (,$(findstring mingw,$(target)))
|
||||
jit.install-common: installdirs jit.install-headers
|
||||
# Install import library
|
||||
$(INSTALL_PROGRAM) $(LIBGCCJIT_FILENAME).a \
|
||||
$(DESTDIR)$(libdir)/$(LIBGCCJIT_FILENAME).a
|
||||
# Install DLL file
|
||||
$(INSTALL_PROGRAM) $(LIBGCCJIT_FILENAME) \
|
||||
$(DESTDIR)/$(libdir)/$(LIBGCCJIT_FILENAME)
|
||||
$(DESTDIR)$(bindir)/$(LIBGCCJIT_FILENAME)
|
||||
else
|
||||
jit.install-common: installdirs jit.install-headers
|
||||
$(INSTALL_PROGRAM) $(LIBGCCJIT_FILENAME) \
|
||||
$(DESTDIR)$(libdir)/$(LIBGCCJIT_FILENAME)
|
||||
ln -sf \
|
||||
$(LIBGCCJIT_FILENAME) \
|
||||
$(DESTDIR)/$(libdir)/$(LIBGCCJIT_SONAME_SYMLINK)
|
||||
$(DESTDIR)$(libdir)/$(LIBGCCJIT_SONAME_SYMLINK)
|
||||
ln -sf \
|
||||
$(LIBGCCJIT_SONAME_SYMLINK)\
|
||||
$(DESTDIR)/$(libdir)/$(LIBGCCJIT_LINKER_NAME_SYMLINK)
|
||||
$(INSTALL_DATA) $(srcdir)/jit/libgccjit.h \
|
||||
$(DESTDIR)/$(includedir)/libgccjit.h
|
||||
$(INSTALL_DATA) $(srcdir)/jit/libgccjit++.h \
|
||||
$(DESTDIR)/$(includedir)/libgccjit++.h
|
||||
$(DESTDIR)$(libdir)/$(LIBGCCJIT_LINKER_NAME_SYMLINK)
|
||||
endif
|
||||
|
||||
jit.install-man:
|
||||
|
||||
|
@ -32,7 +32,7 @@ target_libs=""
|
||||
gtfiles="\$(srcdir)/jit/dummy-frontend.c"
|
||||
|
||||
# The configuration requires --enable-host-shared
|
||||
# for jit to be supported.
|
||||
# for jit to be supported (only when not building for Mingw).
|
||||
# Hence to get the jit, one must configure with:
|
||||
# --enable-host-shared --enable-languages=jit
|
||||
build_by_default="no"
|
||||
|
@ -47,6 +47,10 @@ along with GCC; see the file COPYING3. If not see
|
||||
#include "jit-builtins.h"
|
||||
#include "jit-tempdir.h"
|
||||
|
||||
#ifdef _WIN32
|
||||
#include "jit-w32.h"
|
||||
#endif
|
||||
|
||||
/* Compare with gcc/c-family/c-common.h: DECL_C_BIT_FIELD,
|
||||
SET_DECL_C_BIT_FIELD.
|
||||
These are redefined here to avoid depending from the C frontend. */
|
||||
@ -2159,8 +2163,10 @@ playback::compile_to_file::copy_file (const char *src_path,
|
||||
|
||||
gcc_assert (total_sz_in == total_sz_out);
|
||||
if (get_logger ())
|
||||
get_logger ()->log ("total bytes copied: %ld", total_sz_out);
|
||||
get_logger ()->log ("total bytes copied: %zu", total_sz_out);
|
||||
|
||||
/* fchmod does not exist in Windows. */
|
||||
#ifndef _WIN32
|
||||
/* Set the permissions of the copy to those of the original file,
|
||||
in particular the "executable" bits. */
|
||||
if (fchmod (fileno (f_out), stat_buf.st_mode) == -1)
|
||||
@ -2168,6 +2174,7 @@ playback::compile_to_file::copy_file (const char *src_path,
|
||||
"error setting mode of %s: %s",
|
||||
dst_path,
|
||||
xstrerror (errno));
|
||||
#endif
|
||||
|
||||
fclose (f_out);
|
||||
}
|
||||
@ -2644,10 +2651,19 @@ dlopen_built_dso ()
|
||||
{
|
||||
JIT_LOG_SCOPE (get_logger ());
|
||||
auto_timevar load_timevar (get_timer (), TV_LOAD);
|
||||
void *handle = NULL;
|
||||
const char *error = NULL;
|
||||
result::handle handle = NULL;
|
||||
result *result_obj = NULL;
|
||||
|
||||
#ifdef _WIN32
|
||||
/* Clear any existing error. */
|
||||
SetLastError(0);
|
||||
|
||||
handle = LoadLibrary(m_tempdir->get_path_so_file ());
|
||||
if (GetLastError() != 0) {
|
||||
print_last_error();
|
||||
}
|
||||
#else
|
||||
const char *error = NULL;
|
||||
/* Clear any existing error. */
|
||||
dlerror ();
|
||||
|
||||
@ -2656,6 +2672,8 @@ dlopen_built_dso ()
|
||||
if ((error = dlerror()) != NULL) {
|
||||
add_error (NULL, "%s", error);
|
||||
}
|
||||
#endif
|
||||
|
||||
if (handle)
|
||||
{
|
||||
/* We've successfully dlopened the result; create a
|
||||
|
@ -27,13 +27,17 @@ along with GCC; see the file COPYING3. If not see
|
||||
#include "jit-result.h"
|
||||
#include "jit-tempdir.h"
|
||||
|
||||
#ifdef _WIN32
|
||||
#include "jit-w32.h"
|
||||
#endif
|
||||
|
||||
namespace gcc {
|
||||
namespace jit {
|
||||
|
||||
/* Constructor for gcc::jit::result. */
|
||||
|
||||
result::
|
||||
result(logger *logger, void *dso_handle, tempdir *tempdir_) :
|
||||
result(logger *logger, handle dso_handle, tempdir *tempdir_) :
|
||||
log_user (logger),
|
||||
m_dso_handle (dso_handle),
|
||||
m_tempdir (tempdir_)
|
||||
@ -49,8 +53,11 @@ result::~result()
|
||||
{
|
||||
JIT_LOG_SCOPE (get_logger ());
|
||||
|
||||
#ifdef _WIN32
|
||||
FreeLibrary(m_dso_handle);
|
||||
#else
|
||||
dlclose (m_dso_handle);
|
||||
|
||||
#endif
|
||||
/* Responsibility for cleaning up the tempdir (including "fake.so" within
|
||||
the filesystem) might have been handed to us by the playback::context,
|
||||
so that the cleanup can be delayed (see PR jit/64206).
|
||||
@ -72,8 +79,17 @@ get_code (const char *funcname)
|
||||
JIT_LOG_SCOPE (get_logger ());
|
||||
|
||||
void *code;
|
||||
const char *error;
|
||||
|
||||
#ifdef _WIN32
|
||||
/* Clear any existing error. */
|
||||
SetLastError(0);
|
||||
|
||||
code = (void *)GetProcAddress(m_dso_handle, funcname);
|
||||
if (GetLastError() != 0) {
|
||||
print_last_error ();
|
||||
}
|
||||
#else
|
||||
const char *error;
|
||||
/* Clear any existing error. */
|
||||
dlerror ();
|
||||
|
||||
@ -82,6 +98,7 @@ get_code (const char *funcname)
|
||||
if ((error = dlerror()) != NULL) {
|
||||
fprintf(stderr, "%s\n", error);
|
||||
}
|
||||
#endif
|
||||
|
||||
return code;
|
||||
}
|
||||
@ -99,8 +116,17 @@ get_global (const char *name)
|
||||
JIT_LOG_SCOPE (get_logger ());
|
||||
|
||||
void *global;
|
||||
const char *error;
|
||||
|
||||
#ifdef _WIN32
|
||||
/* Clear any existing error. */
|
||||
SetLastError(0);
|
||||
|
||||
global = (void *)GetProcAddress(m_dso_handle, name);
|
||||
if (GetLastError() != 0) {
|
||||
print_last_error ();
|
||||
}
|
||||
#else
|
||||
const char *error;
|
||||
/* Clear any existing error. */
|
||||
dlerror ();
|
||||
|
||||
@ -109,6 +135,7 @@ get_global (const char *name)
|
||||
if ((error = dlerror()) != NULL) {
|
||||
fprintf(stderr, "%s\n", error);
|
||||
}
|
||||
#endif
|
||||
|
||||
return global;
|
||||
}
|
||||
|
@ -21,6 +21,10 @@ along with GCC; see the file COPYING3. If not see
|
||||
#ifndef JIT_RESULT_H
|
||||
#define JIT_RESULT_H
|
||||
|
||||
#ifdef _WIN32
|
||||
#include <minwindef.h>
|
||||
#endif
|
||||
|
||||
namespace gcc {
|
||||
|
||||
namespace jit {
|
||||
@ -29,7 +33,13 @@ namespace jit {
|
||||
class result : public log_user
|
||||
{
|
||||
public:
|
||||
result(logger *logger, void *dso_handle, tempdir *tempdir_);
|
||||
#ifdef _WIN32
|
||||
typedef HMODULE handle;
|
||||
#else
|
||||
typedef void* handle;
|
||||
#endif
|
||||
|
||||
result(logger *logger, handle dso_handle, tempdir *tempdir_);
|
||||
|
||||
virtual ~result();
|
||||
|
||||
@ -40,7 +50,7 @@ public:
|
||||
get_global (const char *name);
|
||||
|
||||
private:
|
||||
void *m_dso_handle;
|
||||
handle m_dso_handle;
|
||||
tempdir *m_tempdir;
|
||||
};
|
||||
|
||||
|
@ -24,7 +24,11 @@ along with GCC; see the file COPYING3. If not see
|
||||
|
||||
#include "jit-tempdir.h"
|
||||
|
||||
#ifdef _WIN32
|
||||
#include "jit-w32.h"
|
||||
#endif
|
||||
|
||||
#ifndef _WIN32
|
||||
/* Construct a tempdir path template suitable for use by mkdtemp
|
||||
e.g. "/tmp/libgccjit-XXXXXX", but respecting the rules in
|
||||
libiberty's choose_tempdir rather than hardcoding "/tmp/".
|
||||
@ -62,6 +66,7 @@ make_tempdir_path_template ()
|
||||
|
||||
return result;
|
||||
}
|
||||
#endif
|
||||
|
||||
/* The constructor for the jit::tempdir object.
|
||||
The real work is done by the jit::tempdir::create method. */
|
||||
@ -87,6 +92,9 @@ gcc::jit::tempdir::create ()
|
||||
{
|
||||
JIT_LOG_SCOPE (get_logger ());
|
||||
|
||||
#ifdef _WIN32
|
||||
m_path_tempdir = win_mkdtemp ();
|
||||
#else
|
||||
m_path_template = make_tempdir_path_template ();
|
||||
if (!m_path_template)
|
||||
return false;
|
||||
@ -97,6 +105,8 @@ gcc::jit::tempdir::create ()
|
||||
is unique. Hence no other (non-root) users should have access to
|
||||
the paths within it. */
|
||||
m_path_tempdir = mkdtemp (m_path_template);
|
||||
#endif
|
||||
|
||||
if (!m_path_tempdir)
|
||||
return false;
|
||||
log ("m_path_tempdir: %s", m_path_tempdir);
|
||||
|
255
gcc/jit/jit-w32.c
Normal file
255
gcc/jit/jit-w32.c
Normal file
@ -0,0 +1,255 @@
|
||||
/* Functions used by the Windows port of libgccjit.
|
||||
Copyright (C) 2020 Free Software Foundation, Inc.
|
||||
Contributed by Nicolas Bertolo <nicolasbertolo@gmail.com>.
|
||||
|
||||
This file is part of GCC.
|
||||
|
||||
GCC is free software; you can redistribute it and/or modify it
|
||||
under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation; either version 3, or (at your option)
|
||||
any later version.
|
||||
|
||||
GCC is distributed in the hope that it will be useful, but
|
||||
WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with GCC; see the file COPYING3. If not see
|
||||
<http://www.gnu.org/licenses/>. */
|
||||
|
||||
#include "config.h"
|
||||
|
||||
/* Required for rand_s */
|
||||
#define _CRT_RAND_S
|
||||
|
||||
#include <cstdio>
|
||||
#include <cstdint>
|
||||
|
||||
#include "jit-w32.h"
|
||||
|
||||
#include "libiberty.h"
|
||||
|
||||
#include <accctrl.h>
|
||||
#include <aclapi.h>
|
||||
|
||||
namespace gcc {
|
||||
namespace jit {
|
||||
void
|
||||
print_last_error (void)
|
||||
{
|
||||
LPSTR psz = NULL;
|
||||
DWORD dwErrorCode;
|
||||
dwErrorCode = GetLastError();
|
||||
const DWORD cchMsg = FormatMessage(FORMAT_MESSAGE_FROM_SYSTEM
|
||||
| FORMAT_MESSAGE_IGNORE_INSERTS
|
||||
| FORMAT_MESSAGE_ALLOCATE_BUFFER
|
||||
| FORMAT_MESSAGE_MAX_WIDTH_MASK,
|
||||
NULL,
|
||||
dwErrorCode,
|
||||
MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT),
|
||||
reinterpret_cast<LPSTR>(&psz),
|
||||
0,
|
||||
NULL);
|
||||
if (cchMsg > 0)
|
||||
{
|
||||
fprintf (stderr, "%s\n", psz);
|
||||
LocalFree (psz);
|
||||
}
|
||||
else
|
||||
{
|
||||
fprintf (stderr, "Failed to retrieve error message string for error %lu\n",
|
||||
dwErrorCode);
|
||||
}
|
||||
}
|
||||
|
||||
/* Helper function used for getting the SID belonging to the current user. */
|
||||
static TOKEN_USER*
|
||||
get_TOKEN_USER_current_user ()
|
||||
{
|
||||
TOKEN_USER *result = NULL;
|
||||
|
||||
HANDLE process_token = INVALID_HANDLE_VALUE;
|
||||
|
||||
DWORD token_user_info_len;
|
||||
TOKEN_USER *token_user = NULL;
|
||||
|
||||
/* Get current process access token. */
|
||||
if (!OpenProcessToken (GetCurrentProcess (), TOKEN_READ,
|
||||
&process_token))
|
||||
return NULL;
|
||||
|
||||
/* Get necessary buffer size. */
|
||||
if (!GetTokenInformation(process_token, TokenUser, NULL, 0, &token_user_info_len)
|
||||
&& GetLastError() != ERROR_INSUFFICIENT_BUFFER)
|
||||
goto cleanup;
|
||||
|
||||
token_user = (TOKEN_USER*) new char[token_user_info_len];
|
||||
|
||||
/* Get info about the user of the process */
|
||||
if (!GetTokenInformation (process_token, TokenUser, token_user,
|
||||
token_user_info_len, &token_user_info_len))
|
||||
goto cleanup;
|
||||
|
||||
result = token_user;
|
||||
|
||||
cleanup:
|
||||
if (process_token != INVALID_HANDLE_VALUE)
|
||||
CloseHandle(process_token);
|
||||
|
||||
if (token_user != NULL && result == NULL)
|
||||
delete[] (char*)token_user;
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
/* Helper function to create a directory with permissions such that only the
|
||||
current user can access it. */
|
||||
static bool
|
||||
create_directory_for_current_user (const char * path)
|
||||
{
|
||||
PACL pACL = NULL;
|
||||
EXPLICIT_ACCESS ea;
|
||||
SECURITY_ATTRIBUTES sa;
|
||||
SECURITY_DESCRIPTOR SD;
|
||||
DWORD dwRes;
|
||||
bool result = true;
|
||||
TOKEN_USER *token_user = NULL;
|
||||
|
||||
token_user = get_TOKEN_USER_current_user();
|
||||
if (!token_user)
|
||||
return false;
|
||||
|
||||
memset (&ea, 0, sizeof (EXPLICIT_ACCESS));
|
||||
ea.grfAccessPermissions = GENERIC_ALL; /* Access to all. */
|
||||
ea.grfAccessMode = SET_ACCESS; /* Set access and revoke everything else. */
|
||||
/* This is necessary for the Windows Explorer GUI to show the correct tick
|
||||
boxes in the "Security" tab. */
|
||||
ea.grfInheritance = OBJECT_INHERIT_ACE | CONTAINER_INHERIT_ACE;
|
||||
ea.Trustee.TrusteeForm = TRUSTEE_IS_SID;
|
||||
ea.Trustee.TrusteeType = TRUSTEE_IS_USER;
|
||||
ea.Trustee.ptstrName = (char*) token_user->User.Sid;
|
||||
|
||||
/* Create a new ACL that contains the new ACEs. */
|
||||
dwRes = SetEntriesInAcl(1, &ea, NULL, &pACL);
|
||||
if (dwRes != ERROR_SUCCESS)
|
||||
return false;
|
||||
|
||||
if (!InitializeSecurityDescriptor (&SD,
|
||||
SECURITY_DESCRIPTOR_REVISION))
|
||||
goto cleanup;
|
||||
|
||||
/* Add the ACL to the security descriptor. */
|
||||
if (!SetSecurityDescriptorDacl (&SD,
|
||||
TRUE, /* use pACL */
|
||||
pACL,
|
||||
FALSE)) /* not a default DACL */
|
||||
goto cleanup;
|
||||
|
||||
/* Initialize a security attributes structure. */
|
||||
sa.nLength = sizeof (SECURITY_ATTRIBUTES);
|
||||
sa.lpSecurityDescriptor = &SD;
|
||||
sa.bInheritHandle = FALSE;
|
||||
|
||||
/* Finally create the directory */
|
||||
if (!CreateDirectoryA (path, &sa))
|
||||
result = false;
|
||||
|
||||
cleanup:
|
||||
if (pACL)
|
||||
LocalFree (pACL);
|
||||
|
||||
if (token_user)
|
||||
delete[] (char*)token_user;
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
|
||||
char *
|
||||
win_mkdtemp (void)
|
||||
{
|
||||
char lpTempPathBuffer[MAX_PATH];
|
||||
|
||||
/* Gets the temp path env string (no guarantee it's a valid path). */
|
||||
DWORD dwRetVal = GetTempPath (MAX_PATH, lpTempPathBuffer);
|
||||
if (dwRetVal > MAX_PATH || (dwRetVal == 0))
|
||||
{
|
||||
print_last_error ();
|
||||
return NULL;
|
||||
}
|
||||
|
||||
/* Check that the directory actually exists. */
|
||||
DWORD dwAttrib = GetFileAttributes (lpTempPathBuffer);
|
||||
bool temp_path_exists = (dwAttrib != INVALID_FILE_ATTRIBUTES
|
||||
&& (dwAttrib & FILE_ATTRIBUTE_DIRECTORY));
|
||||
if (!temp_path_exists)
|
||||
{
|
||||
fprintf (stderr, "Path returned by GetTempPath does not exist: %s\n",
|
||||
lpTempPathBuffer);
|
||||
}
|
||||
|
||||
/* Make sure there is enough space in the buffer for the prefix and random
|
||||
number.*/
|
||||
int temp_path_buffer_len = dwRetVal;
|
||||
const int appended_len = strlen ("\\libgccjit-123456");
|
||||
if (temp_path_buffer_len + appended_len + 1 >= MAX_PATH)
|
||||
{
|
||||
fprintf (stderr, "Temporary file path too long for generation of random"
|
||||
" directories: %s", lpTempPathBuffer);
|
||||
}
|
||||
|
||||
/* This is all the space we have in the buffer to store the random number and
|
||||
prefix. */
|
||||
int extraspace = MAX_PATH - temp_path_buffer_len - 1;
|
||||
|
||||
int tries;
|
||||
const int max_tries = 1000;
|
||||
|
||||
for (tries = 0; tries < max_tries; ++tries)
|
||||
{
|
||||
/* Get a random number in [0; UINT_MAX]. */
|
||||
unsigned int rand_num;
|
||||
if (rand_s (&rand_num) != 0)
|
||||
{
|
||||
fprintf (stderr,
|
||||
"Failed to create a random number using rand_s(): %s\n",
|
||||
_strerror (NULL));
|
||||
return NULL;
|
||||
}
|
||||
|
||||
/* Create 6 digits random number. */
|
||||
rand_num = ((double)rand_num / ((double) UINT_MAX + 1 ) * 1000000);
|
||||
|
||||
/* Copy the prefix and random number to the buffer. */
|
||||
snprintf (&lpTempPathBuffer[temp_path_buffer_len], extraspace,
|
||||
"\\libgccjit-%06u", rand_num);
|
||||
|
||||
if (create_directory_for_current_user (lpTempPathBuffer))
|
||||
break; // success!
|
||||
|
||||
/* If we can't create the directory because we got unlucky and the
|
||||
directory already exists retry, otherwise fail. */
|
||||
if (GetLastError () != ERROR_ALREADY_EXISTS)
|
||||
{
|
||||
print_last_error ();
|
||||
return NULL;
|
||||
}
|
||||
}
|
||||
|
||||
if (tries == max_tries)
|
||||
{
|
||||
fprintf (stderr, "Failed to create a random directory in %s\n",
|
||||
lpTempPathBuffer);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
{
|
||||
int allocate_len = temp_path_buffer_len + appended_len + 1;
|
||||
char * result = XNEWVEC (char, allocate_len);
|
||||
strcpy (result, lpTempPathBuffer);
|
||||
return result;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
30
gcc/jit/jit-w32.h
Normal file
30
gcc/jit/jit-w32.h
Normal file
@ -0,0 +1,30 @@
|
||||
/* Functions used by the Windows port of libgccjit.
|
||||
Copyright (C) 2020 Free Software Foundation, Inc.
|
||||
Contributed by Nicolas Bertolo <nicolasbertolo@gmail.com>.
|
||||
|
||||
This file is part of GCC.
|
||||
|
||||
GCC is free software; you can redistribute it and/or modify it
|
||||
under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation; either version 3, or (at your option)
|
||||
any later version.
|
||||
|
||||
GCC is distributed in the hope that it will be useful, but
|
||||
WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with GCC; see the file COPYING3. If not see
|
||||
<http://www.gnu.org/licenses/>. */
|
||||
|
||||
#include "config.h"
|
||||
|
||||
#include <windows.h>
|
||||
|
||||
namespace gcc {
|
||||
namespace jit {
|
||||
extern void print_last_error (void);
|
||||
extern char * win_mkdtemp(void);
|
||||
}
|
||||
}
|
Loading…
Reference in New Issue
Block a user