From 34144634026c91a73bd3e1db85627132d3a37a6d Mon Sep 17 00:00:00 2001 From: Hood Chatham Date: Fri, 18 Oct 2024 11:21:01 +0200 Subject: [PATCH 1/2] Drop explicitly passed -lc unless -nodefaultlibs or similar is passed There have been a lot of bugs when the caller passes `-lc` over the years. For example it crashes if we do: ``` emcc -lc -sDISABLE_EXCEPTION_CATCHING=0 -sMIN_SAFARI_VERSION=150000 ``` Rust likes to pass `-lc`. Let's drop it and stop causing trouble for Rust. Resolves #22758, #22742 and would have resolved #16680 if it hadn't disappeared first. --- test/test_other.py | 3 +++ tools/link.py | 16 ++++++++++++---- 2 files changed, 15 insertions(+), 4 deletions(-) diff --git a/test/test_other.py b/test/test_other.py index f8ee4f1281f2..a6538e41fd77 100644 --- a/test/test_other.py +++ b/test/test_other.py @@ -15169,3 +15169,6 @@ def test_fp16(self, opts): def test_embool(self): self.do_other_test('test_embool.c') + + def test_user_passed_lc(self): + self.run_process([EMCC, '-lc', '-sDISABLE_EXCEPTION_CATCHING=0', '-sMIN_SAFARI_VERSION=150000']) diff --git a/tools/link.py b/tools/link.py index 22a8b7494fb0..63d8f8f42c0d 100644 --- a/tools/link.py +++ b/tools/link.py @@ -2749,7 +2749,7 @@ def map_to_js_libs(library_name): return None -def process_libraries(state, linker_inputs): +def process_libraries(state, linker_inputs, nodefaultlibc): new_flags = [] libraries = [] suffixes = STATICLIB_ENDINGS + DYNAMICLIB_ENDINGS @@ -2761,6 +2761,12 @@ def process_libraries(state, linker_inputs): new_flags.append((i, flag)) continue lib = removeprefix(flag, '-l') + if lib == 'c' and not nodefaultlibc: + # Drop explicitly passed -lc unless they also passed -nodefaultlibs or + # similar. It's important to link libc after our other injected system + # libraries like libbulkmemory, but user linked libraries go ahead of + # system libraries, so if the user passes `-lc` then we can get crashes. + continue logger.debug('looking for library "%s"', lib) @@ -3026,12 +3032,12 @@ def package_files(options, target): @ToolchainProfiler.profile_block('calculate linker inputs') -def phase_calculate_linker_inputs(options, state, linker_inputs): +def phase_calculate_linker_inputs(options, state, linker_inputs, nodefaultlibc): using_lld = not (options.oformat == OFormat.OBJECT and settings.LTO) state.link_flags = filter_link_flags(state.link_flags, using_lld) # Decide what we will link - process_libraries(state, linker_inputs) + process_libraries(state, linker_inputs, nodefaultlibc) # Interleave the linker inputs with the linker flags while maintainging their # relative order on the command line (both of these list are pairs, with the @@ -3072,8 +3078,10 @@ def run(linker_inputs, options, state, newargs): target, wasm_target = phase_linker_setup(options, state, newargs) + nodefaultlibc = '-nodefaultlibs' in newargs or '-nolibc' in newargs or '-nostdlib' in newargs + # Link object files using wasm-ld or llvm-link (for bitcode linking) - linker_arguments = phase_calculate_linker_inputs(options, state, linker_inputs) + linker_arguments = phase_calculate_linker_inputs(options, state, linker_inputs, nodefaultlibc) # Embed and preload files if len(options.preload_files) or len(options.embed_files): From a4b1f72adc7e1480ae9b2f13ddc9e10c2b346e7d Mon Sep 17 00:00:00 2001 From: Hood Chatham Date: Fri, 18 Oct 2024 22:17:22 +0200 Subject: [PATCH 2/2] Update test, add warning --- test/test_other.py | 5 ++++- tools/link.py | 1 + 2 files changed, 5 insertions(+), 1 deletion(-) diff --git a/test/test_other.py b/test/test_other.py index a6538e41fd77..160645e7b69c 100644 --- a/test/test_other.py +++ b/test/test_other.py @@ -15171,4 +15171,7 @@ def test_embool(self): self.do_other_test('test_embool.c') def test_user_passed_lc(self): - self.run_process([EMCC, '-lc', '-sDISABLE_EXCEPTION_CATCHING=0', '-sMIN_SAFARI_VERSION=150000']) + # Outputs warning: + # em++: warning: ignoring explicitly passed -lc, if you want to control how libc is linked, pass -nolibc or -nostdlib + self.emcc_args.remove('-Werror') + self.do_runf(test_file('hello_world.cpp'), 'hello, world!\n', emcc_args=['-lc', '-sDISABLE_EXCEPTION_CATCHING=0', '-sMIN_SAFARI_VERSION=150000']) diff --git a/tools/link.py b/tools/link.py index 63d8f8f42c0d..e87ea217820e 100644 --- a/tools/link.py +++ b/tools/link.py @@ -2766,6 +2766,7 @@ def process_libraries(state, linker_inputs, nodefaultlibc): # similar. It's important to link libc after our other injected system # libraries like libbulkmemory, but user linked libraries go ahead of # system libraries, so if the user passes `-lc` then we can get crashes. + diagnostics.warning('emcc', 'ignoring explicitly passed -lc, if you want to control how libc is linked, pass -nolibc or -nostdlib') continue logger.debug('looking for library "%s"', lib)