Skip to content

Commit 70000ac

Browse files
authored
sysimg: Allow loading a system image that is already present in memory (#51121)
I've written this code probably three times at this point, but for some reason it never made it into a PR. This allows loading a system image that has already been loaded into memory. This happen when wanting to distribute a static or mostly-static binary of julia code where the system image (and optionally other libraries like libjulia, etc.) are linked directly into the main executable. It is also useful for deployment to environments that do not have (or have incomplete) support for dynamic linking (e.g. wasm or embedded).
1 parent da86735 commit 70000ac

File tree

6 files changed

+45
-10
lines changed

6 files changed

+45
-10
lines changed

src/Makefile

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -153,7 +153,7 @@ endif
153153
CLANG_LDFLAGS := $(LLVM_LDFLAGS)
154154
ifeq ($(OS), Darwin)
155155
CLANG_LDFLAGS += -Wl,-undefined,dynamic_lookup
156-
OSLIBS += -Wl,-U,__dyld_atfork_parent -Wl,-U,__dyld_atfork_prepare -Wl,-U,__dyld_dlopen_atfork_parent -Wl,-U,__dyld_dlopen_atfork_prepare
156+
OSLIBS += -Wl,-U,__dyld_atfork_parent -Wl,-U,__dyld_atfork_prepare -Wl,-U,__dyld_dlopen_atfork_parent -Wl,-U,__dyld_dlopen_atfork_prepare -Wl,-U,_jl_image_pointers -Wl,-U,_jl_system_image_data -Wl,-U,_jl_system_image_size
157157
LIBJULIA_PATH_REL := @rpath/libjulia
158158
else
159159
LIBJULIA_PATH_REL := libjulia

src/init.c

Lines changed: 5 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -620,7 +620,8 @@ static const char *absformat(const char *in)
620620
}
621621

