From 742a3e60bdc06d650e7a641fa31aae14216bcc29 Mon Sep 17 00:00:00 2001 From: Gyeongjae Choi Date: Thu, 1 May 2025 10:37:32 +0000 Subject: [PATCH 01/13] Fix nested dependencies handling in rpath --- src/lib/libdylink.js | 5 ++++- test/test_other.py | 19 ++++++++++++++++--- 2 files changed, 20 insertions(+), 4 deletions(-) diff --git a/src/lib/libdylink.js b/src/lib/libdylink.js index b1e70178286f6..f5931218f5342 100644 --- a/src/lib/libdylink.js +++ b/src/lib/libdylink.js @@ -904,7 +904,8 @@ var LibraryDylink = { // We need to set rpath in flags based on the current library's rpath. // We can't mutate flags or else if a depends on b and c and b depends on d, // then c will be loaded with b's rpath instead of a's. - flags = {...flags, rpath: { parentLibPath: libName, paths: metadata.runtimePaths }} + var dso = LDSO.loadedLibsByName[libName]; + flags = {...flags, rpath: { parentLibPath: dso.path, paths: metadata.runtimePaths }} // now load needed libraries and the module itself. if (flags.loadAsync) { return metadata.neededDynlibs @@ -937,6 +938,7 @@ var LibraryDylink = { var dso = { refcount: Infinity, name, + path: name, // full path to the library, updated when the library is resolved in the filesystem. exports: syms, global: true, }; @@ -1105,6 +1107,7 @@ var LibraryDylink = { #endif if (f) { var libData = FS.readFile(f, {encoding: 'binary'}); + dso.path = f; return flags.loadAsync ? Promise.resolve(libData) : libData; } #endif diff --git a/test/test_other.py b/test/test_other.py index 2e0b3ad792370..7a1d7357589b0 100644 --- a/test/test_other.py +++ b/test/test_other.py @@ -7701,11 +7701,22 @@ def test_ld_library_path(self, args): @also_with_wasmfs def test_dlopen_rpath(self): + create_file('hello_nested_dep.c', r''' + #include + + void hello_nested_dep() { + printf("Hello_nested_dep\n"); + return; + } + ''') create_file('hello_dep.c', r''' #include + void hello_nested_dep(); + void hello_dep() { printf("Hello_dep\n"); + hello_nested_dep(); return; } ''') @@ -7747,20 +7758,22 @@ def test_dlopen_rpath(self): os.mkdir('subdir') def _build(rpath_flag, expected, **kwds): - self.run_process([EMCC, '-o', 'subdir/libhello_dep.so', 'hello_dep.c', '-sSIDE_MODULE']) + self.run_process([EMCC, '-o', 'subdir/libhello_nested_dep.so', 'hello_nested_dep.c', '-sSIDE_MODULE']) + self.run_process([EMCC, '-o', 'subdir/libhello_dep.so', 'hello_dep.c', '-sSIDE_MODULE', 'subdir/libhello_nested_dep.so'] + rpath_flag) self.run_process([EMCC, '-o', 'hello.wasm', 'hello.c', '-sSIDE_MODULE', 'subdir/libhello_dep.so'] + rpath_flag) args = ['--profiling-funcs', '-sMAIN_MODULE=2', '-sINITIAL_MEMORY=32Mb', '--embed-file', 'hello.wasm@/usr/lib/libhello.wasm', '--embed-file', 'subdir/libhello_dep.so@/usr/lib/subdir/libhello_dep.so', + '--embed-file', 'subdir/libhello_nested_dep.so@/usr/lib/subdir/libhello_nested_dep.so', 'hello.wasm', '-sNO_AUTOLOAD_DYLIBS', - '-L./subdir', '-lhello_dep'] + '-L./subdir', '-lhello_dep', '-lhello_nested_dep'] self.do_runf('main.c', expected, emcc_args=args, **kwds) # case 1) without rpath: fail to locate the library _build([], r"no such file or directory, open '.*libhello_dep\.so'", regex=True, assert_returncode=NON_ZERO) # case 2) with rpath: success - _build(['-Wl,-rpath,$ORIGIN/subdir'], "Hello\nHello_dep\nOk\n") + _build(['-Wl,-rpath,$ORIGIN/subdir,-rpath,$ORIGIN'], "Hello\nHello_dep\nHello_nested_dep\nOk\n") def test_dlopen_bad_flags(self): create_file('main.c', r''' From f1f85ffb68782810c3da1e046836c0bba9fa87dd Mon Sep 17 00:00:00 2001 From: Gyeongjae Choi Date: Thu, 1 May 2025 12:03:26 +0000 Subject: [PATCH 02/13] fallback --- src/lib/libdylink.js | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/lib/libdylink.js b/src/lib/libdylink.js index f5931218f5342..e29a704c7293b 100644 --- a/src/lib/libdylink.js +++ b/src/lib/libdylink.js @@ -905,7 +905,8 @@ var LibraryDylink = { // We can't mutate flags or else if a depends on b and c and b depends on d, // then c will be loaded with b's rpath instead of a's. var dso = LDSO.loadedLibsByName[libName]; - flags = {...flags, rpath: { parentLibPath: dso.path, paths: metadata.runtimePaths }} + var libPath = dso?.path ?? libName + flags = {...flags, rpath: { parentLibPath: libPath, paths: metadata.runtimePaths }} // now load needed libraries and the module itself. if (flags.loadAsync) { return metadata.neededDynlibs From 65f39d42355d5102cd1efae68a2461547ed709fe Mon Sep 17 00:00:00 2001 From: Gyeongjae Choi Date: Thu, 1 May 2025 12:03:42 +0000 Subject: [PATCH 03/13] syntax --- src/lib/libdylink.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/lib/libdylink.js b/src/lib/libdylink.js index e29a704c7293b..57beb0f53cbb3 100644 --- a/src/lib/libdylink.js +++ b/src/lib/libdylink.js @@ -905,7 +905,7 @@ var LibraryDylink = { // We can't mutate flags or else if a depends on b and c and b depends on d, // then c will be loaded with b's rpath instead of a's. var dso = LDSO.loadedLibsByName[libName]; - var libPath = dso?.path ?? libName + var libPath = dso?.path ?? libName; flags = {...flags, rpath: { parentLibPath: libPath, paths: metadata.runtimePaths }} // now load needed libraries and the module itself. if (flags.loadAsync) { From 8bc8fff4397781587b2075c17e02e5984cef74e9 Mon Sep 17 00:00:00 2001 From: Gyeongjae Choi Date: Thu, 1 May 2025 12:12:46 +0000 Subject: [PATCH 04/13] Automatic rebaseline of codesize expectations. NFC This is an automatic change generated by tools/maint/rebaseline_tests.py. The following (2) test expectation files were updated by running the tests with `--rebaseline`: ``` other/codesize/test_codesize_hello_dylink.gzsize: 11735 => 11758 [+23 bytes / +0.20%] other/codesize/test_codesize_hello_dylink.jssize: 27774 => 27799 [+25 bytes / +0.09%] Average change: +0.14% (+0.09% - +0.20%) ``` --- test/other/codesize/test_codesize_hello_dylink.gzsize | 2 +- test/other/codesize/test_codesize_hello_dylink.jssize | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/test/other/codesize/test_codesize_hello_dylink.gzsize b/test/other/codesize/test_codesize_hello_dylink.gzsize index a5755921eac44..ace24481f1d87 100644 --- a/test/other/codesize/test_codesize_hello_dylink.gzsize +++ b/test/other/codesize/test_codesize_hello_dylink.gzsize @@ -1 +1 @@ -11735 +11758 diff --git a/test/other/codesize/test_codesize_hello_dylink.jssize b/test/other/codesize/test_codesize_hello_dylink.jssize index c82e0d84da885..4e26f740d8b3f 100644 --- a/test/other/codesize/test_codesize_hello_dylink.jssize +++ b/test/other/codesize/test_codesize_hello_dylink.jssize @@ -1 +1 @@ -27774 +27799 From 62dc4a43072422b0c924dd354953e80cd7ab9243 Mon Sep 17 00:00:00 2001 From: Gyeongjae Choi Date: Fri, 2 May 2025 07:35:08 +0000 Subject: [PATCH 05/13] wasm ==> so --- test/test_other.py | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/test/test_other.py b/test/test_other.py index 7a1d7357589b0..bc81a7f274e63 100644 --- a/test/test_other.py +++ b/test/test_other.py @@ -7743,7 +7743,7 @@ def test_dlopen_rpath(self): void (*f)(); double (*f2)(double); - h = dlopen("/usr/lib/libhello.wasm", RTLD_NOW); + h = dlopen("/usr/lib/libhello.so", RTLD_NOW); assert(h); f = dlsym(h, "hello"); assert(f); @@ -7760,12 +7760,12 @@ def test_dlopen_rpath(self): def _build(rpath_flag, expected, **kwds): self.run_process([EMCC, '-o', 'subdir/libhello_nested_dep.so', 'hello_nested_dep.c', '-sSIDE_MODULE']) self.run_process([EMCC, '-o', 'subdir/libhello_dep.so', 'hello_dep.c', '-sSIDE_MODULE', 'subdir/libhello_nested_dep.so'] + rpath_flag) - self.run_process([EMCC, '-o', 'hello.wasm', 'hello.c', '-sSIDE_MODULE', 'subdir/libhello_dep.so'] + rpath_flag) + self.run_process([EMCC, '-o', 'hello.so', 'hello.c', '-sSIDE_MODULE', 'subdir/libhello_dep.so'] + rpath_flag) args = ['--profiling-funcs', '-sMAIN_MODULE=2', '-sINITIAL_MEMORY=32Mb', - '--embed-file', 'hello.wasm@/usr/lib/libhello.wasm', + '--embed-file', 'hello.so@/usr/lib/libhello.so', '--embed-file', 'subdir/libhello_dep.so@/usr/lib/subdir/libhello_dep.so', '--embed-file', 'subdir/libhello_nested_dep.so@/usr/lib/subdir/libhello_nested_dep.so', - 'hello.wasm', '-sNO_AUTOLOAD_DYLIBS', + 'hello.so', '-sNO_AUTOLOAD_DYLIBS', '-L./subdir', '-lhello_dep', '-lhello_nested_dep'] self.do_runf('main.c', expected, emcc_args=args, **kwds) From 81b1dbdd0503f3a7d2a9a69fb9ffc7372e70e069 Mon Sep 17 00:00:00 2001 From: Gyeongjae Choi Date: Fri, 2 May 2025 07:35:33 +0000 Subject: [PATCH 06/13] Always pass absolute path in loadDynamicLibrary --- src/lib/libdylink.js | 21 +++++++++++++-------- 1 file changed, 13 insertions(+), 8 deletions(-) diff --git a/src/lib/libdylink.js b/src/lib/libdylink.js index 57beb0f53cbb3..8eca0c229c92b 100644 --- a/src/lib/libdylink.js +++ b/src/lib/libdylink.js @@ -904,19 +904,25 @@ var LibraryDylink = { // We need to set rpath in flags based on the current library's rpath. // We can't mutate flags or else if a depends on b and c and b depends on d, // then c will be loaded with b's rpath instead of a's. - var dso = LDSO.loadedLibsByName[libName]; - var libPath = dso?.path ?? libName; - flags = {...flags, rpath: { parentLibPath: libPath, paths: metadata.runtimePaths }} + flags = {...flags, rpath: { parentLibPath: libName, paths: metadata.runtimePaths }} // now load needed libraries and the module itself. if (flags.loadAsync) { return metadata.neededDynlibs - .reduce((chain, dynNeeded) => chain.then(() => - loadDynamicLibrary(dynNeeded, flags, localScope) - ), Promise.resolve()) + .reduce((chain, needed) => chain.then(() => { +#if FILESYSTEM + needed = findLibraryFS(needed, flags.rpath) ?? needed; +#endif + return loadDynamicLibrary(needed, flags, localScope); + }), Promise.resolve()) .then(loadModule); } - metadata.neededDynlibs.forEach((needed) => loadDynamicLibrary(needed, flags, localScope)); + metadata.neededDynlibs.forEach((needed) => { +#if FILESYSTEM + needed = findLibraryFS(needed, flags.rpath) ?? needed; +#endif + return loadDynamicLibrary(needed, flags, localScope); + }); return loadModule(); }, @@ -939,7 +945,6 @@ var LibraryDylink = { var dso = { refcount: Infinity, name, - path: name, // full path to the library, updated when the library is resolved in the filesystem. exports: syms, global: true, }; From f4e3b254a04e002ccde2a813201d8124527825cf Mon Sep 17 00:00:00 2001 From: Gyeongjae Choi Date: Fri, 2 May 2025 07:36:59 +0000 Subject: [PATCH 07/13] Remove unnecessary changes --- src/lib/libdylink.js | 1 - 1 file changed, 1 deletion(-) diff --git a/src/lib/libdylink.js b/src/lib/libdylink.js index 8eca0c229c92b..c5860f86d5963 100644 --- a/src/lib/libdylink.js +++ b/src/lib/libdylink.js @@ -1113,7 +1113,6 @@ var LibraryDylink = { #endif if (f) { var libData = FS.readFile(f, {encoding: 'binary'}); - dso.path = f; return flags.loadAsync ? Promise.resolve(libData) : libData; } #endif From 8d925656da41c53bd3c6fdb76a3117b9234d3b0a Mon Sep 17 00:00:00 2001 From: Gyeongjae Choi Date: Fri, 2 May 2025 07:43:08 +0000 Subject: [PATCH 08/13] Automatic rebaseline of codesize expectations. NFC This is an automatic change generated by tools/maint/rebaseline_tests.py. The following (2) test expectation files were updated by running the tests with `--rebaseline`: ``` other/codesize/test_codesize_hello_dylink.gzsize: 11758 => 11757 [-1 bytes / -0.01%] other/codesize/test_codesize_hello_dylink.jssize: 27799 => 27823 [+24 bytes / +0.09%] Average change: +0.04% (-0.01% - +0.09%) ``` --- test/other/codesize/test_codesize_hello_dylink.gzsize | 2 +- test/other/codesize/test_codesize_hello_dylink.jssize | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/test/other/codesize/test_codesize_hello_dylink.gzsize b/test/other/codesize/test_codesize_hello_dylink.gzsize index ace24481f1d87..39b0cf833d17c 100644 --- a/test/other/codesize/test_codesize_hello_dylink.gzsize +++ b/test/other/codesize/test_codesize_hello_dylink.gzsize @@ -1 +1 @@ -11758 +11757 diff --git a/test/other/codesize/test_codesize_hello_dylink.jssize b/test/other/codesize/test_codesize_hello_dylink.jssize index 4e26f740d8b3f..9e19cdf0c05e0 100644 --- a/test/other/codesize/test_codesize_hello_dylink.jssize +++ b/test/other/codesize/test_codesize_hello_dylink.jssize @@ -1 +1 @@ -27799 +27823 From af365413d32195c8da7dc55b2af45938c02ad62c Mon Sep 17 00:00:00 2001 From: Gyeongjae Choi Date: Sat, 31 May 2025 13:25:12 +0000 Subject: [PATCH 09/13] Store filename only --- src/lib/libdylink.js | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/src/lib/libdylink.js b/src/lib/libdylink.js index 987b742f9cd64..e3fb9ca63f234 100644 --- a/src/lib/libdylink.js +++ b/src/lib/libdylink.js @@ -1049,7 +1049,10 @@ var LibraryDylink = { // when loadDynamicLibrary did not have flags, libraries were loaded // globally & permanently - var dso = LDSO.loadedLibsByName[libName]; + // Extract the filename part if libName is an absolute path + // This is to avoid problem when the same library is loaded from multiple folders. + var basename = libName.split('/').pop(); + var dso = LDSO.loadedLibsByName[basename]; if (dso) { // the library is being loaded or has been loaded already. #if ASSERTIONS @@ -1080,7 +1083,7 @@ var LibraryDylink = { } // allocate new DSO - dso = newDSO(libName, handle, 'loading'); + dso = newDSO(basename, handle, 'loading'); dso.refcount = flags.nodelete ? Infinity : 1; dso.global = flags.global; From f4fecbb3934ddf23929cb43f5fa14f1833716f77 Mon Sep 17 00:00:00 2001 From: Gyeongjae Choi Date: Sun, 1 Jun 2025 15:11:51 +0000 Subject: [PATCH 10/13] Revert "Store filename only" This reverts commit af365413d32195c8da7dc55b2af45938c02ad62c. --- src/lib/libdylink.js | 7 ++----- 1 file changed, 2 insertions(+), 5 deletions(-) diff --git a/src/lib/libdylink.js b/src/lib/libdylink.js index e3fb9ca63f234..987b742f9cd64 100644 --- a/src/lib/libdylink.js +++ b/src/lib/libdylink.js @@ -1049,10 +1049,7 @@ var LibraryDylink = { // when loadDynamicLibrary did not have flags, libraries were loaded // globally & permanently - // Extract the filename part if libName is an absolute path - // This is to avoid problem when the same library is loaded from multiple folders. - var basename = libName.split('/').pop(); - var dso = LDSO.loadedLibsByName[basename]; + var dso = LDSO.loadedLibsByName[libName]; if (dso) { // the library is being loaded or has been loaded already. #if ASSERTIONS @@ -1083,7 +1080,7 @@ var LibraryDylink = { } // allocate new DSO - dso = newDSO(basename, handle, 'loading'); + dso = newDSO(libName, handle, 'loading'); dso.refcount = flags.nodelete ? Infinity : 1; dso.global = flags.global; From b86e1f055952c5ef8cd305cf360110cabc60d266 Mon Sep 17 00:00:00 2001 From: Gyeongjae Choi Date: Sun, 1 Jun 2025 15:32:29 +0000 Subject: [PATCH 11/13] Fix codesize --- test/other/codesize/test_codesize_hello_dylink.gzsize | 2 +- test/other/codesize/test_codesize_hello_dylink.jssize | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/test/other/codesize/test_codesize_hello_dylink.gzsize b/test/other/codesize/test_codesize_hello_dylink.gzsize index 24d09039ee101..c32c6049908ed 100644 --- a/test/other/codesize/test_codesize_hello_dylink.gzsize +++ b/test/other/codesize/test_codesize_hello_dylink.gzsize @@ -1 +1 @@ -11676 +11696 diff --git a/test/other/codesize/test_codesize_hello_dylink.jssize b/test/other/codesize/test_codesize_hello_dylink.jssize index 0f1f70f75a5f6..f95e9327160ee 100644 --- a/test/other/codesize/test_codesize_hello_dylink.jssize +++ b/test/other/codesize/test_codesize_hello_dylink.jssize @@ -1 +1 @@ -27564 +27613 From 12f094a9270fb84573c655faa7d75cc3cf539820 Mon Sep 17 00:00:00 2001 From: ryanking13 Date: Sat, 8 Nov 2025 18:35:21 +0900 Subject: [PATCH 12/13] rebaseline --- test/codesize/test_codesize_hello_dylink.json | 2 +- test/codesize/test_codesize_hello_dylink_all.json | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/test/codesize/test_codesize_hello_dylink.json b/test/codesize/test_codesize_hello_dylink.json index ca963a0cb05fa..29e6f3f9d2aaf 100644 --- a/test/codesize/test_codesize_hello_dylink.json +++ b/test/codesize/test_codesize_hello_dylink.json @@ -3,7 +3,7 @@ "a.out.js.gz": 11345, "a.out.nodebug.wasm": 17757, "a.out.nodebug.wasm.gz": 8972, - "total": 44309, + "total": 44349, "total_gz": 20317, "sent": [ "__syscall_stat64", diff --git a/test/codesize/test_codesize_hello_dylink_all.json b/test/codesize/test_codesize_hello_dylink_all.json index 0d1f74f824ac2..7ead98b0d78ae 100644 --- a/test/codesize/test_codesize_hello_dylink_all.json +++ b/test/codesize/test_codesize_hello_dylink_all.json @@ -1,7 +1,7 @@ { "a.out.js": 245483, "a.out.nodebug.wasm": 574042, - "total": 819525, + "total": 819566, "sent": [ "IMG_Init", "IMG_Load", From ee7070d5aa8a83dd2ec04088e45dc81c9e1a3343 Mon Sep 17 00:00:00 2001 From: ryanking13 Date: Sat, 8 Nov 2025 18:59:42 +0900 Subject: [PATCH 13/13] Automatic rebaseline of codesize expectations. NFC This is an automatic change generated by tools/maint/rebaseline_tests.py. The following (2) test expectation files were updated by running the tests with `--rebaseline`: ``` codesize/test_codesize_hello_dylink.json: 44349 => 44349 [+0 bytes / +0.00%] codesize/test_codesize_hello_dylink_all.json: 819566 => 819566 [+0 bytes / +0.00%] Average change: +0.00% (+0.00% - +0.00%) ``` --- test/codesize/test_codesize_hello_dylink.json | 6 +++--- test/codesize/test_codesize_hello_dylink_all.json | 2 +- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/test/codesize/test_codesize_hello_dylink.json b/test/codesize/test_codesize_hello_dylink.json index 29e6f3f9d2aaf..78061e2d6e97e 100644 --- a/test/codesize/test_codesize_hello_dylink.json +++ b/test/codesize/test_codesize_hello_dylink.json @@ -1,10 +1,10 @@ { - "a.out.js": 26552, - "a.out.js.gz": 11345, + "a.out.js": 26592, + "a.out.js.gz": 11362, "a.out.nodebug.wasm": 17757, "a.out.nodebug.wasm.gz": 8972, "total": 44349, - "total_gz": 20317, + "total_gz": 20334, "sent": [ "__syscall_stat64", "emscripten_resize_heap", diff --git a/test/codesize/test_codesize_hello_dylink_all.json b/test/codesize/test_codesize_hello_dylink_all.json index 7ead98b0d78ae..5ba64ae9ce9e7 100644 --- a/test/codesize/test_codesize_hello_dylink_all.json +++ b/test/codesize/test_codesize_hello_dylink_all.json @@ -1,5 +1,5 @@ { - "a.out.js": 245483, + "a.out.js": 245524, "a.out.nodebug.wasm": 574042, "total": 819566, "sent": [