Skip to content

Commit 830ff45

Browse files
topolarityKristofferC
authored andcommitted
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. (cherry picked from commit ac4ee59)
1 parent 4eb2556 commit 830ff45

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+
#define FLAG_ANY -1
22+
#define FLAG_TYPE_MASK 0x00ff
23+
#define FLAG_LIBC4 0x0000
24+
#define FLAG_ELF 0x0001
25+
#define FLAG_ELF_LIBC5 0x0002
26+
#define FLAG_ELF_LIBC6 0x0003
27+
#define FLAG_REQUIRED_MASK 0xff00
28+
#define FLAG_SPARC_LIB64 0x0100
29+
#define FLAG_IA64_LIB64 0x0200
30+
#define FLAG_X8664_LIB64 0x0300
31+
#define FLAG_S390_LIB64 0x0400
32+
#define FLAG_POWERPC_LIB64 0x0500
33+
#define FLAG_MIPS64_LIBN32 0x0600
34+
#define FLAG_MIPS64_LIBN64 0x0700
35+
#define FLAG_X8664_LIBX32 0x0800
36+
#define FLAG_ARM_LIBHF 0x0900
37+
#define FLAG_AARCH64_LIB64 0x0a00
38+
#define FLAG_ARM_LIBSF 0x0b00
39+
#define FLAG_MIPS_LIB32_NAN2008 0x0c00
40+
#define FLAG_MIPS64_LIBN32_NAN2008 0x0d00
41+
#define FLAG_MIPS64_LIBN64_NAN2008 0x0e00
42+
#define FLAG_RISCV_FLOAT_ABI_SOFT 0x0f00
43+
#define FLAG_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+
#ifndef LD_SO_CACHE
116+
# define LD_SO_CACHE SYSCONFDIR "/ld.so.cache"
117+
#endif
118+
119+
#define CACHEMAGIC "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+
struct file_entry
142+
{
143+
int flags; /* This is 1 for an ELF library. */
144+
unsigned int key, value; /* String table indices. */
145+
};
146+
147+
struct cache_file
148+
{
149+
char magic[sizeof CACHEMAGIC - 1];
150+
unsigned int nlibs;
151+
struct file_entry libs[0];
152+
};
153+
154+
#define CACHEMAGIC_NEW "glibc-ld.so.cache"
155+
#define CACHE_VERSION "1.1"
156+
#define CACHEMAGIC_VERSION_NEW CACHEMAGIC_NEW CACHE_VERSION
157+
158+
159+
struct file_entry_new
160+
{
161+
int32_t flags; /* This is 1 for an ELF library. */
162+
uint32_t key, value; /* String table indices. */
163+
uint32_t osversion; /* Required OS version. */
164+
uint64_t hwcap; /* Hwcap entry. */
165+
};
166+
167+
struct cache_file_new
168+
{
169+
char magic[sizeof CACHEMAGIC_NEW - 1];
170+
char version[sizeof CACHE_VERSION - 1];
171+
uint32_t nlibs; /* Number of entries. */
172+
uint32_t len_strings; /* Size of string table. */
173+
uint32_t unused[5]; /* Leave space for future extensions
174+
and align to 8 byte boundary. */
175+
struct file_entry_new libs[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+
#define ALIGN_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_DLLEXPORT extern int jl_load_repl(int, char **);
7171
JL_DLLEXPORT void jl_loader_print_stderr(const char * msg);
7272
void jl_loader_print_stderr3(const char * msg1, const char * msg2, const char * msg3);
73+
void *jl_loader_open_via_mmap(const char *filepath, size_t *size);
7374
static void * lookup_symbol(const void * lib_handle, const char * symbol_name);
75+
const char *jl_loader_probe_system_library(const char *libname, const char *symbol);
76+
int jl_loader_locate_symbol(const char *library, const char *symbol);
7477

7578
#ifdef _OS_WINDOWS_
7679
LPWSTR *CommandLineToArgv(LPWSTR lpCmdLine, int *pNumArgs);

0 commit comments

Comments
 (0)