clean up self-path and ELF handling for embedding executables

Clean up tangled and partly repeated code, and normalize ELF use for
boot files and embedded modules. Also, repair Unix-style Mac OS
builds.

With these changes, `raco exe` should always produce a well-formed
ELF, Mach-O, or PE excutable. The mode that just appends to the end of
the executable should happen only platforms that don't use one of
those three --- which are very rare and unlikely supported, anyway.

Closes #3831
This commit is contained in:
Matthew Flatt 2021-05-14 11:28:31 -06:00
parent e032be434e
commit 0f743800e4
25 changed files with 619 additions and 671 deletions

View File

@ -195,7 +195,9 @@ flags:
@nonterm{m} and from @nonterm{m} to @nonterm{p}. (On Mac OS,
@nonterm{n}, @nonterm{m}, and @nonterm{p} are relative to a
@tt{__PLTSCHEME} segment in the executable. On Windows,
they are relative to a resource of type 257 and ID 1.) The first range
they are relative to a resource of type 257 and ID 1. On Unix
using ELF, they are relative to the @tt{.rackprog} segment
in the executable.) The first range
is loaded in every new @tech{place}, and any modules declared
in that range are considered predefined in the sense of
@racket[module-predefined?]. This option is normally embedded
@ -203,7 +205,7 @@ flags:
@item{@FlagFirst{Y} @nonterm{file} @nonterm{n} @nonterm{m} @nonterm{p} :
Like @Flag{k} @nonterm{n} @nonterm{m} @nonterm{p}, but reading
from @nonterm{file} (without any adjustment on Mac OS or Windows
from @nonterm{file} (without any adjustment
for a segment or resource offset).}
@item{@FlagFirst{m} or @DFlagFirst{main} : Evaluates a call to

View File

@ -1511,9 +1511,7 @@
(let ([m (assq 'original-exe? aux)])
(or (not m)
(not (cdr m))))))
(define long-cmdline? (or (eq? (cross-system-type) 'windows)
(eq? (cross-system-type) 'macosx)
unix-starter?))
(define long-cmdline? #t)
(define relative? (let ([m (assq 'relative? aux)])
(and m (cdr m))))
(define collects-path-bytes (collects-path->bytes
@ -1762,15 +1760,18 @@
new-rsrcs))
(update-resources dest-exe pe new+dll-rsrcs)
(values 0 decl-len init-len (+ init-len cmdline-len))]
[(and (eq? (cross-system-type) 'macosx)
(not unix-starter?))
[(memq (cross-system-type 'os*) '(macosx darwin))
;; For Mach-O, we know how to add a proper segment
(remove-signature dest-exe) ; may be needed in 'darwin mode
(define s (open-output-bytes))
(define decl-len (write-module s))
(let* ([s (get-output-bytes s)]
[cl (let ([o (open-output-bytes)])
;; position is relative to __PLTSCHEME:
(write-cmdline (make-full-cmdline 0 decl-len (bytes-length s)) o)
(let ([cmdline (make-full-cmdline 0 decl-len (bytes-length s))])
(cond
[unix-starter? (display (make-starter-cmdline cmdline) o)]
[else (write-cmdline cmdline o)]))
(get-output-bytes o))])
(let ([start (add-plt-segment
dest-exe
@ -1783,28 +1784,25 @@
(+ start (bytes-length s))
(+ start (bytes-length s) (bytes-length cl))))))]
[else
;; Unix starter: Maybe ELF, in which case we
;; Unix starter or direct embedding: Maybe ELF, in which case we
;; can add a proper section
(define-values (s e dl p)
(if unix-starter?
(add-racket-section
orig-exe
dest-exe
(if launcher? #".rackcmdl" #".rackprog")
#".rackprog"
(lambda (start)
(let ([s (open-output-bytes)])
(define decl-len (write-module s))
(let ([p (file-position s)])
(display (make-starter-cmdline
(make-full-cmdline start
(+ start decl-len)
(+ start p)))
s)
(values (get-output-bytes s) decl-len p)))))
(values #f #f #f #f)))
(let ([cmdline (make-full-cmdline 0 decl-len p)])
(cond
[unix-starter? (display (make-starter-cmdline cmdline) s)]
[else (write-cmdline cmdline s)]))
(values (get-output-bytes s) decl-len p))))))
(if (and s e)
;; ELF succeeded:
(values s (+ s dl) (+ s p) e)
;; ELF succeeded, so make values relative to start:
(values 0 dl p (- e s))
;; Otherwise, just add to the end of the file:
(let ([start (file-size dest-exe)])
(define decl-end
@ -1936,7 +1934,7 @@
(assq 'subsystem aux))])
(when m
(set-subsystem dest-exe (cdr m)))))]))))
(when (eq? (cross-system-type) 'macosx)
(when (memq (cross-system-type 'os*) '(macosx darwin))
(add-ad-hoc-signature dest-exe))
(done-writable dest-exe old-perms))))))

View File

@ -7,9 +7,10 @@
call-with-autorelease))
;; Make sure Foundation is loaded:
(when (eq? 'macosx (system-type))
(case (system-type 'os*)
[(macosx darwin)
(void (ffi-lib "/System/Library/Frameworks/Foundation.framework/Foundation"
#:fail (lambda () #f))))
#:fail (lambda () #f)))])
(import-class NSAutoreleasePool)

View File

@ -17,16 +17,19 @@
osx-old-openssl?)
(define (osx-old-openssl?)
(and (eq? 'macosx (system-type))
(and (or (eq? 'macosx (system-type))
(eq? 'darwin (system-type 'os*)))
(not (eq? 'ppc (system-type 'arch))) ; Mac OS 10.5 is too old for this to work?
(or (not ssl-available?)
(not (memq 'tls12 (supported-client-protocols))))))
(define cf-lib
(and (eq? 'macosx (system-type))
(and (or (eq? 'macosx (system-type))
(eq? 'darwin (system-type 'os*)))
(ffi-lib "/System/Library/Frameworks/CoreFoundation.framework/CoreFoundation")))
(define net-lib
(and (eq? 'macosx (system-type))
(and (or (eq? 'macosx (system-type))
(eq? 'darwin (system-type 'os*)))
(ffi-lib
"/System/Library/Frameworks/CFNetwork.framework/CFNetwork"
#:fail (lambda ()

View File

@ -479,12 +479,12 @@ TO DO:
(define ssl-default-verify-sources
(make-parameter
(case (system-type)
(case (system-type 'os*)
[(windows)
;; On Windows, x509-root-sources produces paths like "/usr/local/ssl/certs", which
;; aren't useful. So just skip them.
'((win32-store "ROOT"))]
[(macosx)
[(macosx darwin)
'((macosx-keychain "/System/Library/Keychains/SystemRootCertificates.keychain"))]
[else
(x509-root-sources)])))

View File

@ -16,8 +16,8 @@
;; security export -k /System/Library/Keychains/... -t certs -f pemseq -o foo.pem
(define libcf
(case (system-type)
[(macosx) (ffi-lib "/System/Library/Frameworks/CoreFoundation.framework/CoreFoundation")]
(case (system-type 'os*)
[(macosx darwin) (ffi-lib "/System/Library/Frameworks/CoreFoundation.framework/CoreFoundation")]
[else #f]))
(define-ffi-definer define-cf libcf
@ -47,8 +47,8 @@
;; ----
(define libsec
(case (system-type)
[(macosx) (ffi-lib "/System/Library/Frameworks/Security.framework/Security")]
(case (system-type 'os*)
[(macosx darwin) (ffi-lib "/System/Library/Frameworks/Security.framework/Security")]
[else #f]))
(define-ffi-definer define-sec libsec
#:default-make-fail make-not-available)

View File

@ -304,7 +304,7 @@ DEF_C_DIRS = $(DEF_COLLECTS_DIR) $(DEF_CONFIG_DIR)
MAIN_HEADER_DEPS = $(srcdir)/include/scheme.h $(srcdir)/include/schthread.h $(srcdir)/sconfig.h \
$(srcdir)/src/stypes.h $(srcdir)/cmdline.inc $(srcdir)/../start/parse_cmdl.inc \
$(srcdir)/../start/cmdl_to_argv.inc \
$(srcdir)/../start/config.inc $(srcdir)/../start/delayed.inc \
$(srcdir)/../start/config.inc $(srcdir)/../start/self_exe.inc $(srcdir)/../start/delayed.inc \
$(srcdir)/../start/embedded_dll.inc
MAIN_INCLUDES = -I$(builddir) -I$(srcdir)/include -I$(srcdir)/../version
@ -499,6 +499,7 @@ unix-install-cgc:
cd ..; $(STRIP_DEBUG) "$(DESTDIR)$(bindir)/racket@CGC_INSTALLED@"
cd ..; cp bc/mzdyn.o "$(DESTDIR)$(libpltdir)/mzdyn.o"
@RUN_RACKET_CGC@ $(SETUP_BOOT_COLLECTS_PATH) "$(DESTDIR)$(bindir)/racket@CGC_INSTALLED@@EXE_SUFFIX@" $(DESTDIR)@COLLECTS_PATH@ $(DESTDIR)@CONFIG_PATH@
$(RESTORE_SIGNATURE) "$(DESTDIR)$(bindir)/racket@CGC_INSTALLED@"
unix-install-libs-cgc:
cd ..; $(ICP_LIB) bc/libmzgc.@LIBSFX@ "$(DESTDIR)$(libdir)/libmzgc.@LIBSFX@"
@ -520,6 +521,7 @@ unix-install-3m:
$(MAKE) unix-@INSTALL_LIBS_ENABLE@-libs-3m
cd ..; $(ICP) bc/mzdyn3m.o "$(DESTDIR)$(libpltdir)/mzdyn3m.o"
@RUN_RACKET_MMM@ $(SETUP_BOOT_COLLECTS_PATH) "$(DESTDIR)$(bindir)/racket@MMM_INSTALLED@@EXE_SUFFIX@" $(DESTDIR)@COLLECTS_PATH@ $(DESTDIR)@CONFIG_PATH@
$(RESTORE_SIGNATURE) "$(DESTDIR)$(bindir)/racket@MMM_INSTALLED@"
unix-install-libs-3m:
cd ..; $(ICP_LIB) bc/libracket3m.@LIBSFX@ "$(DESTDIR)$(libdir)/libracket3m.@LIBSFX@"
@ -604,6 +606,7 @@ osx-install-cgc:
$(MAKE) unix-install-cgc
mkdir -p $(DESTDIR)$(MZFWDIR)/Versions/$(FWVERSION)
cp $(MZFW) $(DESTDIR)$(MZFWDIR)/Versions/$(FWVERSION)/
$(STRIP_SIGNATURE) $(DESTDIR)"$(bindir)/racket@CGC_INSTALLED@"
/usr/bin/install_name_tool -change "@executable_path/Racket.framework/Versions/$(FWVERSION)/Racket" "@FRAMEWORK_PREFIX@Racket.framework/Versions/$(FWVERSION)/Racket" $(DESTDIR)"$(bindir)/racket@CGC_INSTALLED@"
$(RESTORE_SIGNATURE) $(DESTDIR)"$(bindir)/racket@CGC_INSTALLED@"
@ -615,6 +618,7 @@ osx-install-3m:
$(MAKE) unix-install-3m
mkdir -p $(DESTDIR)"$(MZFWDIR)/Versions/$(FWVERSION)_3m"
cp $(MZFWMMM) $(DESTDIR)$(MZFWDIR)/Versions/$(FWVERSION)_3m/
$(STRIP_SIGNATURE) $(DESTDIR)"$(bindir)/racket@MMM_INSTALLED@"
/usr/bin/install_name_tool -change "@executable_path/Racket.framework/Versions/$(FWVERSION)_3m/Racket" "@FRAMEWORK_PREFIX@Racket.framework/Versions/$(FWVERSION)_3m/Racket" $(DESTDIR)"$(bindir)/racket@MMM_INSTALLED@"
$(RESTORE_SIGNATURE) $(DESTDIR)"$(bindir)/racket@MMM_INSTALLED@"

View File

@ -42,7 +42,6 @@ static int is_number_arg(const char *s)
return 1;
}
#if defined(OS_X) || defined(DOS_FILE_SYSTEM)
char *add_to_str(const char *addr, long amt)
{
long addr_v;
@ -51,23 +50,19 @@ char *add_to_str(const char *addr, long amt)
sprintf(buf, "%ld", addr_v);
return strdup(buf);
}
#endif
static char *make_embedded_load(const char *file, const char *start, const char *end)
static char *make_embedded_load(const self_exe_t self_exe, const char *file, const char *start, const char *end)
{
char *s;
int slen, elen, flen;
#if defined(OS_X) || defined(DOS_FILE_SYSTEM)
if (file == NULL) {
long fileoff;
fileoff = get_segment_offset();
fileoff = get_segment_offset(self_exe);
start = add_to_str(start, fileoff);
end = add_to_str(end, fileoff);
file = SELF_PATH_TO_BYTES(self_exe);
}
#endif
if (!file) file = "";
slen = strlen(start);
elen = strlen(end);
@ -730,6 +725,7 @@ static int run_from_cmd_line(int argc, char *_argv[],
Scheme_Object *syslog_level = NULL, *stderr_level = NULL, *stdout_level = NULL;
FinishArgs *fa;
FinishArgsAtoms *fa_a;
self_exe_t self_exe;
scheme_set_default_locale();
@ -741,7 +737,9 @@ static int run_from_cmd_line(int argc, char *_argv[],
console_printf = scheme_get_console_printf();
#endif
extract_built_in_arguments(&prog, &sprog, &argc, &argv);
self_exe = get_self_path(prog);
extract_built_in_arguments(self_exe, &prog, &sprog, &argc, &argv);
#ifndef DONT_PARSE_COMMAND_LINE
evals_and_loads = (char **)malloc(sizeof(char *) * argc);
@ -1024,12 +1022,12 @@ static int run_from_cmd_line(int argc, char *_argv[],
}
argv++;
--argc;
se = make_embedded_load(embedding_file, argv[0], argv[1]);
se = make_embedded_load(self_exe, embedding_file, argv[0], argv[1]);
evals_and_loads[num_enl] = se;
argv++;
--argc;
eval_kind[num_enl++] = mzcmd_EMBEDDED_REG;
se = make_embedded_load(embedding_file, argv[0], argv[1]);
se = make_embedded_load(self_exe, embedding_file, argv[0], argv[1]);
evals_and_loads[num_enl] = se;
argv++;
--argc;

View File

@ -60,7 +60,7 @@ MZDYNDEP = ../mzdyn.o $(srcdir)/../include/ext.exp $(srcdir)/../include/racket.e
dynexmpl.o: $(srcdir)/dynexmpl.c $(HEADERS)
$(PLAIN_CC) $(ALL_CFLAGS) -c $(srcdir)/dynexmpl.c -o dynexmpl.o
../starter@NOT_MINGW@@EXE_SUFFIX@: $(srcdir)/../../start/ustart.c $(srcdir)/../../start/unix_self.inc
../starter@NOT_MINGW@@EXE_SUFFIX@: $(srcdir)/../../start/ustart.c $(srcdir)/../../start/self_exe.inc
$(PLAIN_CC) $(ALL_CFLAGS) -o ../starter@EXE_SUFFIX@ $(srcdir)/../../start/ustart.c
PARSE_CMDL = $(srcdir)/../../start/parse_cmdl.inc

View File

@ -57,6 +57,9 @@ LDFLAGS = @LDFLAGS@
ARLIBFLAGS = $(LDFLAGS) $(LDLIBS)
###########################
STRIP_SIGNATURE = @STRIP_SIGNATURE@
RESTORE_SIGNATURE = @RESTORE_SIGNATURE@ "${srcdir}/../../mac/entitlements.plist"
GRACKETLINKER = @MZLINKER@
LIBRKTIO = ../rktio/librktio.@LTA@
@ -224,8 +227,10 @@ GRACKET_NAME@MINGW@ = GRacket
install-wx_xt-cgc:
$(MAKE) @MRLIBINSTALL@-cgc-wx_xt
cd ..; $(ICP) gracket/gracket@CGC@@EXE_SUFFIX@ "$(DESTDIR)$(libpltdir)/$(GRACKET_NAME)@CGC_INSTALLED@@EXE_SUFFIX@"
$(STRIP_SIGNATURE) "$(DESTDIR)$(libpltdir)/$(GRACKET_NAME)@CGC_INSTALLED@@EXE_SUFFIX@"
cd ..; @STRIP_DEBUG@ "$(DESTDIR)$(libpltdir)/$(GRACKET_NAME)@CGC_INSTALLED@@EXE_SUFFIX@"
@RUN_RACKET_CGC@ $(SETUP_BOOT_COLLECTS_PATH) @DIRCVTPRE@"$(DESTDIR)$(libpltdir)/$(GRACKET_NAME)@CGC_INSTALLED@@EXE_SUFFIX@"@DIRCVTPOST@ @GUI_COLLECTS_PATH@ @GUI_CONFIG_PATH@
$(RESTORE_SIGNATURE) "$(DESTDIR)$(libpltdir)/$(GRACKET_NAME)@CGC_INSTALLED@@EXE_SUFFIX@"
install-wx_xt-cgc-final:
$(NOOP)
@ -239,8 +244,10 @@ install-lib-3m-wx_xt:
install-wx_xt-3m:
$(MAKE) @MRLIBINSTALL@-3m-wx_xt
cd ..; $(ICP) gracket/gracket@MMM@@EXE_SUFFIX@ "$(DESTDIR)$(libpltdir)/$(GRACKET_NAME)@MMM_INSTALLED@@EXE_SUFFIX@"
$(STRIP_SIGNATURE) "$(DESTDIR)$(libpltdir)/$(GRACKET_NAME)@MMM_INSTALLED@@EXE_SUFFIX@"
cd ..; @STRIP_DEBUG@ "$(DESTDIR)$(libpltdir)/$(GRACKET_NAME)@MMM_INSTALLED@@EXE_SUFFIX@"
@RUN_RACKET_MMM@ $(SETUP_BOOT_COLLECTS_PATH) @DIRCVTPRE@"$(DESTDIR)$(libpltdir)/$(GRACKET_NAME)@MMM_INSTALLED@@EXE_SUFFIX@"@DIRCVTPOST@ @GUI_COLLECTS_PATH@ @GUI_CONFIG_PATH@
$(RESTORE_SIGNATURE) "$(DESTDIR)$(libpltdir)/$(GRACKET_NAME)@MMM_INSTALLED@@EXE_SUFFIX@"
install-wx_xt-3m-final:
$(NOOP)

View File

@ -32,7 +32,7 @@ EXTRA_COMPILE_DEPS =
COMPILE_FILE = $(SCHEME) --script compile-file.ss $(UNSAFE_COMP) $(COMPRESS_COMP) $(DEBUG_COMP) $(CROSS_COMP) --dest "$(BUILDDIR)"
COMPILE_FILE_DEPS = compile-file.ss include.ss place-register.ss $(EXTRA_COMPILE_DEPS)
RACKET_SETUP_ARGS = false ../../bin/racket ../../bin/racket ../collects ../etc 0 false false 0 ""
RACKET_SETUP_ARGS = false ../../bin/racket ../../bin/racket ../collects ../etc "" 0 false false 0 ""
PRIMITIVES_TABLES = primitive/kernel.ss primitive/unsafe.ss primitive/flfxnum.ss \
primitive/paramz.ss primitive/extfl.ss primitive/network.ss \

View File

@ -212,12 +212,12 @@ racket.boot: racket.so
EMBED_DEPS = $(srcdir)/embed-boot.rkt
racketcs@NOT_OSX@@NOT_MINGW@: raw_racketcs petite-v.boot scheme-v.boot racket-v.boot $(EMBED_DEPS)
$(BOOTSTRAP_RACKET) $(srcdir)/embed-boot.rkt @ELF_COMP@ --target $(TARGET_MACH) @BOOT_COMPRESS_COMP@ raw_racketcs racketcs petite-v.boot scheme-v.boot racket-v.boot
$(BOOTSTRAP_RACKET) $(srcdir)/embed-boot.rkt --target $(TARGET_MACH) @BOOT_COMPRESS_COMP@ raw_racketcs racketcs petite-v.boot scheme-v.boot racket-v.boot
@POST_LINKER@ racketcs
$(RESTORE_SIGNATURE) racketcs
gracketcs@NOT_OSX@@NOT_MINGW@: raw_gracketcs petite-v.boot scheme-v.boot racket-v.boot $(EMBED_DEPS)
$(BOOTSTRAP_RACKET) $(srcdir)/embed-boot.rkt @ELF_COMP@ --target $(TARGET_MACH) @BOOT_COMPRESS_COMP@ raw_gracketcs gracketcs petite-v.boot scheme-v.boot racket-v.boot
$(BOOTSTRAP_RACKET) $(srcdir)/embed-boot.rkt --target $(TARGET_MACH) @BOOT_COMPRESS_COMP@ raw_gracketcs gracketcs petite-v.boot scheme-v.boot racket-v.boot
@POST_LINKER@ gracketcs
$(RESTORE_SIGNATURE) gracketcs
@ -433,7 +433,7 @@ DEF_C_DIRS = $(DEF_COLLECTS_DIR) $(DEF_CONFIG_DIR)
MAIN_DEPS = $(srcdir)/main.c $(srcdir)/boot.h cs_config.h \
$(srcdir)/../../start/config.inc \
$(srcdir)/../../start/unix_self.inc
$(srcdir)/../../start/self_exe.inc
main.o: $(MAIN_DEPS)
$(CC) $(CFLAGS) $(DEF_C_DIRS) -c -o main.o $(srcdir)/main.c
@ -444,7 +444,7 @@ grmain.o: $(srcdir)/grmain.c $(MAIN_DEPS) $(srcdir)/../../start/gui_filter.inc
boot.o: $(srcdir)/boot.c $(srcdir)/../../rktio/rktio.inc $(srcdir)/boot.h
$(CC) $(CFLAGS) -c -o boot.o $(srcdir)/boot.c
starter@NOT_MINGW@: $(srcdir)/../../start/ustart.c $(srcdir)/../../start/unix_self.inc
starter@NOT_MINGW@: $(srcdir)/../../start/ustart.c $(srcdir)/../../start/self_exe.inc
$(CC) $(CFLAGS) -o starter $(srcdir)/../../start/ustart.c

View File

@ -192,9 +192,10 @@ void racket_boot(racket_boot_arguments_t *ba)
l = Scons(Sbytevector(ba->cs_compiled_subdir ? "true" : "false"), l);
sprintf(segment_offset_s, "%ld", ba->segment_offset);
l = Scons(Sbytevector(segment_offset_s), l);
l = Scons(Sbytevector(ba->k_file ? (char *)ba->k_file : (char *)ba->exec_file), l);
l = Scons(Sbytevector(ba->config_dir ? (char *)ba->config_dir : "etc"), l);
l = Scons(parse_coldirs(ba->collects_dir ? (char *)ba->collects_dir : ""), l);
l = Scons(Sbytevector(ba->run_file ? (char *)ba->run_file : (char *)ba->exec_file ), l);
l = Scons(Sbytevector(ba->run_file ? (char *)ba->run_file : (char *)ba->exec_file), l);
l = Scons(Sbytevector((char *)ba->exec_file), l);
l = Scons(Sbytevector(ba->exit_after ? "false" : "true"), l);

View File

@ -30,6 +30,7 @@ typedef struct racket_boot_arguments_t {
const char *collects_dir; /* can be NULL or "" to disable collection path */
const char *config_dir; /* use NULL or "etc" if you don't care */
/* wchar_t * */void *dll_dir; /* can be NULL for default */
const char *k_file; /* for -k; can be NULL for the same as `exec_file` */
/* How to initialize `use-compiled-file-paths`: */
int cs_compiled_subdir; /* true => subdirectory of "compiled" */

View File

@ -639,7 +639,6 @@ FRAMEWORK_INSTALL_DIR
SCHEME_CROSS_CONFIG_ARGS
SCHEME_CONFIG_ARGS
MAKE_BUILD_SCHEME
ELF_COMP
BOOT_COMPRESS_COMP
COMPRESS_COMP
CONFIGURE_RACKET_SO_COMPILE
@ -3222,7 +3221,6 @@ NOT_MINGW=""
CONFIGURE_RACKET_SO_COMPILE=""
COMPRESS_COMP=""
BOOT_COMPRESS_COMP=""
ELF_COMP=""
POST_LINKER="echo"
FRAMEWORK_INSTALL_DIR='$(libpltdir)'
@ -4336,7 +4334,6 @@ case "$host_os" in
LIBS="$LIBS -lsocket -lnsl -lintl"
use_flag_pthread="no"
use_flag_posix_pthread="yes"
enable_strip=no
;;
aix*)
;;
@ -4347,8 +4344,6 @@ case "$host_os" in
LIBS="${LIBS} -lm -lpthread"
LINK_DYNAMIC="-rdynamic"
add_iconv_lib="-liconv"
CPPFLAGS="${CPPFLAGS} -DELF_FIND_BOOT_SECTION"
ELF_COMP="--expect-elf"
;;
openbsd*)
MACH_OS=ob
@ -4358,8 +4353,6 @@ case "$host_os" in
LINK_DYNAMIC="-Wl,--export-dynamic"
add_iconv_lib="-liconv"
LDFLAGS="${LDFLAGS} -Wl,-zwxneeded"
CPPFLAGS="${CPPFLAGS} -DELF_FIND_BOOT_SECTION"
ELF_COMP="--expect-elf"
;;
bitrig*)
LINK_DYNAMIC="-Wl,--export-dynamic"
@ -4372,8 +4365,6 @@ case "$host_os" in
LIBS="${LIBS} -lm -lpthread"
LINK_DYNAMIC="-rdynamic"
add_iconv_lib="/usr/lib/i18n/libiconv_std.a"
CPPFLAGS="${CPPFLAGS} -DELF_FIND_BOOT_SECTION"
ELF_COMP="--expect-elf"
POST_LINKER="paxctl +m"
;;
irix*)
@ -4387,9 +4378,7 @@ case "$host_os" in
LIBS="${LIBS} -lrt"
;;
esac
CPPFLAGS="${CPPFLAGS} -DELF_FIND_BOOT_SECTION"
LINK_DYNAMIC="-rdynamic"
ELF_COMP="--expect-elf"
;;
osf1*)
;;
@ -5793,7 +5782,6 @@ SCHEME_CROSS_CONFIG_ARGS="--machine=${TARGET_MACH} --disable-x11 ${cs_auto_flags
makefiles="Makefile"

View File

@ -140,7 +140,6 @@ NOT_MINGW=""
CONFIGURE_RACKET_SO_COMPILE=""
COMPRESS_COMP=""
BOOT_COMPRESS_COMP=""
ELF_COMP=""
POST_LINKER="echo"
FRAMEWORK_INSTALL_DIR='$(libpltdir)'
@ -218,7 +217,6 @@ case "$host_os" in
LIBS="$LIBS -lsocket -lnsl -lintl"
use_flag_pthread="no"
use_flag_posix_pthread="yes"
enable_strip=no
;;
aix*)
;;
@ -229,8 +227,6 @@ case "$host_os" in
LIBS="${LIBS} -lm -lpthread"
LINK_DYNAMIC="-rdynamic"
add_iconv_lib="-liconv"
CPPFLAGS="${CPPFLAGS} -DELF_FIND_BOOT_SECTION"
ELF_COMP="--expect-elf"
;;
openbsd*)
MACH_OS=ob
@ -240,8 +236,6 @@ case "$host_os" in
LINK_DYNAMIC="-Wl,--export-dynamic"
add_iconv_lib="-liconv"
LDFLAGS="${LDFLAGS} -Wl,-zwxneeded"
CPPFLAGS="${CPPFLAGS} -DELF_FIND_BOOT_SECTION"
ELF_COMP="--expect-elf"
;;
bitrig*)
LINK_DYNAMIC="-Wl,--export-dynamic"
@ -254,8 +248,6 @@ case "$host_os" in
LIBS="${LIBS} -lm -lpthread"
LINK_DYNAMIC="-rdynamic"
add_iconv_lib="/usr/lib/i18n/libiconv_std.a"
CPPFLAGS="${CPPFLAGS} -DELF_FIND_BOOT_SECTION"
ELF_COMP="--expect-elf"
POST_LINKER="paxctl +m"
;;
irix*)
@ -269,9 +261,7 @@ case "$host_os" in
LIBS="${LIBS} -lrt"
;;
esac
CPPFLAGS="${CPPFLAGS} -DELF_FIND_BOOT_SECTION"
LINK_DYNAMIC="-rdynamic"
ELF_COMP="--expect-elf"
;;
osf1*)
;;
@ -819,7 +809,6 @@ AC_SUBST(LZ4_LIB_UNPACK)
AC_SUBST(CONFIGURE_RACKET_SO_COMPILE)
AC_SUBST(COMPRESS_COMP)
AC_SUBST(BOOT_COMPRESS_COMP)
AC_SUBST(ELF_COMP)
AC_SUBST(MAKE_BUILD_SCHEME)
AC_SUBST(SCHEME_CONFIG_ARGS)
AC_SUBST(SCHEME_CROSS_CONFIG_ARGS)

View File

@ -6,7 +6,6 @@
compiler/private/elf
"adjust-compress.rkt")
(define expect-elf? #f)
(define alt-dests '())
(define target #f)
@ -14,8 +13,6 @@
#:once-each
[("--compress") "Leave compiled code files as compressed"
(enable-compress!)]
[("--expect-elf") "Record offset from ELF section"
(set! expect-elf? #t)]
[("--target") machine "Select target machine"
(set! target machine)]
#:multi
@ -57,7 +54,10 @@
"x86_64-darwin" "i386-darwin" "aarch64-darwin"
"x86_64-macosx" "i386-macosx" "aarch64-macosx")
;; Mach-O
(copy-file use-src-file dest-file #t)
(when (file-exists? dest-file)
;; explicit delete to avoid signature unhappiness
(delete-file dest-file))
(copy-file use-src-file dest-file)
(remove-signature dest-file)
(add-plt-segment dest-file data #:name #"__RKTBOOT")
;; Find segment at run time:
@ -86,12 +86,8 @@
[start-pos
;; Success as ELF
(file-or-directory-permissions dest-file (file-or-directory-permissions use-src-file 'bits))
(cond
[expect-elf?
;; Find ".rackboot" at run time:
0]
[else
start-pos])]
[else
;; Not ELF; just append to the end
(copy-file use-src-file dest-file #t)
@ -102,8 +98,6 @@
(lambda (o)
(file-position o pos)
(write-bytes data o)))
(when expect-elf?
(error 'embed-boot "expected ELF"))
pos])]))
(define (write-offsets dest-file)

View File

@ -57,34 +57,11 @@ PRESERVE_IN_EXECUTABLE
char *boot_file_data = "BooT FilE OffsetS:\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0";
static int boot_file_offset = 18;
#include "../../start/unix_self.inc"
#ifdef OS_X
# include <mach-o/dyld.h>
static long find_rktboot_section(char *me)
{
const struct mach_header *mh;
const struct load_command *lc;
int i;
mh = _dyld_get_image_header(0);
lc = (void *)((char *)mh + ((mh->magic == 0xfeedfacf) ? sizeof(struct mach_header_64) : sizeof(struct mach_header)));
for (i = 0; i < mh->ncmds; i++) {
if (lc->cmd == LC_SEGMENT) {
const struct segment_command *sc = (struct segment_command *)lc;
if (!strcmp(sc->segname, "__RKTBOOT"))
return sc->fileoff;
} else if (lc->cmd == LC_SEGMENT_64) {
const struct segment_command_64 *sc = (struct segment_command_64 *)lc;
if (!strcmp(sc->segname, "__RKTBOOT"))
return sc->fileoff;
}
lc = (void *)((char *)lc + lc->cmdsize);
}
return 0;
return find_mach_o_segment("__RKTBOOT", NULL);
}
#endif
@ -127,69 +104,18 @@ static char *path_append(const char *p1, char *p2) {
#endif
#ifdef ELF_FIND_BOOT_SECTION
# include <elf.h>
# include <fcntl.h>
static long find_boot_section(char *me)
#if !defined(WIN32) && !defined(OS_X)
static long find_boot_section(const char *me)
{
int fd, i;
#if SIZEOF_VOID_P == 4
Elf32_Ehdr e;
Elf32_Shdr s;
#else
Elf64_Ehdr e;
Elf64_Shdr s;
#endif
char *strs;
int start = 0, end = 0;
fd = open(me, O_RDONLY, 0);
if (fd == -1) return 0;
find_elf_section_offset(me, ".rackboot", &start, &end);
if (read(fd, &e, sizeof(e)) == sizeof(e)) {
lseek(fd, e.e_shoff + (e.e_shstrndx * e.e_shentsize), SEEK_SET);
if (read(fd, &s, sizeof(s)) != sizeof(s)) {
close(fd);
return 0;
}
strs = (char *)malloc(s.sh_size);
lseek(fd, s.sh_offset, SEEK_SET);
if (read(fd, strs, s.sh_size) != s.sh_size) {
close(fd);
return 0;
}
for (i = 0; i < e.e_shnum; i++) {
lseek(fd, e.e_shoff + (i * e.e_shentsize), SEEK_SET);
if (read(fd, &s, sizeof(s)) != sizeof(s)) {
close(fd);
return 0;
}
if (!strcmp(strs + s.sh_name, ".rackboot")) {
close(fd);
return s.sh_offset;
}
}
}
close(fd);
return 0;
return start;
}
#endif
#ifdef WIN32
static char *string_to_utf8(wchar_t *p)
{
char *r;
int len;
len = WideCharToMultiByte(CP_UTF8, 0, p, -1, NULL, 0, NULL, NULL);
r = malloc(len);
len = WideCharToMultiByte(CP_UTF8, 0, p, -1, r, len, NULL, NULL);
return r;
}
static int scheme_utf8_encode(unsigned int *path, int zero_offset, int len,
char *dest, int offset, int get_utf16)
@ -202,126 +128,6 @@ static int scheme_utf8_encode(unsigned int *path, int zero_offset, int len,
}
# include "../start/cmdl_to_argv.inc"
# undef USE_GENERIC_GET_SELF_PATH
#endif
#ifdef USE_GENERIC_GET_SELF_PATH
/* Get executable path via argv[0] and the `PATH` environment variable */
static int has_slash(char *s)
{
while (*s) {
if (s[0] == '/')
return 1;
s++;
}
return 0;
}
static char *do_path_append(char *s1, int l1, char *s2)
{
int l2;
char *s;
l2 = strlen(s2);
s = (char *)malloc(l1 + l2 + 2);
memcpy(s, s1, l1);
if (s[l1 - 1] != '/') {
s[l1++] = '/';
}
memcpy(s + l1, s2, l2);
s[l1 + l2] = 0;
return s;
}
static char *path_append(char *s1, char *s2)
{
return do_path_append(s1, strlen(s1), s2);
}
static char *copy_string(char *s1)
{
int l1;
char *s;
if (!s1) return NULL;
l1 = strlen(s1);
s = (char *)malloc(l1 + 1);
memcpy(s, s1, l1 + 1);
return s;
}
static int executable_exists(char *path)
{
return (access(path, X_OK) == 0);
}
static char *get_self_path(char *exec_file)
{
if (exec_file[0] == '/') {
/* Absolute path */
return exec_file;
} else if (has_slash(exec_file)) {
/* Relative path with a directory: */
char *buf;
long buflen = 4096;
buf = (char *)malloc(buflen);
return path_append(getcwd(buf, buflen), exec_file);
} else {
/* We have to find the executable by searching PATH: */
char *path = copy_string(getenv("PATH")), *p, *m;
int more;
if (!path) {
path = "";
}
while (1) {
/* Try each element of path: */
for (p = path; *p && (*p != ':'); p++) { }
if (*p) {
*p = 0;
more = 1;
} else
more = 0;
if (!*path)
break;
m = path_append(path, exec_file);
if (executable_exists(m)) {
if (m[0] != '/')
m = path_append(getcwd(NULL, 0), m);
return m;
}
free(m);
if (more)
path = p + 1;
else
break;
}
return exec_file;
}
}
#endif
#ifdef NO_GET_SEGMENT_OFFSET
static long get_segment_offset()
{
return 0;
}
#endif
#ifndef WIN32
@ -355,6 +161,7 @@ static int bytes_main(int argc, char **argv,
int wm_is_gracket_or_x11_arg_count, char *gracket_guid_or_x11_args)
{
char *boot_exe;
self_exe_t self_exe;
char *exec_file = argv[0], *run_file = NULL;
char *boot1_path, *boot2_path, *boot3_path;
int boot1_offset, boot2_offset, boot3_offset, boot_end_offset;
@ -374,12 +181,12 @@ static int bytes_main(int argc, char **argv,
argv++;
}
extract_built_in_arguments(&exec_file, &run_file, &argc, &argv);
self_exe = get_self_path(exec_file);
extract_built_in_arguments(self_exe, &exec_file, &run_file, &argc, &argv);
if (!run_file)
run_file = exec_file;
segment_offset = get_segment_offset();
memcpy(&boot1_offset, boot_file_data + boot_file_offset, sizeof(boot1_offset));
memcpy(&boot2_offset, boot_file_data + boot_file_offset + 4, sizeof(boot2_offset));
memcpy(&boot3_offset, boot_file_data + boot_file_offset + 8, sizeof(boot3_offset));
@ -393,7 +200,7 @@ static int bytes_main(int argc, char **argv,
dll = embedded_dll_open("libracketcsxxxxxxx.dll", 1);
boot_rsrc_offset = in_memory_get_offset("libracketcsxxxxxxx.dll");
racket_boot_p = (racket_boot_t)scheme_dll_find_object(dll, "racket_boot");
dll_path = get_self_executable_path();
dll_path = self_exe;
} else {
HMODULE dll;
dll_path = load_delayed_dll_x(NULL, "libracketcsxxxxxxx.dll", &dll);
@ -402,18 +209,19 @@ static int bytes_main(int argc, char **argv,
boot_exe = string_to_utf8(dll_path);
# define racket_boot racket_boot_p
#else
boot_exe = get_self_path(exec_file);
boot_exe = self_exe;
#endif
#ifdef ELF_FIND_BOOT_SECTION
boot_offset = find_boot_section(boot_exe);
#elif defined(OS_X)
/* segment_offset is for embedded bytecode (not boot files) */
segment_offset = get_segment_offset(self_exe);
#if defined(OS_X)
boot_offset = find_rktboot_section(boot_exe);
if (!boot_offset) boot_images_in_exe = 0;
#elif WIN32
boot_offset = find_resource_offset(dll_path, 259, boot_rsrc_offset);
#else
boot_offset = 0;
boot_offset = find_boot_section(boot_exe);
#endif
boot1_offset += boot_offset;
@ -470,6 +278,7 @@ static int bytes_main(int argc, char **argv,
ba.collects_dir = extract_coldir();
ba.config_dir = extract_configdir();
ba.dll_dir = extract_dlldir();
ba.k_file = SELF_PATH_TO_BYTES(self_exe);
ba.cs_compiled_subdir = CS_COMPILED_SUBDIR;

View File

@ -86,13 +86,13 @@
(#%newline (#%current-error-port))
(exit 1))
(define builtin-argc 10)
(define builtin-argc 11)
(seq
(unless (>= (length the-command-line-arguments) builtin-argc)
(startup-error (string-append
"expected `embedded-interactive-mode?`,"
" `exec-file`, `run-file`, `collects`, and `etc` paths"
" plus `segment-offset`, `cs-compiled-subdir?`, `is-gui?`,"
" plus `k-file`, `segment-offset`, `cs-compiled-subdir?`, `is-gui?`,"
" `wm-is-gracket-or-x11-arg-count`, and `gracket-guid-or-x11-args`"
" to start")))
(set-exec-file! (->path (list-ref the-command-line-arguments/maybe-bytes 1)))
@ -110,11 +110,14 @@
(map ->path (cdr s))))])))
(define init-config-dir (->path (or (getenv-bytes "PLTCONFIGDIR")
(list-ref the-command-line-arguments/maybe-bytes 4))))
(define segment-offset (#%string->number (list-ref the-command-line-arguments 5)))
(define cs-compiled-subdir? (string=? "true" (list-ref the-command-line-arguments 6)))
(define gracket? (string=? "true" (list-ref the-command-line-arguments 7)))
(define wm-is-gracket-or-x11-arg-count (string->number (list-ref the-command-line-arguments 8)))
(define gracket-guid-or-x11-args (list-ref the-command-line-arguments 9))
(define k-executable-path (let ([s (list-ref the-command-line-arguments/maybe-bytes 5)])
(and (not (or (equal? s "") (equal? s '#vu8())))
s)))
(define segment-offset (#%string->number (list-ref the-command-line-arguments 6)))
(define cs-compiled-subdir? (string=? "true" (list-ref the-command-line-arguments 7)))
(define gracket? (string=? "true" (list-ref the-command-line-arguments 8)))
(define wm-is-gracket-or-x11-arg-count (string->number (list-ref the-command-line-arguments 9)))
(define gracket-guid-or-x11-args (list-ref the-command-line-arguments 10))
(seq
(when (eq? 'windows (system-type))
@ -415,10 +418,11 @@
(let ([n (#%string->number s)])
(unless (exact-integer? n)
(startup-error "bad ~a: ~a" what s))
(#%number->string (+ n segment-offset))))]
(#%number->string (+ n (if f 0 segment-offset)))))]
[n (add-segment-offset n "starting offset")]
[m (add-segment-offset m "first ending offset")]
[p (add-segment-offset p "second ending offset")])
[p (add-segment-offset p "second ending offset")]
[f (or f k-executable-path)])
(set! loads
(cons
(lambda ()

View File

@ -1,5 +1,36 @@
/* This code fragment embeds strings in an executable that can be
updated with various Racket exe-manipulation tools. */
updated with various Racket exe-manipulation tools.
Used by CS's "main.c" and BC's "cmdline.inc".
Functions that are "exported":
self_exe_t get_self_path(char *argv0);
void extract_built_in_arguments(const self_exe_t self_exe,
char **_prog, char **_sprog,
int *_argc, char ***_argv);
char *SELF_PATH_TO_BYTES(self_exe_t)
char *extract_coldir();
char *extract_configdir();
long get_segment_offset(self_exe_t self); // added to `-k` arguments
Windows:
self_exe_t is wchar_t
wchar_t *extract_dlldir();
long find_resource_offset(const wchar_t *path, int id, long delta);
char *string_to_utf8(wchar_t *p);
Mac OS:
long find_mach_o_segment(const char *name, long *_len);
Unix:
int find_elf_section_offset(const char *filename,
const char *name,
int *_start, int *_end);
*/
#pragma GCC diagnostic ignored "-Wwrite-strings"
@ -99,15 +130,19 @@ static int _configdir_offset = 17; /* Skip permanent tag */
# define XFORM_OK_PLUS +
#endif
#ifdef OS_X
# include <mach-o/getsect.h>
# include <mach-o/dyld.h>
# include <fcntl.h>
#endif
#ifdef DOS_FILE_SYSTEM
# include <windows.h>
#else
# include <errno.h>
# include <fcntl.h>
# include <sys/types.h>
# include <sys/uio.h>
# include <unistd.h>
#endif
#include "self_exe.inc"
#ifdef DOS_FILE_SYSTEM
#ifndef DLL_RELATIVE_PATH
# define DLL_RELATIVE_PATH L"lib"
#endif
@ -127,40 +162,13 @@ END_XFORM_SKIP;
#endif
#ifdef OS_X
static long get_segment_offset()
static long get_segment_offset(const char *me)
{
# if defined(__x86_64__) || defined(__arm64__)
const struct segment_command_64 *seg;
# else
const struct segment_command *seg;
#endif
seg = getsegbyname("__PLTSCHEME");
if (seg)
return seg->fileoff;
else
return 0;
return find_mach_o_segment("__PLTSCHEME", NULL);
}
#endif
#ifdef DOS_FILE_SYSTEM
wchar_t *get_self_executable_path() XFORM_SKIP_PROC
{
wchar_t *path;
DWORD r, sz = 1024;
while (1) {
path = (wchar_t *)malloc(sz * sizeof(wchar_t));
r = GetModuleFileNameW(NULL, path, sz);
if ((r == sz)
&& (GetLastError() == ERROR_INSUFFICIENT_BUFFER)) {
free(path);
sz = 2 * sz;
} else
break;
}
return path;
}
static DWORD find_by_id(HANDLE fd, DWORD rsrcs, DWORD pos, int id, long delta) XFORM_SKIP_PROC
{
@ -185,7 +193,7 @@ static DWORD find_by_id(HANDLE fd, DWORD rsrcs, DWORD pos, int id, long delta) X
return 0;
}
static long find_resource_offset(wchar_t *path, int id, long delta) XFORM_SKIP_PROC
static long find_resource_offset(const wchar_t *path, int id, long delta) XFORM_SKIP_PROC
{
/* Find the resource of type `id` */
HANDLE fd;
@ -258,14 +266,45 @@ static long find_resource_offset(wchar_t *path, int id, long delta) XFORM_SKIP_P
}
}
static long get_segment_offset() XFORM_SKIP_PROC
static long get_segment_offset(const wchar_t *me) XFORM_SKIP_PROC
{
return find_resource_offset(get_self_executable_path(), 257, 0);
return find_resource_offset(me, 257, 0);
}
static char *string_to_utf8(wchar_t *p) XFORM_SKIP_PROC
{
char *r;
int len;
len = WideCharToMultiByte(CP_UTF8, 0, p, -1, NULL, 0, NULL, NULL);
r = malloc(len);
len = WideCharToMultiByte(CP_UTF8, 0, p, -1, r, len, NULL, NULL);
return r;
}
# define SELF_PATH_TO_BYTES(s) string_to_utf8(s)
#else
# define SELF_PATH_TO_BYTES(s) s
#endif
#if !defined(OS_X) && !defined(DOS_FILE_SYSTEM)
static long get_segment_offset(const char *me) XFORM_SKIP_PROC
{
int start = 0, end = 0;
(void)find_elf_section_offset(me, ".rackprog", &start, &end);
return start;
}
#endif
static void extract_built_in_arguments(char **_prog, char **_sprog, int *_argc, char ***_argv)
static void extract_built_in_arguments(const self_exe_t self_exe, char **_prog, char **_sprog, int *_argc, char ***_argv)
{
GC_CAN_IGNORE char *prog = *_prog;
GC_CAN_IGNORE char *sprog = *_sprog;
@ -321,9 +360,8 @@ static void extract_built_in_arguments(char **_prog, char **_sprog, int *_argc,
the cmdline string is. It might be relative to the
executable. */
HANDLE fd;
wchar_t *path;
wchar_t *path = self_exe;
path = get_self_executable_path();
fd = CreateFileW(path, GENERIC_READ,
FILE_SHARE_READ | FILE_SHARE_WRITE,
NULL,
@ -337,7 +375,7 @@ static void extract_built_in_arguments(char **_prog, char **_sprog, int *_argc,
DWORD got;
start = *(long *)&scheme_cmdline_exe_hack[4];
len = *(long *)&scheme_cmdline_exe_hack[8];
start += get_segment_offset();
start += get_segment_offset(self_exe);
p = (unsigned char *)malloc(len);
SetFilePointer(fd, start, 0, FILE_BEGIN);
ReadFile(fd, p, len, &got, NULL);
@ -386,14 +424,12 @@ static void extract_built_in_arguments(char **_prog, char **_sprog, int *_argc,
+ 4);
}
}
free(path);
}
#endif
#if defined(OS_X)
#else
if (scheme_cmdline_exe_hack[0] == '?') {
long fileoff, cmdoff, cmdlen;
long fileoff, cmdoff, cmdlen, need, got;
int fd;
fileoff = get_segment_offset();
fileoff = get_segment_offset(self_exe);
p = (unsigned char *)scheme_cmdline_exe_hack + 4;
cmdoff = (p[0]
@ -406,9 +442,17 @@ static void extract_built_in_arguments(char **_prog, char **_sprog, int *_argc,
+ (((long)p[7]) << 24));
p = malloc(cmdlen);
fd = open(_dyld_get_image_name(0), O_RDONLY);
fd = open(self_exe, O_RDONLY);
lseek(fd, fileoff + cmdoff, 0);
read(fd, p, cmdlen);
for (need = cmdlen; need > 0; need -= got) {
got = read(fd, p + (cmdlen - need), need);
if (got == -1) {
got = 0;
if (errno != EINTR)
break;
}
}
close(fd);
}
#endif
@ -465,7 +509,3 @@ static char *extract_configdir()
{
return scheme_configdir XFORM_OK_PLUS _configdir_offset;
}
#if !defined(OS_X) && !defined(DOS_FILE_SYSTEM)
# define NO_GET_SEGMENT_OFFSET
#endif

View File

@ -20,7 +20,7 @@ static HANDLE open_self()
wchar_t *path;
HANDLE fd;
path = get_self_executable_path();
path = get_self_path(NULL);
fd = CreateFileW(path, GENERIC_READ,
FILE_SHARE_READ | FILE_SHARE_WRITE,
@ -38,7 +38,7 @@ static void parse_embedded_dlls()
{
long rsrc_pos;
rsrc_pos = find_resource_offset(get_self_executable_path(), 258, 0);
rsrc_pos = find_resource_offset(get_self_path(NULL), 258, 0);
if (rsrc_pos) {
HANDLE fd = open_self();

View File

@ -0,0 +1,368 @@
/* Used by "ustart.c" and "config.inc".
Defines self_exe_t get_self_path(char *exec_file),
which takes argv[0] and returns an improved representation of
the containing executable. At worst, on Unix, uses `PATH` to
convert `exec_file` into a path.
On Mac (even XonX), `find_mach_o_segment` is also defined.
On Unix (not Mac OS, not even XonX), `find_elf_section`
is also defined.
If USE_EXE_LOOKUP_VIA_PATH, also: `lookup_exe_via_path`,
`path_append`, and `do_path_append`.
*/
#define USE_GENERIC_GET_SELF_PATH
#ifdef DOS_FILE_SYSTEM
typedef wchar_t *self_exe_t;
#else
typedef char *self_exe_t;
#endif
#if defined(__linux__)
# include <errno.h>
# include <unistd.h>
static char *get_self_path(char *exec_file)
{
char buf[256], *s = buf;
ssize_t len, blen = sizeof(buf);
while (1) {
len = readlink("/proc/self/exe", s, blen-1);
if (len == (blen-1)) {
if (s != buf) free(s);
blen *= 2;
s = malloc(blen);
} else if (len < 0) {
fprintf(stderr, "failed to get self (%d)\n", errno);
exit(1);
} else
break;
}
buf[len] = 0;
return strdup(buf);
}
# undef USE_GENERIC_GET_SELF_PATH
#endif
#if defined(__FreeBSD__) || defined(__NetBSD__)
# include <sys/sysctl.h>
# include <errno.h>
static char *get_self_path(char *exec_file)
{
int mib[4];
char *s;
size_t len;
int r;
mib[0] = CTL_KERN;
#if defined(__NetBSD__)
mib[1] = KERN_PROC_ARGS;
mib[2] = getpid();
mib[3] = KERN_PROC_PATHNAME;
#else
mib[1] = KERN_PROC;
mib[2] = KERN_PROC_PATHNAME;
mib[3] = -1;
#endif
r = sysctl(mib, 4, NULL, &len, NULL, 0);
if (r < 0) {
fprintf(stderr, "failed to get self (%d)\n", errno);
exit(1);
}
s = malloc(len);
r = sysctl(mib, 4, s, &len, NULL, 0);
if (r < 0) {
fprintf(stderr, "failed to get self (%d)\n", errno);
exit(1);
}
return s;
}
# undef USE_GENERIC_GET_SELF_PATH
#endif
#if defined(__APPLE__) && defined(__MACH__)
# include <mach-o/getsect.h>
# include <mach-o/dyld.h>
static char *get_self_path(char *exec_file)
{
char buf[1024], *s;
uint32_t size = sizeof(buf);
int r;
r = _NSGetExecutablePath(buf, &size);
if (!r)
return strdup(buf);
else {
s = malloc(size);
r = _NSGetExecutablePath(s, &size);
if (!r)
return s;
fprintf(stderr, "failed to get self\n");
exit(1);
}
}
# undef USE_GENERIC_GET_SELF_PATH
static long find_mach_o_segment(const char *name, long *_len)
{
# if defined(__x86_64__) || defined(__arm64__)
const struct segment_command_64 *seg;
# else
const struct segment_command *seg;
#endif
seg = getsegbyname(name);
if (seg) {
if (_len)
*_len = seg->filesize;
return seg->fileoff;
} else
return 0;
}
#endif
#ifdef DOS_FILE_SYSTEM
/* used outside this file: */
wchar_t *get_self_path(char *exec_file) XFORM_SKIP_PROC
{
wchar_t *path;
DWORD r, sz = 1024;
while (1) {
path = (wchar_t *)malloc(sz * sizeof(wchar_t));
r = GetModuleFileNameW(NULL, path, sz);
if ((r == sz)
&& (GetLastError() == ERROR_INSUFFICIENT_BUFFER)) {
free(path);
sz = 2 * sz;
} else
break;
}
return path;
}
# undef USE_GENERIC_GET_SELF_PATH
#endif
#if defined(USE_GENERIC_GET_SELF_PATH) || defined(USE_EXE_LOOKUP_VIA_PATH)
/* Get executable path via argv[0] and the `PATH` environment variable */
static int has_slash(char *s) XFORM_SKIP_PROC
{
while (*s) {
if (s[0] == '/')
return 1;
s++;
}
return 0;
}
static char *do_path_append(char *s1, int l1, char *s2) XFORM_SKIP_PROC
{
int l2;
char *s;
l2 = strlen(s2);
s = (char *)malloc(l1 + l2 + 2);
memcpy(s, s1, l1);
if (s[l1 - 1] != '/') {
s[l1++] = '/';
}
memcpy(s + l1, s2, l2);
s[l1 + l2] = 0;
return s;
}
static char *path_append(char *s1, char *s2) XFORM_SKIP_PROC
{
return do_path_append(s1, strlen(s1), s2);
}
static char *copy_string(char *s1) XFORM_SKIP_PROC
{
int l1;
char *s;
if (!s1) return NULL;
l1 = strlen(s1);
s = (char *)malloc(l1 + 1);
memcpy(s, s1, l1 + 1);
return s;
}
static int executable_exists(char *path) XFORM_SKIP_PROC
{
return (access(path, X_OK) == 0);
}
static char *lookup_exe_via_path(char *exec_file) XFORM_SKIP_PROC
{
if (exec_file[0] == '/') {
/* Absolute path */
return exec_file;
} else if (has_slash(exec_file)) {
/* Relative path with a directory: */
char *buf;
long buflen = 4096;
buf = (char *)malloc(buflen);
return path_append(getcwd(buf, buflen), exec_file);
} else {
/* We have to find the executable by searching PATH: */
char *path = copy_string(getenv("PATH")), *p, *m;
int more;
if (!path) {
path = "";
}
while (1) {
/* Try each element of path: */
for (p = path; *p && (*p != ':'); p++) { }
if (*p) {
*p = 0;
more = 1;
} else
more = 0;
if (!*path)
break;
m = path_append(path, exec_file);
if (executable_exists(m)) {
if (m[0] != '/')
m = path_append(getcwd(NULL, 0), m);
return m;
}
free(m);
if (more)
path = p + 1;
else
break;
}
return exec_file;
}
}
#endif
#ifdef USE_GENERIC_GET_SELF_PATH
static char *get_self_path(char *exec_file)
{
return lookup_exe_via_path(exec_file);
}
#endif
#if !defined(OS_X) && !defined(DOS_FILE_SYSTEM)
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
typedef unsigned short ELF__Half;
typedef unsigned int ELF__Word;
typedef unsigned long ELF__Xword;
typedef unsigned long ELF__Addr;
typedef unsigned long ELF__Off;
typedef struct {
unsigned char e_ident[16];
ELF__Half e_type;
ELF__Half e_machine;
ELF__Word e_version;
ELF__Addr e_entry;
ELF__Off e_phoff;
ELF__Off e_shoff;
ELF__Word e_flags;
ELF__Half e_ehsize;
ELF__Half e_phentsize;
ELF__Half e_phnum;
ELF__Half e_shentsize;
ELF__Half e_shnum;
ELF__Half e_shstrndx;
} ELF__Header;
typedef struct
{
ELF__Word sh_name;
ELF__Word sh_type;
ELF__Xword sh_flags;
ELF__Addr sh_addr;
ELF__Off sh_offset;
ELF__Xword sh_size;
ELF__Word sh_link;
ELF__Word sh_info;
ELF__Xword sh_addralign;
ELF__Xword sh_entsize;
} Elf__Shdr;
static int find_elf_section_offset(const char *filename,
const char *name,
int *_start, int *_end) XFORM_SKIP_PROC
{
int fd, i;
ELF__Header e;
Elf__Shdr s;
char *strs;
fd = open(filename, O_RDONLY, 0);
if (fd == -1) return 0;
if (read(fd, &e, sizeof(e)) == sizeof(e)) {
if ((e.e_ident[0] == 0x7F)
&& (e.e_ident[1] == 'E')
&& (e.e_ident[2] == 'L')
&& (e.e_ident[3] == 'F')) {
lseek(fd, e.e_shoff + (e.e_shstrndx * e.e_shentsize), SEEK_SET);
if (read(fd, &s, sizeof(s)) != sizeof(s)) {
close(fd);
return 0;
}
strs = (char *)malloc(s.sh_size);
lseek(fd, s.sh_offset, SEEK_SET);
if (read(fd, strs, s.sh_size) != s.sh_size) {
close(fd);
free(strs);
return 0;
}
for (i = 0; i < e.e_shnum; i++) {
lseek(fd, e.e_shoff + (i * e.e_shentsize), SEEK_SET);
if (read(fd, &s, sizeof(s)) != sizeof(s)) {
close(fd);
return 0;
}
if (!strcmp(strs + s.sh_name, name)) {
*_start = s.sh_offset;
*_end = s.sh_offset + s.sh_size;
close(fd);
free(strs);
return 1;
}
}
free(strs);
}
}
close(fd);
return 0;
}
#endif

View File

@ -1,86 +0,0 @@
#define USE_GENERIC_GET_SELF_PATH
#if defined(__linux__)
# include <errno.h>
static char *get_self_path(char *exec_file)
{
char buf[256], *s = buf;
ssize_t len, blen = sizeof(buf);
while (1) {
len = readlink("/proc/self/exe", s, blen-1);
if (len == (blen-1)) {
if (s != buf) free(s);
blen *= 2;
s = malloc(blen);
} else if (len < 0) {
fprintf(stderr, "failed to get self (%d)\n", errno);
exit(1);
} else
break;
}
buf[len] = 0;
return strdup(buf);
}
# undef USE_GENERIC_GET_SELF_PATH
#endif
#if defined(__FreeBSD__) || defined(__NetBSD__)
# include <sys/sysctl.h>
# include <errno.h>
static char *get_self_path(char *exec_file)
{
int mib[4];
char *s;
size_t len;
int r;
mib[0] = CTL_KERN;
#if defined(__NetBSD__)
mib[1] = KERN_PROC_ARGS;
mib[2] = getpid();
mib[3] = KERN_PROC_PATHNAME;
#else
mib[1] = KERN_PROC;
mib[2] = KERN_PROC_PATHNAME;
mib[3] = -1;
#endif
r = sysctl(mib, 4, NULL, &len, NULL, 0);
if (r < 0) {
fprintf(stderr, "failed to get self (%d)\n", errno);
exit(1);
}
s = malloc(len);
r = sysctl(mib, 4, s, &len, NULL, 0);
if (r < 0) {
fprintf(stderr, "failed to get self (%d)\n", errno);
exit(1);
}
return s;
}
# undef USE_GENERIC_GET_SELF_PATH
#endif
#if defined(__APPLE__) && defined(__MACH__)
# include <mach-o/dyld.h>
static char *get_self_path(char *exec_file)
{
char buf[1024], *s;
uint32_t size = sizeof(buf);
int r;
r = _NSGetExecutablePath(buf, &size);
if (!r)
return strdup(buf);
else {
s = malloc(size);
r = _NSGetExecutablePath(s, &size);
if (!r)
return s;
fprintf(stderr, "failed to get self\n");
exit(1);
}
}
# undef USE_GENERIC_GET_SELF_PATH
#endif

View File

@ -95,6 +95,10 @@ char * volatile _configdir = "coNFIg dIRECTORy:" /* <- this tag stays, so we can
"****************************************************************";
static int _configdir_offset = 17; /* Skip permanent tag */
#define XFORM_SKIP_PROC /* empty */
#define USE_EXE_LOOKUP_VIA_PATH
#include "self_exe.inc"
typedef struct {
char *flag;
int arg_count;
@ -174,68 +178,12 @@ static char *string_append(char *s1, char *s2)
return s;
}
static char *copy_string(char *s1)
{
int l1;
char *s;
if (!s1) return NULL;
l1 = strlen(s1);
s = (char *)malloc(l1 + 1);
memcpy(s, s1, l1 + 1);
return s;
}
static char *do_path_append(char *s1, int l1, char *s2)
{
int l2;
char *s;
l2 = strlen(s2);
s = (char *)malloc(l1 + l2 + 2);
memcpy(s, s1, l1);
if (s[l1 - 1] != '/') {
s[l1++] = '/';
}
memcpy(s + l1, s2, l2);
s[l1 + l2] = 0;
return s;
}
static char *path_append(char *s1, char *s2)
{
return do_path_append(s1, strlen(s1), s2);
}
static int executable_exists(char *path)
{
return (access(path, X_OK) == 0);
}
static int as_int(char *_c)
{
unsigned char *c = (unsigned char *)_c;
return c[0] | ((int)c[1] << 8) | ((int)c[2] << 16) | ((int)c[3] << 24);
}
static int has_slash(char *s)
{
while (*s) {
if (s[0] == '/')
return 1;
s++;
}
return 0;
}
char *absolutize(char *p, char *d)
{
int l1;
@ -262,107 +210,30 @@ static char *next_string(char *s)
return s + strlen(s) + 1;
}
#include "unix_self.inc"
static int try_section_shift(const char *me, int *_start, int *_decl_end, int *_prog_end, int *_end)
{
int start = 0, end = 0;
int is_prog;
#ifdef USE_GENERIC_GET_SELF_PATH
static char *adjust_self_reference(char *me)
{
return me;
}
#ifdef OS_X
{
long len = 0;
start = find_mach_o_segment("__PLTSCHEME", &len);
end = start + len;
is_prog = 1;
}
#else
static char *adjust_self_reference(char *me)
{
return get_self_path(me);
}
is_prog = find_elf_section_offset(me, ".rackprog", &start, &end);
#endif
typedef unsigned short ELF__Half;
typedef unsigned int ELF__Word;
typedef unsigned long ELF__Xword;
typedef unsigned long ELF__Addr;
typedef unsigned long ELF__Off;
typedef struct {
unsigned char e_ident[16];
ELF__Half e_type;
ELF__Half e_machine;
ELF__Word e_version;
ELF__Addr e_entry;
ELF__Off e_phoff;
ELF__Off e_shoff;
ELF__Word e_flags;
ELF__Half e_ehsize;
ELF__Half e_phentsize;
ELF__Half e_phnum;
ELF__Half e_shentsize;
ELF__Half e_shnum;
ELF__Half e_shstrndx;
} ELF__Header;
typedef struct
{
ELF__Word sh_name;
ELF__Word sh_type;
ELF__Xword sh_flags;
ELF__Addr sh_addr;
ELF__Off sh_offset;
ELF__Xword sh_size;
ELF__Word sh_link;
ELF__Word sh_info;
ELF__Xword sh_addralign;
ELF__Xword sh_entsize;
} Elf__Shdr;
static int try_elf_section(const char *me, int *_start, int *_decl_end, int *_prog_end, int *_end)
{
int fd, i;
ELF__Header e;
Elf__Shdr s;
char *strs;
fd = open(me, O_RDONLY, 0);
if (fd == -1) return 0;
if (read(fd, &e, sizeof(e)) == sizeof(e)) {
if ((e.e_ident[0] == 0x7F)
&& (e.e_ident[1] == 'E')
&& (e.e_ident[2] == 'L')
&& (e.e_ident[3] == 'F')) {
lseek(fd, e.e_shoff + (e.e_shstrndx * e.e_shentsize), SEEK_SET);
if (read(fd, &s, sizeof(s)) != sizeof(s)) {
close(fd);
return 0;
if (start != 0) {
*_decl_end = (*_decl_end - *_start) + start;
*_prog_end = (*_prog_end - *_start) + start;
*_start = start;
*_end = end;
}
strs = (char *)malloc(s.sh_size);
lseek(fd, s.sh_offset, SEEK_SET);
if (read(fd, strs, s.sh_size) != s.sh_size) {
close(fd);
return 0;
}
for (i = 0; i < e.e_shnum; i++) {
lseek(fd, e.e_shoff + (i * e.e_shentsize), SEEK_SET);
if (read(fd, &s, sizeof(s)) != sizeof(s)) {
close(fd);
return 0;
}
if (!strcmp(strs + s.sh_name, ".rackcmdl")
|| !strcmp(strs + s.sh_name, ".rackprog")) {
*_decl_end = (*_decl_end - *_start) + s.sh_offset;
*_prog_end = (*_prog_end - *_start) + s.sh_offset;
*_start = s.sh_offset;
*_end = s.sh_offset + s.sh_size;
close(fd);
return !strcmp(strs + s.sh_name, ".rackprog");
}
}
}
}
close(fd);
return 0;
return is_prog;
}
int main(int argc, char **argv)
@ -379,52 +250,7 @@ int main(int argc, char **argv)
return 1;
}
if (me[0] == '/') {
/* Absolute path */
} else if (has_slash(me)) {
/* Relative path with a directory: */
char *buf;
long buflen = 4096;
buf = (char *)malloc(buflen);
me = path_append(getcwd(buf, buflen), me);
free(buf);
} else {
/* We have to find the executable by searching PATH: */
char *path = copy_string(getenv("PATH")), *p, *m;
int more;
if (!path) {
path = "";
}
while (1) {
/* Try each element of path: */
for (p = path; *p && (*p != ':'); p++) { }
if (*p) {
*p = 0;
more = 1;
} else
more = 0;
if (!*path)
break;
m = path_append(path, me);
if (executable_exists(m)) {
if (m[0] != '/')
m = path_append(getcwd(NULL, 0), m);
me = m;
break;
}
free(m);
if (more)
path = p + 1;
else
break;
}
}
me = lookup_exe_via_path(me);
/* me is now an absolute path to the binary */
@ -451,7 +277,7 @@ int main(int argc, char **argv)
/* use `me` for `-k`, unless we have a way to more directly get the
executable file that contains embedded code; if we do, then
argv[0] doesn't have to match the executable */
embedding_me = adjust_self_reference(me);
embedding_me = get_self_path(me);
start = as_int(config + 8);
decl_end = as_int(config + 12);
@ -460,7 +286,7 @@ int main(int argc, char **argv)
count = as_int(config + 24);
x11 = as_int(config + 28);
fix_argv = try_elf_section(embedding_me, &start, &decl_end, &prog_end, &end);
try_section_shift(embedding_me, &start, &decl_end, &prog_end, &end);
{
int offset, len;
@ -566,13 +392,11 @@ int main(int argc, char **argv)
new_argv[argpos++] = "-G";
new_argv[argpos++] = absolutize(_configdir + _configdir_offset, me);
if (fix_argv) {
/* next four args are "-k" and numbers; leave room to insert the
filename in place of "-k", and fix the numbers to match start,
decl_end, and prog_end */
new_argv[argpos++] = "-Y";
fix_argv = argpos;
}
/* Add built-in flags: */
while (count--) {

View File

@ -42,3 +42,6 @@ cstartup.exe
/liblz4.dll
/liblz4.lib
/liblz4.exp
/liblz4mt.dll
/liblz4mt.lib
/liblz4mt.exp