Skip to content

Commit ac4ee59

Browse files
authored
Avoid using fork() when probing system libstdc++ (#60254)
Somewhat of a companion to #60248. For a small application that has just started up `fork()` is not a huge concern, but it's quite heavy-handed for Julia- as-a-library scenarios where resident memory may already be large. Many soft-embedded targets also do not support fork() well, so it is good for our compatibility to adjust this. Rather than relying on the linker to do all of the heavy lifting, this changes our `libstdcxx` probe sequence to directly parse the `ld.so.cache` and `libstdc++.so.6` files. As long as we can expect `/etc/ld.so.cache` to be the same path on all Linux systems, this seems to be a reliable way to locate system libraries.
1 parent 296cca2 commit ac4ee59

File tree

7 files changed

+545
-159
lines changed

7 files changed

+545
-159
lines changed

‎THIRDPARTY.md‎

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@ and some utilities (most of the rest of the files in this repository). See below
44
for exceptions.
55

66
-[crc32c.c](https://stackoverflow.com/questions/17645167/implementing-sse-4-2s-crc32c-in-software) (CRC-32c checksum code by Mark Adler) [[ZLib](https://opensource.org/licenses/Zlib)].
7+
-[dl-cache.h](https://www.gnu.org/licenses/old-licenses/lgpl-2.1.html) (for reading ld-cache files on startup) [LGPL2.1+]
78
-[LDC](https://github.com/ldc-developers/ldc/blob/master/LICENSE) (for ccall/cfunction ABI definitions) [BSD-3]. The portion of code that Julia uses from LDC is [BSD-3] licensed.
89
-[LLVM](https://releases.llvm.org/3.9.0/LICENSE.TXT) (for parts of src/disasm.cpp) [UIUC]
910
-[NetBSD](https://www.netbsd.org/about/redistribution.html) (for setjmp, longjmp, and strptime implementations on Windows) [BSD-3]

‎cli/Makefile‎

Lines changed: 11 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,7 @@ include $(JULIAHOME)/Make.inc
55
include$(JULIAHOME)/deps/llvm-ver.make
66

77

8-
HEADERS := $(addprefix$(SRCDIR)/,jl_exports.h loader.h)$(addprefix$(JULIAHOME)/src/,julia_fasttls.h support/platform.h support/dirpath.h jl_exported_data.inc jl_exported_funcs.inc)
8+
HEADERS := $(addprefix$(SRCDIR)/,jl_exports.h loader.h dl-cache.h)$(addprefix$(JULIAHOME)/src/,julia_fasttls.h support/platform.h support/dirpath.h jl_exported_data.inc jl_exported_funcs.inc)
99

1010
LOADER_CFLAGS = $(JCFLAGS) -I$(BUILDROOT)/src -I$(JULIAHOME)/src -I$(JULIAHOME)/src/support -I$(build_includedir) -ffreestanding
1111
LOADER_LDFLAGS = $(JLDFLAGS) -ffreestanding -L$(build_shlibdir) -L$(build_libdir)
@@ -46,8 +46,8 @@ endif # USE_RT_STATIC_LIBSTDCXX
4646

4747
EXE_OBJS := $(BUILDDIR)/loader_exe.o
4848
EXE_DOBJS := $(BUILDDIR)/loader_exe.dbg.obj
49-
LIB_OBJS := $(BUILDDIR)/loader_lib.o
50-
LIB_DOBJS := $(BUILDDIR)/loader_lib.dbg.obj
49+
LIB_OBJS := $(BUILDDIR)/loader_lib.o$(BUILDDIR)/loader_symbol_probe.o $(BUILDDIR)/loader_library_probe.o
50+
LIB_DOBJS := $(BUILDDIR)/loader_lib.dbg.obj$(BUILDDIR)/loader_symbol_probe.dbg.obj $(BUILDDIR)/loader_library_probe.dbg.obj
5151

5252
# If this is an architecture that supports dynamic linking, link in a trampoline definition
5353
ifneq (,$(wildcard$(SRCDIR)/trampolines/trampolines_$(ARCH).S))
@@ -71,6 +71,14 @@ $(BUILDDIR)/loader_trampolines.o : $(SRCDIR)/trampolines/trampolines_$(ARCH).S $
7171
@$(call PRINT_CC, $(CC)$(SHIPFLAGS)$(LOADER_CFLAGS)$< -c -o $@)
7272
$(BUILDDIR)/loader_trampolines.dbg.obj : $(SRCDIR)/trampolines/trampolines_$(ARCH).S $(HEADERS)$(SRCDIR)/trampolines/common.h
7373
@$(call PRINT_CC, $(CC)$(DEBUGFLAGS)$(LOADER_CFLAGS)$< -c -o $@)
74+
$(BUILDDIR)/loader_library_probe.o : $(SRCDIR)/loader_library_probe.c $(HEADERS)$(JULIAHOME)/VERSION
75+
@$(call PRINT_CC, $(CC) -DJL_LIBRARY_EXPORTS $(SHIPFLAGS)$(LOADER_CFLAGS) -c $< -o $@)
76+
$(BUILDDIR)/loader_library_probe.dbg.obj : $(SRCDIR)/loader_library_probe.c $(HEADERS)$(JULIAHOME)/VERSION
77+
@$(call PRINT_CC, $(CC) -DJL_LIBRARY_EXPORTS $(DEBUGFLAGS)$(LOADER_CFLAGS) -c $< -o $@)
78+
$(BUILDDIR)/loader_symbol_probe.o : $(SRCDIR)/loader_symbol_probe.c $(HEADERS)$(JULIAHOME)/VERSION
79+
@$(call PRINT_CC, $(CC) -DJL_LIBRARY_EXPORTS $(SHIPFLAGS)$(LOADER_CFLAGS) -c $< -o $@)
80+
$(BUILDDIR)/loader_symbol_probe.dbg.obj : $(SRCDIR)/loader_symbol_probe.c $(HEADERS)$(JULIAHOME)/VERSION
81+
@$(call PRINT_CC, $(CC) -DJL_LIBRARY_EXPORTS $(DEBUGFLAGS)$(LOADER_CFLAGS) -c $< -o $@)
7482

7583
# Debugging target to help us see what kind of code is being generated for our trampolines
7684
dump-trampolines: $(SRCDIR)/trampolines/trampolines_$(ARCH).S

‎cli/dl-cache.h‎

Lines changed: 184 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,184 @@
1+
/* Support for reading /etc/ld.so.cache files written by Linux ldconfig.
2+
Copyright (C) 1999-2019 Free Software Foundation, Inc.
3+
This file is part of the GNU C Library.
4+
5+
The GNU C Library is free software; you can redistribute it and/or
6+
modify it under the terms of the GNU Lesser General Public
7+
License as published by the Free Software Foundation; either
8+
version 2.1 of the License, or (at your option) any later version.
9+
10+
The GNU C Library is distributed in the hope that it will be useful,
11+
but WITHOUT ANY WARRANTY; without even the implied warranty of
12+
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
13+
Lesser General Public License for more details.
14+
15+
You should have received a copy of the GNU Lesser General Public
16+
License along with the GNU C Library; if not, see
17+
<http://www.gnu.org/licenses/>. */
18+
19+
#include<stdint.h>
20+
21+
#defineFLAG_ANY -1
22+
#defineFLAG_TYPE_MASK 0x00ff
23+
#defineFLAG_LIBC4 0x0000
24+
#defineFLAG_ELF 0x0001
25+
#defineFLAG_ELF_LIBC5 0x0002
26+
#defineFLAG_ELF_LIBC6 0x0003
27+
#defineFLAG_REQUIRED_MASK 0xff00
28+
#defineFLAG_SPARC_LIB64 0x0100
29+
#defineFLAG_IA64_LIB64 0x0200
30+
#defineFLAG_X8664_LIB64 0x0300
31+
#defineFLAG_S390_LIB64 0x0400
32+
#defineFLAG_POWERPC_LIB64 0x0500
33+
#defineFLAG_MIPS64_LIBN32 0x0600
34+
#defineFLAG_MIPS64_LIBN64 0x0700
35+
#defineFLAG_X8664_LIBX32 0x0800
36+
#defineFLAG_ARM_LIBHF 0x0900
37+
#defineFLAG_AARCH64_LIB64 0x0a00
38+
#defineFLAG_ARM_LIBSF 0x0b00
39+
#defineFLAG_MIPS_LIB32_NAN2008 0x0c00
40+
#defineFLAG_MIPS64_LIBN32_NAN2008 0x0d00
41+
#defineFLAG_MIPS64_LIBN64_NAN2008 0x0e00
42+
#defineFLAG_RISCV_FLOAT_ABI_SOFT 0x0f00
43+
#defineFLAG_RISCV_FLOAT_ABI_DOUBLE 0x1000
44+
45+
#if defined(_CPU_X86_64_)
46+
47+
#define_DL_CACHE_DEFAULT_ID 0x303
48+
#define_dl_cache_check_flags(flags) ((flags) == _DL_CACHE_DEFAULT_ID)
49+
50+
#elif defined(_CPU_AARCH64_)
51+
52+
#ifdef__LP64__
53+
# define_DL_CACHE_DEFAULT_ID (FLAG_AARCH64_LIB64 | FLAG_ELF_LIBC6)
54+
#else
55+
# define_DL_CACHE_DEFAULT_ID (FLAG_AARCH64_LIB32 | FLAG_ELF_LIBC6)
56+
#endif
57+
58+
#define_dl_cache_check_flags(flags) ((flags) == _DL_CACHE_DEFAULT_ID)
59+
60+
#elif defined(_CPU_RISCV64_)
61+
62+
/* For now we only support the natural XLEN ABI length on all targets, so the
63+
only bits that need to go into ld.so.cache are the flags for ABI length. */
64+
#if defined __riscv_float_abi_double
65+
# define_DL_CACHE_DEFAULT_ID (FLAG_RISCV_FLOAT_ABI_DOUBLE | FLAG_ELF_LIBC6)
66+
#else
67+
# define_DL_CACHE_DEFAULT_ID (FLAG_RISCV_FLOAT_ABI_SOFT | FLAG_ELF_LIBC6)
68+
#endif
69+
70+
#define_dl_cache_check_flags(flags) ((flags) == _DL_CACHE_DEFAULT_ID)
71+
72+
#elif defined(_CPU_ARM_)
73+
74+
/* In order to support the transition from unmarked objects
75+
to marked objects we must treat unmarked objects as
76+
compatible with either FLAG_ARM_LIBHF or FLAG_ARM_LIBSF. */
77+
#ifdef__ARM_PCS_VFP
78+
# define_dl_cache_check_flags(flags) \
79+
((flags) == (FLAG_ARM_LIBHF | FLAG_ELF_LIBC6) \
80+
|| (flags) == FLAG_ELF_LIBC6)
81+
#else
82+
# define_dl_cache_check_flags(flags) \
83+
((flags) == (FLAG_ARM_LIBSF | FLAG_ELF_LIBC6) \
84+
|| (flags) == FLAG_ELF_LIBC6)
85+
#endif
86+
87+
#elif defined(_CPU_X86_)
88+
89+
/* Defined as (FLAG_ELF_LIBC6 | FLAG_X8664_LIBX32). */
90+
#undef _DL_CACHE_DEFAULT_ID
91+
#define_DL_CACHE_DEFAULT_ID 0x803
92+
93+
#elif defined(_CPU_PPC64_)
94+
95+
#define_DL_CACHE_DEFAULT_ID 0x503
96+
97+
#define_dl_cache_check_flags(flags) \
98+
((flags) == _DL_CACHE_DEFAULT_ID)
99+
100+
#else
101+
102+
#error "Missing CPU arch-specific definitions in dl-cache.h"
103+
104+
#endif
105+
106+
#ifndef_DL_CACHE_DEFAULT_ID
107+
# define_DL_CACHE_DEFAULT_ID 3
108+
#endif
109+
110+
#ifndef_dl_cache_check_flags
111+
# define_dl_cache_check_flags(flags) \
112+
((flags) == 1 || (flags) == _DL_CACHE_DEFAULT_ID)
113+
#endif
114+
115+
#ifndefLD_SO_CACHE
116+
# defineLD_SO_CACHE SYSCONFDIR "/ld.so.cache"
117+
#endif
118+
119+
#defineCACHEMAGIC "ld.so-1.7.0"
120+
121+
/* libc5 and glibc 2.0/2.1 use the same format. For glibc 2.2 another
122+
format has been added in a compatible way:
123+
The beginning of the string table is used for the new table:
124+
old_magic
125+
nlibs
126+
libs[0]
127+
...
128+
libs[nlibs-1]
129+
pad, new magic needs to be aligned
130+
- this is string[0] for the old format
131+
new magic - this is string[0] for the new format
132+
newnlibs
133+
...
134+
newlibs[0]
135+
...
136+
newlibs[newnlibs-1]
137+
string 1
138+
string 2
139+
...
140+
*/
141+
structfile_entry
142+
{
143+
intflags; /* This is 1 for an ELF library. */
144+
unsigned intkey, value; /* String table indices. */
145+
};
146+
147+
structcache_file
148+
{
149+
charmagic[sizeofCACHEMAGIC-1];
150+
unsigned intnlibs;
151+
structfile_entrylibs[0];
152+
};
153+
154+
#defineCACHEMAGIC_NEW "glibc-ld.so.cache"
155+
#defineCACHE_VERSION "1.1"
156+
#defineCACHEMAGIC_VERSION_NEW CACHEMAGIC_NEW CACHE_VERSION
157+
158+
159+
structfile_entry_new
160+
{
161+
int32_tflags; /* This is 1 for an ELF library. */
162+
uint32_tkey, value; /* String table indices. */
163+
uint32_tosversion; /* Required OS version. */
164+
uint64_thwcap; /* Hwcap entry. */
165+
};
166+
167+
structcache_file_new
168+
{
169+
charmagic[sizeofCACHEMAGIC_NEW-1];
170+
charversion[sizeofCACHE_VERSION-1];
171+
uint32_tnlibs; /* Number of entries. */
172+
uint32_tlen_strings; /* Size of string table. */
173+
uint32_tunused[5]; /* Leave space for future extensions
174+
and align to 8 byte boundary. */
175+
structfile_entry_newlibs[0]; /* Entries describing libraries. */
176+
/* After this the string table of size len_strings is found. */
177+
};
178+
179+
/* Used to align cache_file_new. */
180+
#defineALIGN_CACHE(addr) \
181+
(((addr) + __alignof__ (struct cache_file_new) -1) \
182+
& (~(__alignof__ (struct cache_file_new) - 1)))
183+
184+
// extern int _dl_cache_libcmp (const char *p1, const char *p2) attribute_hidden;

‎cli/loader.h‎

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -70,7 +70,10 @@
7070
JL_DLLEXPORTexternintjl_load_repl(int, char**);
7171
JL_DLLEXPORTvoidjl_loader_print_stderr(constchar*msg);
7272
voidjl_loader_print_stderr3(constchar*msg1, constchar*msg2, constchar*msg3);
73+
void*jl_loader_open_via_mmap(constchar*filepath, size_t*size);
7374
staticvoid*lookup_symbol(constvoid*lib_handle, constchar*symbol_name);
75+
constchar*jl_loader_probe_system_library(constchar*libname, constchar*symbol);
76+
intjl_loader_locate_symbol(constchar*library, constchar*symbol);
7477

7578
#ifdef_OS_WINDOWS_
7679
LPWSTR*CommandLineToArgv(LPWSTRlpCmdLine, int*pNumArgs);

0 commit comments

Comments
(0)