622622
static void jl_resolve_sysimg_location(JL_IMAGE_SEARCH rel)
623-
{ // this function resolves the paths in jl_options to absolute file locations as needed
623+
{
624+
// this function resolves the paths in jl_options to absolute file locations as needed
624625
// and it replaces the pointers to `julia_bindir`, `julia_bin`, `image_file`, and output file paths
625626
// it may fail, print an error, and exit(1) if any of these paths are longer than JL_PATH_MAX
626627
//
@@ -841,7 +842,9 @@ static NOINLINE void _finish_julia_init(JL_IMAGE_SEARCH rel, jl_ptls_t ptls, jl_
841842
JL_TIMING(JULIA_INIT, JULIA_INIT);
842843
jl_resolve_sysimg_location(rel);
843844
// loads sysimg if available, and conditionally sets jl_options.cpu_target
844-
if (jl_options.image_file)
845+
if (rel == JL_IMAGE_IN_MEMORY)
846+
jl_set_sysimg_so(jl_exe_handle);
847+
else if (jl_options.image_file)
845848
jl_preload_sysimg_so(jl_options.image_file);
846849
if (jl_options.cpu_target == NULL)
847850
jl_options.cpu_target = "native";

src/julia.h

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1863,7 +1863,7 @@ JL_DLLEXPORT void jl_exception_clear(void) JL_NOTSAFEPOINT;
18631863
typedef enum {
18641864
JL_IMAGE_CWD = 0,
18651865
JL_IMAGE_JULIA_HOME = 1,
1866-
//JL_IMAGE_LIBJULIA = 2,
1866+
JL_IMAGE_IN_MEMORY = 2
18671867
} JL_IMAGE_SEARCH;
18681868

18691869
JL_DLLIMPORT const char *jl_get_libdir(void);

src/julia_internal.h

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1645,6 +1645,17 @@ jl_sym_t *_jl_symbol(const char *str, size_t len) JL_NOTSAFEPOINT;
16451645
#define JL_GC_ASSERT_LIVE(x) (void)(x)
16461646
#endif
16471647

1648+
#ifdef _OS_WINDOWS_
1649+
// On Windows, weak symbols do not default to 0 due to a GCC bug
1650+
// (https://gcc.gnu.org/bugzilla/show_bug.cgi?id=90826), use symbol
1651+
// aliases with a known value instead.
1652+
#define JL_WEAK_SYMBOL_OR_ALIAS_DEFAULT(sym) __attribute__((weak,alias(#sym)))
1653+
#define JL_WEAK_SYMBOL_DEFAULT(sym) &sym
1654+
#else
1655+
#define JL_WEAK_SYMBOL_OR_ALIAS_DEFAULT(sym) __attribute__((weak))
1656+
#define JL_WEAK_SYMBOL_DEFAULT(sym) NULL
1657+
#endif
1658+
16481659
JL_DLLEXPORT float julia__gnu_h2f_ieee(uint16_t param) JL_NOTSAFEPOINT;
16491660
JL_DLLEXPORT uint16_t julia__gnu_f2h_ieee(float param) JL_NOTSAFEPOINT;
16501661
JL_DLLEXPORT uint16_t julia__truncdfhf2(double param) JL_NOTSAFEPOINT;

src/processor.cpp

Lines changed: 9 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -618,6 +618,11 @@ static inline std::vector<TargetData<n>> &get_cmdline_targets(F &&feature_cb)
618618
return targets;
619619
}
620620

621+
extern "C" {
622+
void *image_pointers_unavailable;
623+
extern void * JL_WEAK_SYMBOL_OR_ALIAS_DEFAULT(image_pointers_unavailable) jl_image_pointers;
624+
}
625+
621626
// Load sysimg, use the `callback` for dispatch and perform all relocations
622627
// for the selected target.
623628
template<typename F>
@@ -627,7 +632,10 @@ static inline jl_image_t parse_sysimg(void *hdl, F &&callback)
627632
jl_image_t res{};
628633

629634
const jl_image_pointers_t *pointers;
630-
jl_dlsym(hdl, "jl_image_pointers", (void**)&pointers, 1);
635+
if (hdl == jl_exe_handle && &jl_image_pointers != JL_WEAK_SYMBOL_DEFAULT(image_pointers_unavailable))
636+
pointers = (const jl_image_pointers_t *)&jl_image_pointers;
637+
else
638+
jl_dlsym(hdl, "jl_image_pointers", (void**)&pointers, 1);
631639

632640
const void *ids = pointers->target_data;
633641
jl_value_t* rejection_reason = nullptr;

src/staticdata.c

Lines changed: 18 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -569,6 +569,9 @@ JL_DLLEXPORT int jl_running_on_valgrind(void)
569569
return RUNNING_ON_VALGRIND;
570570
}
571571

572+
void *system_image_data_unavailable;
573+
extern void * JL_WEAK_SYMBOL_OR_ALIAS_DEFAULT(system_image_data_unavailable) jl_system_image_data;
574+
extern void * JL_WEAK_SYMBOL_OR_ALIAS_DEFAULT(system_image_data_unavailable) jl_system_image_size;
572575
static void jl_load_sysimg_so(void)
573576
{
574577
int imaging_mode = jl_generating_output() && !jl_options.incremental;
@@ -580,9 +583,17 @@ static void jl_load_sysimg_so(void)
580583
memset(&sysimage.fptrs, 0, sizeof(sysimage.fptrs));
581584
}
582585
const char *sysimg_data;
583-
jl_dlsym(jl_sysimg_handle, "jl_system_image_data", (void **)&sysimg_data, 1);
586+
if (jl_sysimg_handle == jl_exe_handle &&
587+
&jl_system_image_data != JL_WEAK_SYMBOL_DEFAULT(system_image_data_unavailable))
588+
sysimg_data = (const char*)&jl_system_image_data;
589+
else
590+
jl_dlsym(jl_sysimg_handle, "jl_system_image_data", (void **)&sysimg_data, 1);
584591
size_t *plen;
585-
jl_dlsym(jl_sysimg_handle, "jl_system_image_size", (void **)&plen, 1);
592+
if (jl_sysimg_handle == jl_exe_handle &&
593+
&jl_system_image_size != JL_WEAK_SYMBOL_DEFAULT(system_image_data_unavailable))
594+
plen = (size_t *)&jl_system_image_size;
595+
else
596+
jl_dlsym(jl_sysimg_handle, "jl_system_image_size", (void **)&plen, 1);
586597
jl_restore_system_image_data(sysimg_data, *plen);
587598
}
588599

@@ -2820,9 +2831,11 @@ JL_DLLEXPORT void jl_preload_sysimg_so(const char *fname)
28202831
JL_DLLEXPORT void jl_set_sysimg_so(void *handle)
28212832
{
28222833
void* *jl_RTLD_DEFAULT_handle_pointer;
2823-
int symbol_found = jl_dlsym(handle, "jl_RTLD_DEFAULT_handle_pointer", (void **)&jl_RTLD_DEFAULT_handle_pointer, 0);
2824-
if (!symbol_found || (void*)&jl_RTLD_DEFAULT_handle != *jl_RTLD_DEFAULT_handle_pointer)
2825-
jl_error("System image file failed consistency check: maybe opened the wrong version?");
2834+
if (handle != jl_RTLD_DEFAULT_handle) {
2835+
int symbol_found = jl_dlsym(handle, "jl_RTLD_DEFAULT_handle_pointer", (void **)&jl_RTLD_DEFAULT_handle_pointer, 0);
2836+
if (!symbol_found || (void*)&jl_RTLD_DEFAULT_handle != *jl_RTLD_DEFAULT_handle_pointer)
2837+
jl_error("System image file failed consistency check: maybe opened the wrong version?");
2838+
}
28262839
if (jl_options.cpu_target == NULL)
28272840
jl_options.cpu_target = "native";
28282841
jl_sysimg_handle = handle;

0 commit comments

Comments
 (0)