├── .dockerignore ├── tests ├── tls-lib-gcc │ ├── answer │ │ └── .gitkeep │ ├── original │ │ └── .gitkeep │ ├── sold_out │ │ └── .gitkeep │ ├── lib.h │ ├── base.c │ ├── base.h │ ├── lib.c │ ├── main.c │ └── test.sh ├── renamer │ ├── mapping │ ├── hoge.c │ ├── fugafuga.c │ ├── .gitignore │ ├── use_fugafuga.c │ └── test.sh ├── tls-lib-gcc-aarch64 │ ├── answer │ │ └── .gitkeep │ ├── original │ │ └── .gitkeep │ ├── sold_out │ │ └── .gitkeep │ ├── lib.h │ ├── base.c │ ├── base.h │ ├── lib.c │ ├── main.c │ └── test.sh ├── tls-multiple-lib-gcc │ ├── answer │ │ └── .gitkeep │ ├── original │ │ └── .gitkeep │ ├── sold_out │ │ └── .gitkeep │ ├── base.c │ ├── base.h │ ├── base2.c │ ├── base2.h │ ├── lib.h │ ├── lib.c │ ├── main.c │ └── test.sh ├── tls-lib-gcc-without-base │ ├── original │ │ └── .gitkeep │ ├── sold_out │ │ └── .gitkeep │ ├── lib.h │ ├── base.h │ ├── base.c │ ├── lib.c │ ├── main.c │ └── test.sh ├── typeid-g++ │ ├── lib.h │ ├── .gitignore │ ├── main.cc │ ├── test.sh │ └── lib.cc ├── dynamic_cast-g++ │ ├── lib.h │ ├── .gitignore │ ├── main.cc │ ├── lib.cc │ └── test.sh ├── hello-g++ │ ├── .gitignore │ ├── hello.cc │ └── test.sh ├── mprotect │ ├── base.h │ ├── mprotect_check.h │ ├── base.c │ ├── main.c │ ├── .gitignore │ ├── mprotect_check.c │ └── test.sh ├── static-in-function-g++ │ ├── lib.h │ ├── .gitignore │ ├── lib.cc │ ├── main.cc │ └── test.sh ├── tls-multiple-lib-gcc-aarch64 │ ├── answer │ │ └── .gitkeep │ ├── original │ │ └── .gitkeep │ ├── base.c │ ├── base.h │ ├── base2.c │ ├── base2.h │ ├── lib.h │ ├── lib.c │ ├── main.c │ └── test.sh ├── hello-g++-aarch64 │ ├── .gitignore │ ├── hello.cc │ └── test.sh ├── inheritance-g++ │ ├── .gitignore │ ├── lib.h │ ├── test.sh │ ├── lib.cc │ └── main.cc ├── just-return-gcc │ ├── .gitignore │ ├── return.c │ └── test.sh ├── mprotect-aarch64 │ ├── base.h │ ├── mprotect_check.h │ ├── base.c │ ├── main.c │ ├── .gitignore │ ├── mprotect_check.c │ └── test.sh ├── simple-lib-g++ │ ├── libmax.h │ ├── .gitignore │ ├── libmax.cc │ ├── main.cc │ └── test.sh ├── static-in-function-g++-aarch64 │ ├── lib.h │ ├── .gitignore │ ├── lib.cc │ ├── main.cc │ └── test.sh ├── tls-lib-gcc-without-base-aarch64 │ ├── original │ │ └── .gitkeep │ ├── sold_out │ │ └── .gitkeep │ ├── lib.h │ ├── base.h │ ├── base.c │ ├── lib.c │ ├── main.c │ └── test.sh ├── typeid-g++-aarch64 │ ├── lib.h │ ├── .gitignore │ ├── main.cc │ ├── fuga.h │ ├── lib.cc │ └── test.sh ├── dynamic_cast-g++-aarch64 │ ├── lib.h │ ├── .gitignore │ ├── main.cc │ ├── lib.cc │ └── test.sh ├── hello-gcc │ ├── .gitignore │ ├── hello.c │ └── test.sh ├── simple-lib-gcc │ ├── libmax.h │ ├── .gitignore │ ├── libmax.c │ ├── main.c │ └── test.sh ├── version-gcc │ ├── libmax1.h │ ├── libmax2.h │ ├── libmax1.c │ ├── .gitignore │ ├── vertest1.c │ ├── vertest2.c │ ├── libmax2.def │ ├── libmax2.c │ └── test.sh ├── inheritance-g++-aarch64 │ ├── .gitignore │ ├── lib.h │ ├── lib.cc │ ├── test.sh │ └── main.cc ├── simple-lib-g++-aarch64 │ ├── libmax.h │ ├── .gitignore │ ├── libmax.cc │ ├── main.cc │ └── test.sh ├── global-write-aarch64 │ ├── hoge.c │ ├── main.c │ └── test.sh ├── just-return-g++ │ ├── return.cc │ └── test.sh ├── simple-lib-gcc-aarch64 │ ├── libmax.h │ ├── .gitignore │ ├── libmax.c │ ├── main.c │ └── test.sh ├── version-gcc-aarch64 │ ├── libmax1.h │ ├── libmax2.h │ ├── libmax1.c │ ├── .gitignore │ ├── vertest1.c │ ├── vertest2.c │ ├── libmax2.def │ ├── libmax2.c │ └── test.sh ├── tls-thread-g++ │ ├── lib.h │ ├── .gitignore │ ├── lib.cc │ ├── test.sh │ └── main.cc ├── just-return-g++-aarch64 │ ├── return.cc │ └── test.sh ├── just-return-gcc-aarch64 │ ├── return.c │ ├── .gitignore │ └── test.sh ├── tls-thread-g++-aarch64 │ ├── lib.h │ ├── .gitignore │ ├── lib.cc │ ├── main.cc │ └── test.sh ├── call_once-g++ │ ├── main.cc │ ├── .gitignore │ ├── hoge.cc │ ├── fuga.cc │ └── test.sh ├── tls-conflict-aarch64 │ ├── fuga.cc │ ├── hoge.cc │ ├── main.cc │ └── test.sh ├── unique_ptr-aarch64 │ ├── main.cc │ ├── .gitignore │ ├── hoge.cc │ └── test.sh ├── call_once-g++-aarch64 │ ├── main.cc │ ├── .gitignore │ ├── hoge.cc │ ├── fuga.cc │ └── test.sh ├── setjmp-gcc │ ├── .gitignore │ ├── hoge.h │ ├── main.c │ ├── test.sh │ └── hoge.c ├── stb_gnu_unique_tls │ ├── main.cc │ ├── .gitignore │ ├── test.sh │ └── unique.cc ├── tls-dlopen-gcc │ ├── .gitignore │ ├── lib.c │ ├── test.sh │ └── main.c ├── tls-dlopen-gcc-aarch64 │ ├── .gitignore │ ├── lib.c │ ├── test.sh │ └── main.c ├── setjmp-gcc-aarch64 │ ├── .gitignore │ ├── hoge.h │ ├── main.c │ ├── hoge.c │ └── test.sh ├── stb_gnu_unique_tls-aarch64 │ ├── main.cc │ ├── .gitignore │ ├── test.sh │ └── unique.cc ├── hello-gcc-aarch64 │ ├── hello.c │ └── test.sh ├── tls-multiple-module-g++ │ ├── .gitignore │ ├── fuga.h │ ├── hoge.h │ ├── fuga.cc │ ├── hoge.cc │ ├── test.sh │ ├── fugahoge.cc │ └── main.cc ├── tls-multiple-module-g++-aarch64 │ ├── .gitignore │ ├── fuga.h │ ├── hoge.h │ ├── fuga.cc │ ├── hoge.cc │ ├── test.sh │ ├── fugahoge.cc │ └── main.cc ├── static-in-class-g++ │ ├── main.cc │ ├── lib.cc │ ├── lib.h │ └── test.sh ├── static-in-class-g++-aarch64 │ ├── main.cc │ ├── lib.cc │ ├── lib.h │ └── test.sh ├── tls-bss-g++ │ ├── test.sh │ └── main.cc ├── tls-gcc │ ├── test.sh │ └── main.c ├── exception-g++ │ ├── fuga.h │ ├── hoge.h │ ├── fuga.cc │ ├── main.cc │ ├── hoge.cc │ └── test.sh ├── exception-g++-aarch64 │ ├── fuga.h │ ├── hoge.h │ ├── fuga.cc │ ├── main.cc │ ├── hoge.cc │ └── test.sh ├── exception-str-g++-aarch64 │ ├── fuga.h │ ├── hoge.h │ ├── main.cc │ ├── fuga.cc │ ├── hoge.cc │ └── test.sh ├── tls-bss-gcc │ ├── test.sh │ └── main.c ├── tls-bss-gcc-aarch64 │ ├── main.c │ └── test.sh ├── tls-bss-g++-aarch64 │ ├── main.cc │ └── test.sh ├── tls-gcc-aarch64 │ ├── test.sh │ └── main.c ├── runtest.sh ├── base.h ├── lib.h ├── CMakeLists.txt ├── exe.cc ├── base.cc ├── lib.cc └── run-all-tests.sh ├── libtorch_test ├── torch_test.h ├── torch_test_main.cc ├── torch_test_main_dlopen.cc ├── torch_test.cc └── CMakeLists.txt ├── .gitignore ├── CTestCustom.cmake ├── .clang-format ├── run-format.sh ├── pybind_test ├── README.md ├── add.cc ├── numpy.cc ├── test_soldout_modules.py ├── CMakeLists.txt └── object.cc ├── fedora-latest.Dockerfile ├── tools ├── search-symbol.sh ├── relocation-list-up.sh ├── listup_duplicated_syms.py ├── tracer.cc ├── resolve_addr.py └── raw_write.h ├── third_party ├── glog.cmake └── pybind11.cmake ├── ubuntu18.04.Dockerfile ├── ubuntu20.04.Dockerfile ├── .github └── workflows │ └── build.yml ├── ldsoconf.h ├── cmake └── third-party.cmake ├── hash.cc ├── print_tls.cc ├── print_dtrela.cc ├── print_version.cc ├── print_ehframe.cc ├── strtab_builder.h ├── hash.h ├── strtab_builder.cc ├── print_dynsymtab.cc ├── version_builder.h ├── ldsoconf.cc ├── shdr_builder.h ├── symtab_builder.h ├── CMakeLists.txt ├── README.md ├── ehframe_builder.h ├── mprotect_builder.cc ├── mprotect_builder.h ├── version_builder.cc ├── sold_main.cc ├── shdr_builder.cc └── elf_binary.h /.dockerignore: -------------------------------------------------------------------------------- 1 | build 2 | -------------------------------------------------------------------------------- /tests/tls-lib-gcc/answer/.gitkeep: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /tests/tls-lib-gcc/original/.gitkeep: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /tests/tls-lib-gcc/sold_out/.gitkeep: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /tests/renamer/mapping: -------------------------------------------------------------------------------- 1 | hoge fugafuga 2 | -------------------------------------------------------------------------------- /tests/tls-lib-gcc-aarch64/answer/.gitkeep: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /tests/tls-lib-gcc-aarch64/original/.gitkeep: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /tests/tls-lib-gcc-aarch64/sold_out/.gitkeep: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /tests/tls-multiple-lib-gcc/answer/.gitkeep: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /tests/tls-lib-gcc-without-base/original/.gitkeep: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /tests/tls-lib-gcc-without-base/sold_out/.gitkeep: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /tests/tls-multiple-lib-gcc/original/.gitkeep: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /tests/tls-multiple-lib-gcc/sold_out/.gitkeep: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /tests/typeid-g++/lib.h: -------------------------------------------------------------------------------- 1 | void PrintTypeid(); 2 | -------------------------------------------------------------------------------- /tests/dynamic_cast-g++/lib.h: -------------------------------------------------------------------------------- 1 | void TryDowncast(); 2 | -------------------------------------------------------------------------------- /tests/hello-g++/.gitignore: -------------------------------------------------------------------------------- 1 | hello 2 | hello.out 3 | -------------------------------------------------------------------------------- /tests/mprotect/base.h: -------------------------------------------------------------------------------- 1 | int func(int a, int b); 2 | -------------------------------------------------------------------------------- /tests/mprotect/mprotect_check.h: -------------------------------------------------------------------------------- 1 | void check(); 2 | -------------------------------------------------------------------------------- /tests/static-in-function-g++/lib.h: -------------------------------------------------------------------------------- 1 | int func(); 2 | -------------------------------------------------------------------------------- /tests/tls-multiple-lib-gcc-aarch64/answer/.gitkeep: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /tests/tls-multiple-lib-gcc-aarch64/original/.gitkeep: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /libtorch_test/torch_test.h: -------------------------------------------------------------------------------- 1 | extern "C" void test(); 2 | -------------------------------------------------------------------------------- /tests/hello-g++-aarch64/.gitignore: -------------------------------------------------------------------------------- 1 | hello 2 | hello.out 3 | -------------------------------------------------------------------------------- /tests/inheritance-g++/.gitignore: -------------------------------------------------------------------------------- 1 | hello 2 | hello.out 3 | -------------------------------------------------------------------------------- /tests/just-return-gcc/.gitignore: -------------------------------------------------------------------------------- 1 | return.c 2 | test.sh 3 | -------------------------------------------------------------------------------- /tests/mprotect-aarch64/base.h: -------------------------------------------------------------------------------- 1 | int func(int a, int b); 2 | -------------------------------------------------------------------------------- /tests/mprotect-aarch64/mprotect_check.h: -------------------------------------------------------------------------------- 1 | void check(); 2 | -------------------------------------------------------------------------------- /tests/simple-lib-g++/libmax.h: -------------------------------------------------------------------------------- 1 | int max(int a, int b); 2 | -------------------------------------------------------------------------------- /tests/static-in-function-g++-aarch64/lib.h: -------------------------------------------------------------------------------- 1 | int func(); 2 | -------------------------------------------------------------------------------- /tests/tls-lib-gcc-without-base-aarch64/original/.gitkeep: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /tests/tls-lib-gcc-without-base-aarch64/sold_out/.gitkeep: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /tests/typeid-g++-aarch64/lib.h: -------------------------------------------------------------------------------- 1 | void PrintTypeid(); 2 | -------------------------------------------------------------------------------- /tests/dynamic_cast-g++-aarch64/lib.h: -------------------------------------------------------------------------------- 1 | void TryDowncast(); 2 | -------------------------------------------------------------------------------- /tests/hello-gcc/.gitignore: -------------------------------------------------------------------------------- 1 | hello 2 | hello.out 3 | test.sh 4 | -------------------------------------------------------------------------------- /tests/simple-lib-gcc/libmax.h: -------------------------------------------------------------------------------- 1 | extern int max(int a, int b); 2 | -------------------------------------------------------------------------------- /tests/tls-lib-gcc-without-base/lib.h: -------------------------------------------------------------------------------- 1 | int return_tls_i(); 2 | -------------------------------------------------------------------------------- /tests/version-gcc/libmax1.h: -------------------------------------------------------------------------------- 1 | extern int max(int a, int b); 2 | -------------------------------------------------------------------------------- /tests/inheritance-g++-aarch64/.gitignore: -------------------------------------------------------------------------------- 1 | hello 2 | hello.out 3 | -------------------------------------------------------------------------------- /tests/simple-lib-g++-aarch64/libmax.h: -------------------------------------------------------------------------------- 1 | int max(int a, int b); 2 | -------------------------------------------------------------------------------- /tests/simple-lib-g++/.gitignore: -------------------------------------------------------------------------------- 1 | libmax.o 2 | libmax.so 3 | main 4 | -------------------------------------------------------------------------------- /tests/simple-lib-gcc/.gitignore: -------------------------------------------------------------------------------- 1 | libmax.o 2 | libmax.so 3 | main 4 | -------------------------------------------------------------------------------- /tests/tls-lib-gcc-without-base-aarch64/lib.h: -------------------------------------------------------------------------------- 1 | int return_tls_i(); 2 | -------------------------------------------------------------------------------- /tests/version-gcc/libmax2.h: -------------------------------------------------------------------------------- 1 | extern int max(int a, int b, int c); 2 | -------------------------------------------------------------------------------- /tests/global-write-aarch64/hoge.c: -------------------------------------------------------------------------------- 1 | int hoge; 2 | __thread int hoge_th; 3 | -------------------------------------------------------------------------------- /tests/just-return-g++/return.cc: -------------------------------------------------------------------------------- 1 | int main() { 2 | return 0; 3 | } 4 | -------------------------------------------------------------------------------- /tests/just-return-gcc/return.c: -------------------------------------------------------------------------------- 1 | int main() { 2 | return 0; 3 | } 4 | -------------------------------------------------------------------------------- /tests/simple-lib-gcc-aarch64/libmax.h: -------------------------------------------------------------------------------- 1 | extern int max(int a, int b); 2 | -------------------------------------------------------------------------------- /tests/tls-multiple-lib-gcc/base.c: -------------------------------------------------------------------------------- 1 | __thread int thread_local_i = 3; 2 | -------------------------------------------------------------------------------- /tests/tls-multiple-lib-gcc/base.h: -------------------------------------------------------------------------------- 1 | extern __thread int thread_local_i; 2 | -------------------------------------------------------------------------------- /tests/tls-multiple-lib-gcc/base2.c: -------------------------------------------------------------------------------- 1 | __thread int thread_local_j = 100; 2 | -------------------------------------------------------------------------------- /tests/version-gcc-aarch64/libmax1.h: -------------------------------------------------------------------------------- 1 | extern int max(int a, int b); 2 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | /build 2 | *.so 3 | *.original 4 | *.soldout 5 | *.o 6 | *.out 7 | -------------------------------------------------------------------------------- /tests/renamer/hoge.c: -------------------------------------------------------------------------------- 1 | int hoge(int a, int b) { 2 | return a + b; 3 | } 4 | -------------------------------------------------------------------------------- /tests/simple-lib-g++-aarch64/.gitignore: -------------------------------------------------------------------------------- 1 | libmax.o 2 | libmax.so 3 | main 4 | -------------------------------------------------------------------------------- /tests/simple-lib-gcc-aarch64/.gitignore: -------------------------------------------------------------------------------- 1 | libmax.o 2 | libmax.so 3 | main 4 | -------------------------------------------------------------------------------- /tests/tls-lib-gcc-without-base/base.h: -------------------------------------------------------------------------------- 1 | extern __thread int thread_local_i; 2 | -------------------------------------------------------------------------------- /tests/tls-lib-gcc/lib.h: -------------------------------------------------------------------------------- 1 | #include "base.h" 2 | 3 | int return_tls_i(); 4 | -------------------------------------------------------------------------------- /tests/tls-multiple-lib-gcc-aarch64/base.c: -------------------------------------------------------------------------------- 1 | __thread int thread_local_i = 3; 2 | -------------------------------------------------------------------------------- /tests/tls-multiple-lib-gcc/base2.h: -------------------------------------------------------------------------------- 1 | extern __thread int thread_local_j; 2 | -------------------------------------------------------------------------------- /tests/tls-thread-g++/lib.h: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | int create_id(); 4 | -------------------------------------------------------------------------------- /tests/version-gcc-aarch64/libmax2.h: -------------------------------------------------------------------------------- 1 | extern int max(int a, int b, int c); 2 | -------------------------------------------------------------------------------- /tests/just-return-g++-aarch64/return.cc: -------------------------------------------------------------------------------- 1 | int main() { 2 | return 0; 3 | } 4 | -------------------------------------------------------------------------------- /tests/just-return-gcc-aarch64/return.c: -------------------------------------------------------------------------------- 1 | int main() { 2 | return 0; 3 | } 4 | -------------------------------------------------------------------------------- /tests/mprotect/base.c: -------------------------------------------------------------------------------- 1 | 2 | int func(int a, int b) { 3 | return a + b; 4 | } 5 | -------------------------------------------------------------------------------- /tests/tls-lib-gcc-aarch64/lib.h: -------------------------------------------------------------------------------- 1 | #include "base.h" 2 | 3 | int return_tls_i(); 4 | -------------------------------------------------------------------------------- /tests/tls-multiple-lib-gcc-aarch64/base.h: -------------------------------------------------------------------------------- 1 | extern __thread int thread_local_i; 2 | -------------------------------------------------------------------------------- /tests/tls-multiple-lib-gcc-aarch64/base2.c: -------------------------------------------------------------------------------- 1 | __thread int thread_local_j = 100; 2 | -------------------------------------------------------------------------------- /tests/tls-multiple-lib-gcc-aarch64/base2.h: -------------------------------------------------------------------------------- 1 | extern __thread int thread_local_j; 2 | -------------------------------------------------------------------------------- /tests/tls-thread-g++-aarch64/lib.h: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | int create_id(); 4 | -------------------------------------------------------------------------------- /tests/tls-thread-g++/.gitignore: -------------------------------------------------------------------------------- 1 | main 2 | lib.so.original 3 | lib.so.soldout 4 | -------------------------------------------------------------------------------- /tests/call_once-g++/main.cc: -------------------------------------------------------------------------------- 1 | void fuga(); 2 | 3 | int main() { 4 | fuga(); 5 | } 6 | -------------------------------------------------------------------------------- /tests/just-return-gcc-aarch64/.gitignore: -------------------------------------------------------------------------------- 1 | return 2 | return.out 3 | return.soldout 4 | -------------------------------------------------------------------------------- /tests/renamer/fugafuga.c: -------------------------------------------------------------------------------- 1 | int fugafuga(int a, int b) { 2 | return a - b; 3 | } 4 | -------------------------------------------------------------------------------- /tests/static-in-function-g++/.gitignore: -------------------------------------------------------------------------------- 1 | main 2 | lib.so.original 3 | lib.so.soldout 4 | -------------------------------------------------------------------------------- /tests/tls-lib-gcc-without-base-aarch64/base.h: -------------------------------------------------------------------------------- 1 | extern __thread int thread_local_i; 2 | -------------------------------------------------------------------------------- /tests/tls-thread-g++-aarch64/.gitignore: -------------------------------------------------------------------------------- 1 | main 2 | lib.so.original 3 | lib.so.soldout 4 | -------------------------------------------------------------------------------- /tests/mprotect-aarch64/base.c: -------------------------------------------------------------------------------- 1 | 2 | int func(int a, int b) { 3 | return a + b; 4 | } 5 | -------------------------------------------------------------------------------- /tests/tls-conflict-aarch64/fuga.cc: -------------------------------------------------------------------------------- 1 | thread_local int fuga; 2 | thread_local int dummy; 3 | -------------------------------------------------------------------------------- /tests/unique_ptr-aarch64/main.cc: -------------------------------------------------------------------------------- 1 | void fn(); 2 | 3 | int main() { 4 | fn(); 5 | } 6 | -------------------------------------------------------------------------------- /tests/call_once-g++-aarch64/main.cc: -------------------------------------------------------------------------------- 1 | void fuga(); 2 | 3 | int main() { 4 | fuga(); 5 | } 6 | -------------------------------------------------------------------------------- /tests/setjmp-gcc/.gitignore: -------------------------------------------------------------------------------- 1 | libhoge.so 2 | libhoge.so.original 3 | libhoge.so.soldout 4 | main 5 | -------------------------------------------------------------------------------- /tests/simple-lib-g++/libmax.cc: -------------------------------------------------------------------------------- 1 | int max(int a, int b) { 2 | return (a < b) ? b : a; 3 | } 4 | -------------------------------------------------------------------------------- /tests/simple-lib-gcc/libmax.c: -------------------------------------------------------------------------------- 1 | int max(int a, int b) { 2 | return (a < b) ? b : a; 3 | } 4 | -------------------------------------------------------------------------------- /tests/static-in-function-g++-aarch64/.gitignore: -------------------------------------------------------------------------------- 1 | main 2 | lib.so.original 3 | lib.so.soldout 4 | -------------------------------------------------------------------------------- /tests/stb_gnu_unique_tls/main.cc: -------------------------------------------------------------------------------- 1 | int fn(); 2 | 3 | int main() { 4 | int x = fn(); 5 | } 6 | -------------------------------------------------------------------------------- /tests/tls-dlopen-gcc/.gitignore: -------------------------------------------------------------------------------- 1 | lib.so 2 | lib.so.original 3 | lib.so.soldout 4 | main 5 | 6 | -------------------------------------------------------------------------------- /tests/tls-lib-gcc/base.c: -------------------------------------------------------------------------------- 1 | __thread int thread_local_i = 3; 2 | __thread int thread_local_j; 3 | -------------------------------------------------------------------------------- /tests/typeid-g++/.gitignore: -------------------------------------------------------------------------------- 1 | lib.o 2 | lib.so 3 | lib.so.original 4 | lib.so.soldout 5 | main 6 | -------------------------------------------------------------------------------- /tests/dynamic_cast-g++/.gitignore: -------------------------------------------------------------------------------- 1 | lib.o 2 | lib.so 3 | lib.so.original 4 | lib.so.soldout 5 | main 6 | -------------------------------------------------------------------------------- /tests/simple-lib-gcc-aarch64/libmax.c: -------------------------------------------------------------------------------- 1 | int max(int a, int b) { 2 | return (a < b) ? b : a; 3 | } 4 | -------------------------------------------------------------------------------- /tests/tls-dlopen-gcc-aarch64/.gitignore: -------------------------------------------------------------------------------- 1 | lib.so 2 | lib.so.original 3 | lib.so.soldout 4 | main 5 | 6 | -------------------------------------------------------------------------------- /tests/tls-lib-gcc-aarch64/base.c: -------------------------------------------------------------------------------- 1 | __thread int thread_local_i = 3; 2 | __thread int thread_local_j; 3 | -------------------------------------------------------------------------------- /tests/tls-lib-gcc-without-base/base.c: -------------------------------------------------------------------------------- 1 | #include "base.h" 2 | 3 | __thread int thread_local_i = 3; 4 | -------------------------------------------------------------------------------- /tests/setjmp-gcc-aarch64/.gitignore: -------------------------------------------------------------------------------- 1 | libhoge.so 2 | libhoge.so.original 3 | libhoge.so.soldout 4 | main 5 | -------------------------------------------------------------------------------- /tests/simple-lib-g++-aarch64/libmax.cc: -------------------------------------------------------------------------------- 1 | int max(int a, int b) { 2 | return (a < b) ? b : a; 3 | } 4 | -------------------------------------------------------------------------------- /tests/stb_gnu_unique_tls-aarch64/main.cc: -------------------------------------------------------------------------------- 1 | int fn(); 2 | 3 | int main() { 4 | int x = fn(); 5 | } 6 | -------------------------------------------------------------------------------- /tests/tls-lib-gcc/base.h: -------------------------------------------------------------------------------- 1 | extern __thread int thread_local_i; 2 | extern __thread int thread_local_j; 3 | -------------------------------------------------------------------------------- /tests/typeid-g++-aarch64/.gitignore: -------------------------------------------------------------------------------- 1 | lib.o 2 | lib.so 3 | lib.so.original 4 | lib.so.soldout 5 | main 6 | -------------------------------------------------------------------------------- /tests/dynamic_cast-g++-aarch64/.gitignore: -------------------------------------------------------------------------------- 1 | lib.o 2 | lib.so 3 | lib.so.original 4 | lib.so.soldout 5 | main 6 | -------------------------------------------------------------------------------- /tests/stb_gnu_unique_tls/.gitignore: -------------------------------------------------------------------------------- 1 | libunique.so 2 | libunique.so.original 3 | libunique.so.soldout 4 | main 5 | -------------------------------------------------------------------------------- /tests/tls-lib-gcc-aarch64/base.h: -------------------------------------------------------------------------------- 1 | extern __thread int thread_local_i; 2 | extern __thread int thread_local_j; 3 | -------------------------------------------------------------------------------- /tests/tls-lib-gcc-without-base-aarch64/base.c: -------------------------------------------------------------------------------- 1 | #include "base.h" 2 | 3 | __thread int thread_local_i = 3; 4 | -------------------------------------------------------------------------------- /tests/tls-lib-gcc/lib.c: -------------------------------------------------------------------------------- 1 | #include "lib.h" 2 | 3 | int return_tls_i() { 4 | return thread_local_i; 5 | } 6 | -------------------------------------------------------------------------------- /tests/mprotect/main.c: -------------------------------------------------------------------------------- 1 | #include "mprotect_check.h" 2 | 3 | int main() { 4 | check(); 5 | return 0; 6 | } 7 | -------------------------------------------------------------------------------- /tests/typeid-g++/main.cc: -------------------------------------------------------------------------------- 1 | #include "lib.h" 2 | 3 | int main() { 4 | PrintTypeid(); 5 | return 0; 6 | } 7 | -------------------------------------------------------------------------------- /tests/unique_ptr-aarch64/.gitignore: -------------------------------------------------------------------------------- 1 | libhoge.so 2 | libhoge.so.original 3 | libhoge.so.soldout 4 | main 5 | sold.* 6 | -------------------------------------------------------------------------------- /libtorch_test/torch_test_main.cc: -------------------------------------------------------------------------------- 1 | #include "torch_test.h" 2 | 3 | int main() { 4 | test(); 5 | return 0; 6 | } 7 | -------------------------------------------------------------------------------- /tests/dynamic_cast-g++/main.cc: -------------------------------------------------------------------------------- 1 | #include "lib.h" 2 | 3 | int main() { 4 | TryDowncast(); 5 | return 0; 6 | } 7 | -------------------------------------------------------------------------------- /tests/renamer/.gitignore: -------------------------------------------------------------------------------- 1 | libfugafuga.so 2 | libhoge_original.so 3 | libhoge_renamed.so 4 | libhoge.so 5 | use_fugafuga 6 | -------------------------------------------------------------------------------- /tests/stb_gnu_unique_tls-aarch64/.gitignore: -------------------------------------------------------------------------------- 1 | libunique.so 2 | libunique.so.original 3 | libunique.so.soldout 4 | main 5 | -------------------------------------------------------------------------------- /tests/tls-lib-gcc-aarch64/lib.c: -------------------------------------------------------------------------------- 1 | #include "lib.h" 2 | 3 | int return_tls_i() { 4 | return thread_local_i; 5 | } 6 | -------------------------------------------------------------------------------- /tests/typeid-g++-aarch64/main.cc: -------------------------------------------------------------------------------- 1 | #include "lib.h" 2 | 3 | int main() { 4 | PrintTypeid(); 5 | return 0; 6 | } 7 | -------------------------------------------------------------------------------- /tests/call_once-g++/.gitignore: -------------------------------------------------------------------------------- 1 | libfuga.so 2 | libfuga.so.original 3 | libfuga.so.soldout 4 | libhoge.so 5 | main 6 | sold.* 7 | -------------------------------------------------------------------------------- /tests/dynamic_cast-g++-aarch64/main.cc: -------------------------------------------------------------------------------- 1 | #include "lib.h" 2 | 3 | int main() { 4 | TryDowncast(); 5 | return 0; 6 | } 7 | -------------------------------------------------------------------------------- /tests/hello-gcc/hello.c: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | int main() { 4 | puts("Hello World!\n"); 5 | return 0; 6 | } 7 | -------------------------------------------------------------------------------- /tests/mprotect-aarch64/main.c: -------------------------------------------------------------------------------- 1 | #include "mprotect_check.h" 2 | 3 | int main() { 4 | check(); 5 | return 0; 6 | } 7 | -------------------------------------------------------------------------------- /tests/tls-lib-gcc-without-base/lib.c: -------------------------------------------------------------------------------- 1 | #include "base.h" 2 | 3 | int return_tls_i() { 4 | return thread_local_i; 5 | } 6 | -------------------------------------------------------------------------------- /tests/hello-gcc-aarch64/hello.c: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | int main() { 4 | puts("Hello World!\n"); 5 | return 0; 6 | } 7 | -------------------------------------------------------------------------------- /tests/mprotect/.gitignore: -------------------------------------------------------------------------------- 1 | base.so 2 | main 3 | mprotect_check.so 4 | mprotect_check.so.original 5 | mprotect_check.so.soldout 6 | -------------------------------------------------------------------------------- /tests/tls-lib-gcc-without-base-aarch64/lib.c: -------------------------------------------------------------------------------- 1 | #include "base.h" 2 | 3 | int return_tls_i() { 4 | return thread_local_i; 5 | } 6 | -------------------------------------------------------------------------------- /tests/tls-multiple-lib-gcc/lib.h: -------------------------------------------------------------------------------- 1 | #include "base.h" 2 | #include "base2.h" 3 | 4 | int return_tls_i(); 5 | int return_tls_j(); 6 | -------------------------------------------------------------------------------- /tests/call_once-g++-aarch64/.gitignore: -------------------------------------------------------------------------------- 1 | libfuga.so 2 | libfuga.so.original 3 | libfuga.so.soldout 4 | libhoge.so 5 | main 6 | sold.* 7 | -------------------------------------------------------------------------------- /tests/mprotect-aarch64/.gitignore: -------------------------------------------------------------------------------- 1 | base.so 2 | main 3 | mprotect_check.so 4 | mprotect_check.so.original 5 | mprotect_check.so.soldout 6 | -------------------------------------------------------------------------------- /tests/tls-multiple-lib-gcc-aarch64/lib.h: -------------------------------------------------------------------------------- 1 | #include "base.h" 2 | #include "base2.h" 3 | 4 | int return_tls_i(); 5 | int return_tls_j(); 6 | -------------------------------------------------------------------------------- /tests/tls-multiple-module-g++/.gitignore: -------------------------------------------------------------------------------- 1 | libfugahoge.so.original 2 | libfugahoge.so.soldout 3 | libfuga.so 4 | libhoge.so 5 | main 6 | -------------------------------------------------------------------------------- /tests/static-in-function-g++/lib.cc: -------------------------------------------------------------------------------- 1 | #include "lib.h" 2 | 3 | int func() { 4 | static int v = 0; 5 | v++; 6 | return v; 7 | } 8 | -------------------------------------------------------------------------------- /tests/tls-multiple-module-g++-aarch64/.gitignore: -------------------------------------------------------------------------------- 1 | libfugahoge.so.original 2 | libfugahoge.so.soldout 3 | libfuga.so 4 | libhoge.so 5 | main 6 | -------------------------------------------------------------------------------- /tests/hello-g++/hello.cc: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | int main() { 4 | std::cout << "Hello World!" << std::endl; 5 | return 0; 6 | } 7 | -------------------------------------------------------------------------------- /tests/tls-multiple-module-g++/fuga.h: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | void show_fuga(); 4 | uint64_t get_fuga_data(); 5 | uint64_t get_fuga_bss(); 6 | -------------------------------------------------------------------------------- /tests/tls-multiple-module-g++/hoge.h: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | void show_hoge(); 4 | uint64_t get_hoge_data(); 5 | uint64_t get_hoge_bss(); 6 | -------------------------------------------------------------------------------- /tests/hello-g++-aarch64/hello.cc: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | int main() { 4 | std::cout << "Hello World!" << std::endl; 5 | return 0; 6 | } 7 | -------------------------------------------------------------------------------- /tests/static-in-class-g++/main.cc: -------------------------------------------------------------------------------- 1 | #include "lib.h" 2 | 3 | #include 4 | 5 | int main() { 6 | std::cout << func() << std::endl; 7 | } 8 | -------------------------------------------------------------------------------- /tests/static-in-function-g++-aarch64/lib.cc: -------------------------------------------------------------------------------- 1 | #include "lib.h" 2 | 3 | int func() { 4 | static int v = 0; 5 | v++; 6 | return v; 7 | } 8 | -------------------------------------------------------------------------------- /tests/tls-multiple-module-g++-aarch64/fuga.h: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | void show_fuga(); 4 | uint64_t get_fuga_data(); 5 | uint64_t get_fuga_bss(); 6 | -------------------------------------------------------------------------------- /tests/tls-multiple-module-g++-aarch64/hoge.h: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | void show_hoge(); 4 | uint64_t get_hoge_data(); 5 | uint64_t get_hoge_bss(); 6 | -------------------------------------------------------------------------------- /tests/tls-thread-g++/lib.cc: -------------------------------------------------------------------------------- 1 | #include "lib.h" 2 | 3 | int create_id() { 4 | thread_local int current_id = 0; 5 | return current_id++; 6 | } 7 | -------------------------------------------------------------------------------- /tests/typeid-g++-aarch64/fuga.h: -------------------------------------------------------------------------------- 1 | struct BaseFuga { 2 | public: 3 | virtual void f() {} 4 | }; 5 | 6 | struct DerivedFuga : public BaseFuga {}; 7 | -------------------------------------------------------------------------------- /tests/hello-g++/test.sh: -------------------------------------------------------------------------------- 1 | #! /bin/bash 2 | 3 | g++ hello.cc -o hello 4 | ../../build/sold hello -o hello.out --section-headers --check-output 5 | ./hello.out 6 | -------------------------------------------------------------------------------- /tests/hello-gcc/test.sh: -------------------------------------------------------------------------------- 1 | #! /bin/bash 2 | 3 | gcc hello.c -o hello 4 | ../../build/sold hello -o hello.out --section-headers --check-output 5 | ./hello.out 6 | -------------------------------------------------------------------------------- /tests/static-in-class-g++-aarch64/main.cc: -------------------------------------------------------------------------------- 1 | #include "lib.h" 2 | 3 | #include 4 | 5 | int main() { 6 | std::cout << func() << std::endl; 7 | } 8 | -------------------------------------------------------------------------------- /tests/tls-bss-g++/test.sh: -------------------------------------------------------------------------------- 1 | #! /bin/bash -eu 2 | 3 | g++ -o main.out main.cc 4 | ../../build/sold main.out -o main.soldout --section-headers 5 | ./main.soldout 6 | -------------------------------------------------------------------------------- /tests/tls-thread-g++-aarch64/lib.cc: -------------------------------------------------------------------------------- 1 | #include "lib.h" 2 | 3 | int create_id() { 4 | thread_local int current_id = 0; 5 | return current_id++; 6 | } 7 | -------------------------------------------------------------------------------- /tests/version-gcc/libmax1.c: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | int max(int a, int b) { 4 | printf("max__1 @ libmax1\n"); 5 | return (a > b ? a : b); 6 | } 7 | -------------------------------------------------------------------------------- /tests/global-write-aarch64/main.c: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | extern int hoge; 4 | 5 | int main() { 6 | hoge = 10; 7 | printf("hoge = %d\n", hoge); 8 | } 9 | -------------------------------------------------------------------------------- /tests/simple-lib-gcc/main.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include "libmax.h" 3 | 4 | int main() { 5 | printf("max(1,2) = %d\n", max(1, 2)); 6 | return 0; 7 | } 8 | -------------------------------------------------------------------------------- /tests/tls-gcc/test.sh: -------------------------------------------------------------------------------- 1 | #! /bin/bash -eu 2 | 3 | gcc -Wl,--hash-style=gnu -o main main.c 4 | 5 | ../../build/sold main -o main.out --section-headers 6 | ./main.out 7 | -------------------------------------------------------------------------------- /tests/version-gcc-aarch64/libmax1.c: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | int max(int a, int b) { 4 | printf("max__1 @ libmax1\n"); 5 | return (a > b ? a : b); 6 | } 7 | -------------------------------------------------------------------------------- /tests/exception-g++/fuga.h: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | 5 | void throw_exception_fuga(); 6 | void catch_exception_fuga(); 7 | -------------------------------------------------------------------------------- /tests/exception-g++/hoge.h: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | 5 | void throw_exception_hoge(); 6 | void catch_exception_hoge(); 7 | -------------------------------------------------------------------------------- /tests/tls-lib-gcc-without-base/main.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include "lib.h" 3 | 4 | int main() { 5 | printf("j = %d\n", return_tls_i()); 6 | return 0; 7 | } 8 | -------------------------------------------------------------------------------- /tests/version-gcc/.gitignore: -------------------------------------------------------------------------------- 1 | libmax.so 2 | libmax.so.1 3 | libmax.so.2 4 | libmax1.o 5 | libmax2.o 6 | vertest1 7 | vertest1.out 8 | vertest2 9 | vertest2.out 10 | -------------------------------------------------------------------------------- /tests/version-gcc/vertest1.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include "libmax1.h" 3 | 4 | int main(void) { 5 | printf("max(1,2) = %d\n", max(1, 2)); 6 | return 0; 7 | } 8 | -------------------------------------------------------------------------------- /tests/simple-lib-gcc-aarch64/main.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include "libmax.h" 3 | 4 | int main() { 5 | printf("max(1,2) = %d\n", max(1, 2)); 6 | return 0; 7 | } 8 | -------------------------------------------------------------------------------- /CTestCustom.cmake: -------------------------------------------------------------------------------- 1 | set(CTEST_CUSTOM_TESTS_IGNORE 2 | demangle 3 | logging 4 | signalhandler 5 | stacktrace 6 | stl_logging 7 | symbolize 8 | ) -------------------------------------------------------------------------------- /tests/exception-g++-aarch64/fuga.h: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | 5 | void throw_exception_fuga(); 6 | void catch_exception_fuga(); 7 | -------------------------------------------------------------------------------- /tests/exception-g++-aarch64/hoge.h: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | 5 | void throw_exception_hoge(); 6 | void catch_exception_hoge(); 7 | -------------------------------------------------------------------------------- /tests/exception-str-g++-aarch64/fuga.h: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | 5 | void throw_exception_fuga(); 6 | void catch_exception_fuga(); 7 | -------------------------------------------------------------------------------- /tests/exception-str-g++-aarch64/hoge.h: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | 5 | void throw_exception_hoge(); 6 | void catch_exception_hoge(); 7 | -------------------------------------------------------------------------------- /tests/tls-lib-gcc-without-base-aarch64/main.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include "lib.h" 3 | 4 | int main() { 5 | printf("j = %d\n", return_tls_i()); 6 | return 0; 7 | } 8 | -------------------------------------------------------------------------------- /tests/version-gcc-aarch64/.gitignore: -------------------------------------------------------------------------------- 1 | libmax.so 2 | libmax.so.1 3 | libmax.so.2 4 | libmax1.o 5 | libmax2.o 6 | vertest1 7 | vertest1.out 8 | vertest2 9 | vertest2.out 10 | -------------------------------------------------------------------------------- /tests/version-gcc-aarch64/vertest1.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include "libmax1.h" 3 | 4 | int main(void) { 5 | printf("max(1,2) = %d\n", max(1, 2)); 6 | return 0; 7 | } 8 | -------------------------------------------------------------------------------- /tests/version-gcc/vertest2.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include "libmax2.h" 3 | 4 | int main(void) { 5 | printf("max(1, 2, 3) = %d\n", max(1, 2, 3)); 6 | return 0; 7 | } 8 | -------------------------------------------------------------------------------- /tests/just-return-g++/test.sh: -------------------------------------------------------------------------------- 1 | #! /bin/bash 2 | 3 | g++ return.cc -o return.out 4 | ../../build/sold return.out -o return.soldout --section-headers --check-output 5 | ./return.soldout 6 | -------------------------------------------------------------------------------- /tests/just-return-gcc/test.sh: -------------------------------------------------------------------------------- 1 | #! /bin/bash 2 | 3 | gcc return.c -o return.out 4 | ../../build/sold return.out -o return.soldout --section-headers --check-output 5 | ./return.soldout 6 | -------------------------------------------------------------------------------- /tests/simple-lib-g++/main.cc: -------------------------------------------------------------------------------- 1 | #include 2 | #include "libmax.h" 3 | 4 | int main() { 5 | std::cout << "max(1,2) = " << max(1, 2) << std::endl; 6 | return 0; 7 | } 8 | -------------------------------------------------------------------------------- /tests/tls-bss-gcc/test.sh: -------------------------------------------------------------------------------- 1 | #! /bin/bash -eu 2 | 3 | gcc -Wl,--hash-style=gnu -o main.out main.c 4 | 5 | ../../build/sold main.out -o main.soldout --section-headers 6 | ./main.soldout 7 | -------------------------------------------------------------------------------- /tests/version-gcc-aarch64/vertest2.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include "libmax2.h" 3 | 4 | int main(void) { 5 | printf("max(1, 2, 3) = %d\n", max(1, 2, 3)); 6 | return 0; 7 | } 8 | -------------------------------------------------------------------------------- /tests/setjmp-gcc/hoge.h: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | 4 | extern int counter; 5 | extern jmp_buf buf; 6 | 7 | void setjmp_longjmp_in_function(); 8 | void call_longjmp(); 9 | -------------------------------------------------------------------------------- /tests/simple-lib-g++-aarch64/main.cc: -------------------------------------------------------------------------------- 1 | #include 2 | #include "libmax.h" 3 | 4 | int main() { 5 | std::cout << "max(1,2) = " << max(1, 2) << std::endl; 6 | return 0; 7 | } 8 | -------------------------------------------------------------------------------- /tests/static-in-class-g++/lib.cc: -------------------------------------------------------------------------------- 1 | #include "lib.h" 2 | 3 | int X::i_static = 42; 4 | double X::d_static = 42.00; 5 | 6 | double func() { 7 | X x; 8 | return x.f(); 9 | } 10 | -------------------------------------------------------------------------------- /tests/tls-conflict-aarch64/hoge.cc: -------------------------------------------------------------------------------- 1 | extern thread_local int dummy; 2 | extern thread_local int fuga; 3 | thread_local int hoge; 4 | 5 | void fn() { 6 | dummy = 10; 7 | fuga = 10; 8 | } 9 | -------------------------------------------------------------------------------- /tests/tls-multiple-lib-gcc/lib.c: -------------------------------------------------------------------------------- 1 | #include "lib.h" 2 | 3 | int return_tls_i() { 4 | return thread_local_i; 5 | } 6 | 7 | int return_tls_j() { 8 | return thread_local_j; 9 | } 10 | -------------------------------------------------------------------------------- /tests/setjmp-gcc-aarch64/hoge.h: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | 4 | extern int counter; 5 | extern jmp_buf buf; 6 | 7 | void setjmp_longjmp_in_function(); 8 | void call_longjmp(); 9 | -------------------------------------------------------------------------------- /tests/static-in-class-g++-aarch64/lib.cc: -------------------------------------------------------------------------------- 1 | #include "lib.h" 2 | 3 | int X::i_static = 42; 4 | double X::d_static = 42.00; 5 | 6 | double func() { 7 | X x; 8 | return x.f(); 9 | } 10 | -------------------------------------------------------------------------------- /tests/tls-multiple-lib-gcc-aarch64/lib.c: -------------------------------------------------------------------------------- 1 | #include "lib.h" 2 | 3 | int return_tls_i() { 4 | return thread_local_i; 5 | } 6 | 7 | int return_tls_j() { 8 | return thread_local_j; 9 | } 10 | -------------------------------------------------------------------------------- /tests/tls-multiple-lib-gcc/main.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include "lib.h" 3 | 4 | int main() { 5 | printf("i = %d\n", return_tls_i()); 6 | printf("j = %d\n", return_tls_j()); 7 | return 0; 8 | } 9 | -------------------------------------------------------------------------------- /tests/version-gcc/libmax2.def: -------------------------------------------------------------------------------- 1 | LIBMAX_1.0{ 2 | global: 3 | max*; 4 | local: *; 5 | }; 6 | LIBMAX_2.0{ 7 | global: 8 | max*; 9 | local: *; 10 | } LIBMAX_1.0; 11 | -------------------------------------------------------------------------------- /tests/tls-multiple-lib-gcc-aarch64/main.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include "lib.h" 3 | 4 | int main() { 5 | printf("i = %d\n", return_tls_i()); 6 | printf("j = %d\n", return_tls_j()); 7 | return 0; 8 | } 9 | -------------------------------------------------------------------------------- /tests/version-gcc-aarch64/libmax2.def: -------------------------------------------------------------------------------- 1 | LIBMAX_1.0{ 2 | global: 3 | max*; 4 | local: *; 5 | }; 6 | LIBMAX_2.0{ 7 | global: 8 | max*; 9 | local: *; 10 | } LIBMAX_1.0; 11 | -------------------------------------------------------------------------------- /tests/static-in-class-g++/lib.h: -------------------------------------------------------------------------------- 1 | class X { 2 | public: 3 | double f() { return i_static + d_static; } 4 | 5 | private: 6 | static int i_static; 7 | static double d_static; 8 | }; 9 | 10 | double func(); 11 | -------------------------------------------------------------------------------- /tests/static-in-class-g++-aarch64/lib.h: -------------------------------------------------------------------------------- 1 | class X { 2 | public: 3 | double f() { return i_static + d_static; } 4 | 5 | private: 6 | static int i_static; 7 | static double d_static; 8 | }; 9 | 10 | double func(); 11 | -------------------------------------------------------------------------------- /.clang-format: -------------------------------------------------------------------------------- 1 | BasedOnStyle: Google 2 | AccessModifierOffset: -4 3 | ColumnLimit: 140 4 | IndentWidth: 4 5 | DerivePointerAlignment: false 6 | PointerAlignment: Left 7 | IncludeBlocks: Preserve 8 | AllowShortFunctionsOnASingleLine: Inline 9 | -------------------------------------------------------------------------------- /tests/tls-lib-gcc/main.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include "lib.h" 3 | 4 | int main() { 5 | printf("i = %d\n", return_tls_i()); 6 | thread_local_j = 3; 7 | printf("j = %d\n", thread_local_j); 8 | return 0; 9 | } 10 | -------------------------------------------------------------------------------- /tests/tls-lib-gcc-aarch64/main.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include "lib.h" 3 | 4 | int main() { 5 | printf("i = %d\n", return_tls_i()); 6 | thread_local_j = 3; 7 | printf("j = %d\n", thread_local_j); 8 | return 0; 9 | } 10 | -------------------------------------------------------------------------------- /tests/static-in-function-g++/main.cc: -------------------------------------------------------------------------------- 1 | #include "lib.h" 2 | 3 | #include 4 | 5 | int main() { 6 | std::cout << func() << std::endl; 7 | std::cout << func() << std::endl; 8 | std::cout << func() << std::endl; 9 | } 10 | -------------------------------------------------------------------------------- /run-format.sh: -------------------------------------------------------------------------------- 1 | #! /bin/bash -eu 2 | 3 | cd "$(git rev-parse --show-toplevel)" 4 | git ls-files -- '**/*.h' '**/*.cc' '**/*.c'| xargs -P4 clang-format -i 5 | git ls-files -- '**/CMakeLists.txt' | xargs -P4 cmake-format -i 6 | git diff --exit-code -- . 7 | -------------------------------------------------------------------------------- /tests/static-in-function-g++-aarch64/main.cc: -------------------------------------------------------------------------------- 1 | #include "lib.h" 2 | 3 | #include 4 | 5 | int main() { 6 | std::cout << func() << std::endl; 7 | std::cout << func() << std::endl; 8 | std::cout << func() << std::endl; 9 | } 10 | -------------------------------------------------------------------------------- /tests/tls-bss-gcc/main.c: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | __thread int tls_bss_i; 4 | 5 | int main() { 6 | tls_bss_i = 2; 7 | printf("tls_bss_i = %d\n", tls_bss_i); 8 | printf("tls_bss_i = %d\n", tls_bss_i + 10); 9 | return 0; 10 | } 11 | -------------------------------------------------------------------------------- /tests/tls-conflict-aarch64/main.cc: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | extern thread_local int hoge; 4 | extern thread_local int fuga; 5 | 6 | int main() { 7 | hoge = 42; 8 | fuga = 10; 9 | printf("hoge = %d, fuga = %d\n", hoge, fuga); 10 | } 11 | -------------------------------------------------------------------------------- /tests/tls-bss-g++/main.cc: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | thread_local int tls_bss_i; 4 | 5 | int main() { 6 | tls_bss_i = 2; 7 | printf("tls_bss_i = %d\n", tls_bss_i); 8 | printf("tls_bss_i = %d\n", tls_bss_i + 10); 9 | return 0; 10 | } 11 | -------------------------------------------------------------------------------- /tests/tls-bss-gcc-aarch64/main.c: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | __thread int tls_bss_i; 4 | 5 | int main() { 6 | tls_bss_i = 2; 7 | printf("tls_bss_i = %d\n", tls_bss_i); 8 | printf("tls_bss_i = %d\n", tls_bss_i + 10); 9 | return 0; 10 | } 11 | -------------------------------------------------------------------------------- /tests/hello-gcc-aarch64/test.sh: -------------------------------------------------------------------------------- 1 | #! /bin/bash 2 | 3 | aarch64-linux-gnu-gcc hello.c -o hello 4 | ../../build/sold hello -o hello.out --section-headers --check-output --custom-library-path /usr/aarch64-linux-gnu/lib 5 | qemu-aarch64 -L /usr/aarch64-linux-gnu ./hello.out 6 | -------------------------------------------------------------------------------- /tests/tls-bss-g++-aarch64/main.cc: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | thread_local int tls_bss_i; 4 | 5 | int main() { 6 | tls_bss_i = 2; 7 | printf("tls_bss_i = %d\n", tls_bss_i); 8 | printf("tls_bss_i = %d\n", tls_bss_i + 10); 9 | return 0; 10 | } 11 | -------------------------------------------------------------------------------- /tests/hello-g++-aarch64/test.sh: -------------------------------------------------------------------------------- 1 | #! /bin/bash 2 | 3 | aarch64-linux-gnu-g++ hello.cc -o hello 4 | ../../build/sold hello -o hello.out --section-headers --check-output --custom-library-path /usr/aarch64-linux-gnu/lib 5 | qemu-aarch64 -L /usr/aarch64-linux-gnu ./hello.out 6 | -------------------------------------------------------------------------------- /tests/tls-bss-g++-aarch64/test.sh: -------------------------------------------------------------------------------- 1 | #! /bin/bash -eu 2 | 3 | aarch64-linux-gnu-g++ -o main.out main.cc 4 | ../../build/sold main.out -o main.soldout --section-headers --custom-library-path /usr/aarch64-linux-gnu/lib 5 | qemu-aarch64 -L /usr/aarch64-linux-gnu ./main.soldout 6 | -------------------------------------------------------------------------------- /tests/tls-gcc-aarch64/test.sh: -------------------------------------------------------------------------------- 1 | #! /bin/bash -eu 2 | 3 | aarch64-linux-gnu-gcc -Wl,--hash-style=gnu -o main main.c 4 | 5 | ../../build/sold main -o main.out --section-headers --custom-library-path /usr/aarch64-linux-gnu/lib 6 | qemu-aarch64 -L /usr/aarch64-linux-gnu ./main.out 7 | -------------------------------------------------------------------------------- /tests/call_once-g++/hoge.cc: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | 5 | std::once_flag once; 6 | 7 | void init() { 8 | std::cout << "initialize" << std::endl; 9 | } 10 | 11 | void thread_proc() { 12 | std::call_once(once, init); 13 | } 14 | -------------------------------------------------------------------------------- /pybind_test/README.md: -------------------------------------------------------------------------------- 1 | # pybind test 2 | Most of codes in this directory comes from 3 | - [https://pybind11.readthedocs.io/en/stable/basics.html]() 4 | - [https://pybind11.readthedocs.io/en/stable/classes.html]() 5 | - [https://pybind11.readthedocs.io/en/stable/advanced/pycpp/numpy.html]() 6 | -------------------------------------------------------------------------------- /tests/call_once-g++-aarch64/hoge.cc: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | 5 | std::once_flag once; 6 | 7 | void init() { 8 | std::cout << "initialize" << std::endl; 9 | } 10 | 11 | void thread_proc() { 12 | std::call_once(once, init); 13 | } 14 | -------------------------------------------------------------------------------- /tests/call_once-g++/fuga.cc: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | void thread_proc(); 4 | 5 | void fuga() { 6 | std::thread t1(thread_proc); 7 | std::thread t2(thread_proc); 8 | std::thread t3(thread_proc); 9 | 10 | t1.join(); 11 | t2.join(); 12 | t3.join(); 13 | } 14 | -------------------------------------------------------------------------------- /tests/call_once-g++-aarch64/fuga.cc: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | void thread_proc(); 4 | 5 | void fuga() { 6 | std::thread t1(thread_proc); 7 | std::thread t2(thread_proc); 8 | std::thread t3(thread_proc); 9 | 10 | t1.join(); 11 | t2.join(); 12 | t3.join(); 13 | } 14 | -------------------------------------------------------------------------------- /tests/just-return-g++-aarch64/test.sh: -------------------------------------------------------------------------------- 1 | #! /bin/bash 2 | 3 | aarch64-linux-gnu-g++ return.cc -o return.out 4 | ../../build/sold return.out -o return.soldout --section-headers --check-output --custom-library-path /usr/aarch64-linux-gnu/lib 5 | qemu-aarch64 -L /usr/aarch64-linux-gnu ./return.soldout 6 | -------------------------------------------------------------------------------- /tests/just-return-gcc-aarch64/test.sh: -------------------------------------------------------------------------------- 1 | #! /bin/bash 2 | 3 | aarch64-linux-gnu-gcc return.c -o return.out 4 | ../../build/sold return.out -o return.soldout --section-headers --check-output --custom-library-path /usr/aarch64-linux-gnu/lib 5 | qemu-aarch64 -L /usr/aarch64-linux-gnu ./return.soldout 6 | -------------------------------------------------------------------------------- /tests/tls-bss-gcc-aarch64/test.sh: -------------------------------------------------------------------------------- 1 | #! /bin/bash -eu 2 | 3 | aarch64-linux-gnu-gcc -Wl,--hash-style=gnu -o main.out main.c 4 | 5 | ../../build/sold main.out -o main.soldout --section-headers --custom-library-path /usr/aarch64-linux-gnu/lib 6 | qemu-aarch64 -L /usr/aarch64-linux-gnu ./main.soldout 7 | -------------------------------------------------------------------------------- /tests/unique_ptr-aarch64/hoge.cc: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | 4 | struct X { 5 | X(int v) : var(v){}; 6 | int var; 7 | int fn() { return var; } 8 | }; 9 | 10 | void fn() { 11 | auto up = std::make_unique(42); 12 | auto p = up.release(); 13 | printf("%d\n", p->fn()); 14 | } 15 | -------------------------------------------------------------------------------- /tests/mprotect/mprotect_check.c: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | #include "base.h" 4 | 5 | void check() { 6 | int x = func(1, 2); 7 | char str[1024]; 8 | FILE* fp = fopen("/proc/self/maps", "r"); 9 | while ((fgets(str, 256, fp)) != NULL) { 10 | printf("%s", str); 11 | } 12 | fclose(fp); 13 | } 14 | -------------------------------------------------------------------------------- /tests/exception-g++/fuga.cc: -------------------------------------------------------------------------------- 1 | #include "fuga.h" 2 | 3 | void throw_exception_fuga() { 4 | throw std::runtime_error("fuga"); 5 | } 6 | 7 | void catch_exception_fuga() { 8 | try { 9 | throw_exception_fuga(); 10 | } catch (std::exception& e) { 11 | std::cout << e.what() << std::endl; 12 | } 13 | } 14 | -------------------------------------------------------------------------------- /tests/tls-multiple-module-g++/fuga.cc: -------------------------------------------------------------------------------- 1 | #include "fuga.h" 2 | 3 | namespace { 4 | thread_local uint64_t fuga_data = 0xDEADBEEFDEADBEEF; 5 | thread_local uint64_t fuga_bss; 6 | } // namespace 7 | 8 | uint64_t get_fuga_data() { 9 | return fuga_data; 10 | } 11 | 12 | uint64_t get_fuga_bss() { 13 | return fuga_bss; 14 | } 15 | -------------------------------------------------------------------------------- /tests/tls-multiple-module-g++/hoge.cc: -------------------------------------------------------------------------------- 1 | #include "hoge.h" 2 | 3 | namespace { 4 | thread_local uint64_t hoge_data = 0xABCDEFABCDEFABCD; 5 | thread_local uint64_t hoge_bss; 6 | } // namespace 7 | 8 | uint64_t get_hoge_data() { 9 | return hoge_data; 10 | } 11 | 12 | uint64_t get_hoge_bss() { 13 | return hoge_bss; 14 | } 15 | -------------------------------------------------------------------------------- /tests/mprotect-aarch64/mprotect_check.c: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | #include "base.h" 4 | 5 | void check() { 6 | int x = func(1, 2); 7 | char str[1024]; 8 | FILE* fp = fopen("/proc/self/maps", "r"); 9 | while ((fgets(str, 256, fp)) != NULL) { 10 | printf("%s", str); 11 | } 12 | fclose(fp); 13 | } 14 | -------------------------------------------------------------------------------- /tests/runtest.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | set -e 4 | 5 | if [ ! -z $1 ]; then 6 | cd "$1" 7 | fi 8 | 9 | out=out 10 | mkdir -p "${out}" 11 | 12 | sotest="${out}/sotest" 13 | mkdir -p "${sotest}" 14 | ./sold tests/libtest_lib.so "${sotest}/libtest_lib.so" 15 | cp tests/test_exe "${sotest}/test_exe" 16 | "${sotest}/test_exe" lib 17 | -------------------------------------------------------------------------------- /tests/exception-g++-aarch64/fuga.cc: -------------------------------------------------------------------------------- 1 | #include "fuga.h" 2 | 3 | void throw_exception_fuga() { 4 | throw std::runtime_error("fuga"); 5 | } 6 | 7 | void catch_exception_fuga() { 8 | try { 9 | throw_exception_fuga(); 10 | } catch (std::exception& e) { 11 | std::cout << e.what() << std::endl; 12 | } 13 | } 14 | -------------------------------------------------------------------------------- /tests/tls-multiple-module-g++-aarch64/fuga.cc: -------------------------------------------------------------------------------- 1 | #include "fuga.h" 2 | 3 | namespace { 4 | thread_local uint64_t fuga_data = 0xDEADBEEFDEADBEEF; 5 | thread_local uint64_t fuga_bss; 6 | } // namespace 7 | 8 | uint64_t get_fuga_data() { 9 | return fuga_data; 10 | } 11 | 12 | uint64_t get_fuga_bss() { 13 | return fuga_bss; 14 | } 15 | -------------------------------------------------------------------------------- /tests/tls-multiple-module-g++-aarch64/hoge.cc: -------------------------------------------------------------------------------- 1 | #include "hoge.h" 2 | 3 | namespace { 4 | thread_local uint64_t hoge_data = 0xABCDEFABCDEFABCD; 5 | thread_local uint64_t hoge_bss; 6 | } // namespace 7 | 8 | uint64_t get_hoge_data() { 9 | return hoge_data; 10 | } 11 | 12 | uint64_t get_hoge_bss() { 13 | return hoge_bss; 14 | } 15 | -------------------------------------------------------------------------------- /tests/inheritance-g++/lib.h: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | class A { 4 | public: 5 | virtual void Speak(){}; 6 | }; 7 | 8 | class B : public A { 9 | public: 10 | void Speak() override; 11 | int a; 12 | int b; 13 | }; 14 | 15 | class C : public A { 16 | public: 17 | void Speak() override; 18 | }; 19 | 20 | void JustHelloFun(); 21 | -------------------------------------------------------------------------------- /tests/renamer/use_fugafuga.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | 4 | // Although `fugafuga` in fugafuga.c is subtraction, `hoge` in hoge.c is 5 | // addition. renamer renames `hoge` to `fugafuga`. 6 | int fugafuga(int a, int b); 7 | 8 | int main() { 9 | int a = fugafuga(1, 2); 10 | assert(a == 3); 11 | return 0; 12 | } 13 | -------------------------------------------------------------------------------- /fedora-latest.Dockerfile: -------------------------------------------------------------------------------- 1 | FROM fedora:34 2 | RUN dnf install -y ninja-build cmake gcc g++ git libstdc++ python3 python3-devel python3-pip 3 | RUN pip3 install numpy pytest 4 | COPY . /sold 5 | WORKDIR /sold 6 | RUN rm -rf build 7 | RUN mkdir build && cd build && cmake -GNinja -DSOLD_PYBIND_TEST=ON .. 8 | RUN cmake --build build 9 | RUN cd build && ctest 10 | -------------------------------------------------------------------------------- /tests/inheritance-g++-aarch64/lib.h: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | class A { 4 | public: 5 | virtual void Speak(){}; 6 | }; 7 | 8 | class B : public A { 9 | public: 10 | void Speak() override; 11 | int a; 12 | int b; 13 | }; 14 | 15 | class C : public A { 16 | public: 17 | void Speak() override; 18 | }; 19 | 20 | void JustHelloFun(); 21 | -------------------------------------------------------------------------------- /tests/simple-lib-g++/test.sh: -------------------------------------------------------------------------------- 1 | #! /bin/bash -eu 2 | 3 | g++ -fPIC -c -o libmax.o libmax.cc 4 | g++ -Wl,--hash-style=gnu -shared -Wl,-soname,libmax.so -o libmax.so libmax.o 5 | g++ -Wl,--hash-style=gnu -o main.out main.cc libmax.so 6 | 7 | LD_LIBRARY_PATH=. ../../build/sold main.out -o main.soldout --section-headers --check-output 8 | LD_LIBRARY_PATH=. ./main.soldout 9 | -------------------------------------------------------------------------------- /tests/simple-lib-gcc/test.sh: -------------------------------------------------------------------------------- 1 | #! /bin/bash -eu 2 | 3 | gcc -fPIC -c -o libmax.o libmax.c 4 | gcc -Wl,--hash-style=gnu -shared -Wl,-soname,libmax.so -o libmax.so libmax.o 5 | gcc -Wl,--hash-style=gnu -o main.out main.c libmax.so 6 | 7 | LD_LIBRARY_PATH=. ../../build/sold main.out -o main.soldout --section-headers --check-output 8 | LD_LIBRARY_PATH=. ./main.soldout 9 | -------------------------------------------------------------------------------- /tests/tls-conflict-aarch64/test.sh: -------------------------------------------------------------------------------- 1 | #! /bin/bash -eux 2 | 3 | aarch64-linux-gnu-g++ -fPIC -shared -o libfuga.so -Wl,-soname,libfuga.so fuga.cc 4 | aarch64-linux-gnu-g++ -fPIC -shared -o libhoge.so -Wl,-soname,libhoge.so hoge.cc libfuga.so 5 | aarch64-linux-gnu-g++ -o main main.cc libhoge.so 6 | 7 | LD_LIBRARY_PATH=. qemu-aarch64 -L /usr/aarch64-linux-gnu ./main 8 | -------------------------------------------------------------------------------- /tests/base.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | int base_42(); 4 | int base_add_42(int x); 5 | void base_use_stderr(); 6 | int base_init_value(); 7 | 8 | extern int base_global; 9 | 10 | class Base { 11 | public: 12 | virtual ~Base() {} 13 | virtual int vf() = 0; 14 | }; 15 | 16 | Base* MakeBase(); 17 | 18 | int base_thread_var(); 19 | int base_thread_var_reloc(); 20 | -------------------------------------------------------------------------------- /tests/exception-g++/main.cc: -------------------------------------------------------------------------------- 1 | #include "hoge.h" 2 | 3 | int main() { 4 | std::cout << "catch_exception" << std::endl; 5 | catch_exception_hoge(); 6 | 7 | std::cout << "throw_exception" << std::endl; 8 | try { 9 | throw_exception_hoge(); 10 | } catch (std::exception& e) { 11 | std::cout << e.what() << std::endl; 12 | } 13 | } 14 | -------------------------------------------------------------------------------- /tests/tls-dlopen-gcc/lib.c: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | __thread int tls_with_init_value = 0; 4 | __thread int tls_without_init_value; 5 | 6 | void show_tls_variables() { 7 | tls_with_init_value = 10; 8 | tls_without_init_value = 10; 9 | printf("tls_with_init_value = %d, tls_without_init_value = %d\n", tls_with_init_value, tls_without_init_value); 10 | } 11 | -------------------------------------------------------------------------------- /tests/exception-g++-aarch64/main.cc: -------------------------------------------------------------------------------- 1 | #include "hoge.h" 2 | 3 | int main() { 4 | std::cout << "catch_exception" << std::endl; 5 | catch_exception_hoge(); 6 | 7 | std::cout << "throw_exception" << std::endl; 8 | try { 9 | throw_exception_hoge(); 10 | } catch (std::exception& e) { 11 | std::cout << e.what() << std::endl; 12 | } 13 | } 14 | -------------------------------------------------------------------------------- /tests/exception-str-g++-aarch64/main.cc: -------------------------------------------------------------------------------- 1 | #include "hoge.h" 2 | 3 | int main() { 4 | std::cout << "catch_exception" << std::endl; 5 | catch_exception_hoge(); 6 | 7 | std::cout << "throw_exception" << std::endl; 8 | try { 9 | throw_exception_hoge(); 10 | } catch (std::exception& e) { 11 | std::cout << e.what() << std::endl; 12 | } 13 | } 14 | -------------------------------------------------------------------------------- /tests/tls-dlopen-gcc-aarch64/lib.c: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | __thread int tls_with_init_value = 0; 4 | __thread int tls_without_init_value; 5 | 6 | void show_tls_variables() { 7 | tls_with_init_value = 10; 8 | tls_without_init_value = 10; 9 | printf("tls_with_init_value = %d, tls_without_init_value = %d\n", tls_with_init_value, tls_without_init_value); 10 | } 11 | -------------------------------------------------------------------------------- /tests/lib.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | int lib_42(); 4 | int lib_add_42_via_base(int v); 5 | int in_both_lib_and_base(); 6 | void lib_use_stderr(); 7 | int lib_init_value(); 8 | int lib_base_init_value(); 9 | int lib_base_global(); 10 | int lib_base_vf(); 11 | int lib_base_thread_var(); 12 | int lib_base_thread_var_reloc(); 13 | int lib_thread_var(); 14 | int lib_thread_var_reloc(); 15 | -------------------------------------------------------------------------------- /tests/stb_gnu_unique_tls/test.sh: -------------------------------------------------------------------------------- 1 | #! /bin/bash -eux 2 | 3 | g++ -std=c++17 -fPIC -shared unique.cc -o libunique.so 4 | g++ -std=c++17 -o main main.cc libunique.so 5 | 6 | mv libunique.so libunique.so.original 7 | ../../build/sold -i libunique.so.original -o libunique.so.soldout --section-headers --check-output 8 | ln -sf libunique.so.soldout libunique.so 9 | 10 | LD_LIBRARY_PATH=. ./main 11 | -------------------------------------------------------------------------------- /tests/tls-gcc/main.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | 4 | // thread_local int tls_bss_i; 5 | static int global_x; 6 | thread_local int tls_data_j = 3; 7 | 8 | int main() { 9 | // tls_bss_i = 2; 10 | // printf("tls_bss_i = %d\n", tls_bss_i); 11 | global_x = 2; 12 | printf("global_x = %d\n", global_x); 13 | printf("tls_data_j = %d\n", tls_data_j); 14 | return 0; 15 | } 16 | -------------------------------------------------------------------------------- /tests/tls-gcc-aarch64/main.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | 4 | // thread_local int tls_bss_i; 5 | static int global_x; 6 | thread_local int tls_data_j = 3; 7 | 8 | int main() { 9 | // tls_bss_i = 2; 10 | // printf("tls_bss_i = %d\n", tls_bss_i); 11 | global_x = 2; 12 | printf("global_x = %d\n", global_x); 13 | printf("tls_data_j = %d\n", tls_data_j); 14 | return 0; 15 | } 16 | -------------------------------------------------------------------------------- /tests/dynamic_cast-g++/lib.cc: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | 4 | class Base { 5 | public: 6 | virtual ~Base() {} 7 | }; 8 | class Sub1 : public Base {}; 9 | class Sub2 : public Base {}; 10 | 11 | void TryDowncast() { 12 | Base* base = new Sub1; 13 | Sub2* sub2 = dynamic_cast(base); 14 | if (sub2 == nullptr) { 15 | std::cout << "Downcast failed" << std::endl; 16 | } 17 | } 18 | -------------------------------------------------------------------------------- /tests/version-gcc/libmax2.c: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | int max__1(int a, int b) { 4 | printf("max__1 @ libmax2\n"); 5 | return (a > b ? a : b); 6 | } 7 | 8 | int max__2(int a, int b, int c) { 9 | printf("max__2 @ libmax2\n"); 10 | int r = a > b ? a : b; 11 | r = r > c ? r : c; 12 | return r; 13 | } 14 | 15 | __asm__(".symver max__1,max@LIBMAX_1.0"); 16 | __asm__(".symver max__2,max@@LIBMAX_2.0"); 17 | -------------------------------------------------------------------------------- /tests/setjmp-gcc/main.c: -------------------------------------------------------------------------------- 1 | #include "hoge.h" 2 | 3 | int main() { 4 | printf("call setjmp_longjmp_in_function\n"); 5 | setjmp_longjmp_in_function(); 6 | 7 | printf("call longjmp\n"); 8 | counter = 0; 9 | 10 | setjmp(buf); // set the jump position using buf 11 | printf("counter = %d\n", counter); // Prints a number 12 | counter++; 13 | call_longjmp(); 14 | return 0; 15 | } 16 | -------------------------------------------------------------------------------- /tests/version-gcc-aarch64/libmax2.c: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | int max__1(int a, int b) { 4 | printf("max__1 @ libmax2\n"); 5 | return (a > b ? a : b); 6 | } 7 | 8 | int max__2(int a, int b, int c) { 9 | printf("max__2 @ libmax2\n"); 10 | int r = a > b ? a : b; 11 | r = r > c ? r : c; 12 | return r; 13 | } 14 | 15 | __asm__(".symver max__1,max@LIBMAX_1.0"); 16 | __asm__(".symver max__2,max@@LIBMAX_2.0"); 17 | -------------------------------------------------------------------------------- /tests/dynamic_cast-g++-aarch64/lib.cc: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | 4 | class Base { 5 | public: 6 | virtual ~Base() {} 7 | }; 8 | class Sub1 : public Base {}; 9 | class Sub2 : public Base {}; 10 | 11 | void TryDowncast() { 12 | Base* base = new Sub1; 13 | Sub2* sub2 = dynamic_cast(base); 14 | if (sub2 == nullptr) { 15 | std::cout << "Downcast failed" << std::endl; 16 | } 17 | } 18 | -------------------------------------------------------------------------------- /tests/setjmp-gcc/test.sh: -------------------------------------------------------------------------------- 1 | #! /bin/bash -eux 2 | 3 | gcc -shared -fPIC -Wl,-soname,libhoge.so -o libhoge.so hoge.c 4 | gcc -o main main.c libhoge.so 5 | 6 | mv libhoge.so libhoge.so.original 7 | ../../build/sold -i libhoge.so.original -o libhoge.so.soldout --section-headers 8 | 9 | # Use sold 10 | ln -sf libhoge.so.soldout libhoge.so 11 | 12 | # Use original 13 | # ln -sf lib.so.original lib.so 14 | 15 | LD_LIBRARY_PATH=. ./main 16 | -------------------------------------------------------------------------------- /tests/setjmp-gcc-aarch64/main.c: -------------------------------------------------------------------------------- 1 | #include "hoge.h" 2 | 3 | int main() { 4 | printf("call setjmp_longjmp_in_function\n"); 5 | setjmp_longjmp_in_function(); 6 | 7 | printf("call longjmp\n"); 8 | counter = 0; 9 | 10 | setjmp(buf); // set the jump position using buf 11 | printf("counter = %d\n", counter); // Prints a number 12 | counter++; 13 | call_longjmp(); 14 | return 0; 15 | } 16 | -------------------------------------------------------------------------------- /libtorch_test/torch_test_main_dlopen.cc: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | 5 | int main() { 6 | void* handle; 7 | void (*test)(); 8 | handle = dlopen("libtorch_test.so", RTLD_LAZY); 9 | if (!handle) { 10 | fprintf(stderr, "%s\n", dlerror()); 11 | exit(1); 12 | } 13 | dlerror(); 14 | test = (void (*)())dlsym(handle, "test"); 15 | test(); 16 | return 0; 17 | } 18 | -------------------------------------------------------------------------------- /tests/renamer/test.sh: -------------------------------------------------------------------------------- 1 | #! /bin/bash -eux 2 | 3 | gcc -fPIC -fpic -shared -o libhoge_original.so hoge.c -Wl,-soname,libhoge.so 4 | gcc -fPIC -fpic -shared -o libfugafuga.so fugafuga.c -Wl,-soname,libhoge.so 5 | ln -sf libfugafuga.so libhoge.so 6 | gcc -o use_fugafuga use_fugafuga.c libhoge.so 7 | ../../build/renamer libhoge_original.so --output libhoge_renamed.so --rename-mapping-file mapping 8 | ln -sf libhoge_renamed.so libhoge.so 9 | LD_LIBRARY_PATH=. ./use_fugafuga 10 | -------------------------------------------------------------------------------- /tests/tls-multiple-module-g++/test.sh: -------------------------------------------------------------------------------- 1 | #! /bin/bash -eu 2 | 3 | g++ -shared -fPIC -o libfuga.so -Wl,-soname,libfuga.so fuga.cc 4 | g++ -shared -fPIC -o libhoge.so -Wl,-soname,libhoge.so hoge.cc 5 | g++ -shared -fPIC -o libfugahoge.so.original fugahoge.cc libfuga.so libhoge.so 6 | g++ -o main main.cc -ldl 7 | 8 | LD_LIBRARY_PATH=. ../../build/sold -i libfugahoge.so.original -o libfugahoge.so.soldout --section-headers --check-output 9 | 10 | LD_LIBRARY_PATH=. ./main 11 | -------------------------------------------------------------------------------- /tests/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | set(CMAKE_SKIP_RPATH ON) 2 | 3 | add_library(test_base SHARED base.cc) 4 | 5 | add_library(test_lib SHARED lib.cc) 6 | target_link_libraries(test_lib PRIVATE test_base "-Wl,-R,'$$ORIGIN'") 7 | 8 | add_executable(test_exe exe.cc) 9 | target_link_libraries(test_exe test_lib "-Wl,-R,'$$ORIGIN'") 10 | 11 | add_executable(test_hash exe.cc) 12 | target_link_libraries(test_hash test_lib -Wl,--hash-style=sysv 13 | "-Wl,-R,'$$ORIGIN'") 14 | -------------------------------------------------------------------------------- /tests/static-in-class-g++/test.sh: -------------------------------------------------------------------------------- 1 | #! /bin/bash -eu 2 | 3 | g++ -fPIC -c -o lib.o lib.cc 4 | g++ -shared -Wl,-soname,lib.so -o lib.so lib.o 5 | g++ -Wl,--hash-style=gnu -o main.out main.cc lib.so 6 | 7 | mv lib.so lib.so.original 8 | ../../build/sold -i lib.so.original -o lib.so.soldout --section-headers --check-output 9 | 10 | # Use sold 11 | ln -sf lib.so.soldout lib.so 12 | 13 | # Use original 14 | # ln -sf lib.so.original lib.so 15 | 16 | LD_LIBRARY_PATH=. ./main.out 17 | -------------------------------------------------------------------------------- /tests/tls-dlopen-gcc/test.sh: -------------------------------------------------------------------------------- 1 | #! /bin/bash -eu 2 | 3 | gcc -fPIC -c -o lib.o lib.c 4 | gcc -Wl,--hash-style=gnu -shared -Wl,-soname,lib.so -o lib.so lib.o 5 | gcc -Wl,--hash-style=gnu -o main main.c -ldl 6 | 7 | mv lib.so lib.so.original 8 | ../../build/sold -i lib.so.original -o lib.so.soldout --section-headers --check-output 9 | 10 | # Use sold 11 | ln -sf lib.so.soldout lib.so 12 | 13 | # Use original 14 | # ln -sf lib.so.original lib.so 15 | 16 | LD_LIBRARY_PATH=. ./main 17 | -------------------------------------------------------------------------------- /tests/call_once-g++/test.sh: -------------------------------------------------------------------------------- 1 | #! /bin/bash -eux 2 | 3 | g++ -fPIC -shared -Wl,-soname,libhoge.so -o libhoge.so hoge.cc 4 | g++ -fPIC -shared -Wl,-soname,libfuga.so -o libfuga.so fuga.cc libhoge.so 5 | LD_LIBRARY_PATH=. g++ -o main main.cc libfuga.so -pthread 6 | 7 | mv libfuga.so libfuga.so.original 8 | GLOG_log_dir=. LD_LIBRARY_PATH=. ../../build/sold -i libfuga.so.original -o libfuga.so.soldout --section-headers 9 | ln -sf libfuga.so.soldout libfuga.so 10 | LD_LIBRARY_PATH=. ./main 11 | -------------------------------------------------------------------------------- /tests/setjmp-gcc/hoge.c: -------------------------------------------------------------------------------- 1 | #include "hoge.h" 2 | 3 | int counter = 0; 4 | jmp_buf buf; 5 | 6 | void setjmp_longjmp_in_function() { 7 | int x = 1; 8 | setjmp(buf); // set the jump position using buf 9 | printf("x = %d\n", x); // Prints a number 10 | x++; 11 | if (x <= 5) longjmp(buf, 1); // Jump to the point located by setjmp 12 | } 13 | 14 | void call_longjmp() { 15 | if (counter <= 5) longjmp(buf, 1); // Jump to the point located by setjmp 16 | } 17 | -------------------------------------------------------------------------------- /tests/global-write-aarch64/test.sh: -------------------------------------------------------------------------------- 1 | #! /bin/bash -eux 2 | 3 | aarch64-linux-gnu-gcc -fPIC -shared -o libhoge.so -Wl,-soname,libhoge.so hoge.c 4 | aarch64-linux-gnu-gcc -o main main.c libhoge.so 5 | 6 | mv libhoge.so libhoge.so.original 7 | ../../build/sold -i libhoge.so.original -o libhoge.so.soldout --section-headers --check-output --custom-library-path /usr/aarch64-linux-gnu/lib 8 | ln -sf libhoge.so.soldout libhoge.so 9 | 10 | LD_LIBRARY_PATH=. qemu-aarch64 -L /usr/aarch64-linux-gnu ./main 11 | -------------------------------------------------------------------------------- /tests/inheritance-g++/test.sh: -------------------------------------------------------------------------------- 1 | #! /bin/bash -eu 2 | 3 | g++ -fPIC -c -o lib.o lib.cc 4 | g++ -Wl,--hash-style=gnu -shared -Wl,-soname,lib.so -o lib.so lib.o 5 | g++ -Wl,--hash-style=gnu -o main.out main.cc lib.so 6 | 7 | mv lib.so lib.so.original 8 | ../../build/sold -i lib.so.original -o lib.so.soldout --section-headers --check-output 9 | 10 | # Use sold 11 | ln -sf lib.so.soldout lib.so 12 | 13 | # Use original 14 | # ln -sf lib.so.original lib.so 15 | 16 | LD_LIBRARY_PATH=. ./main.out 17 | -------------------------------------------------------------------------------- /tests/setjmp-gcc-aarch64/hoge.c: -------------------------------------------------------------------------------- 1 | #include "hoge.h" 2 | 3 | int counter = 0; 4 | jmp_buf buf; 5 | 6 | void setjmp_longjmp_in_function() { 7 | int x = 1; 8 | setjmp(buf); // set the jump position using buf 9 | printf("x = %d\n", x); // Prints a number 10 | x++; 11 | if (x <= 5) longjmp(buf, 1); // Jump to the point located by setjmp 12 | } 13 | 14 | void call_longjmp() { 15 | if (counter <= 5) longjmp(buf, 1); // Jump to the point located by setjmp 16 | } 17 | -------------------------------------------------------------------------------- /tests/inheritance-g++/lib.cc: -------------------------------------------------------------------------------- 1 | #include "lib.h" 2 | 3 | void B::Speak() { 4 | std::cout << "I am B." << std::endl; 5 | } 6 | 7 | void C::Speak() { 8 | std::cout << "I am C." << std::endl; 9 | } 10 | 11 | void JustHelloFun() { 12 | std::cout << "Hello from lib" << std::endl; 13 | 14 | B* bptr = new B; 15 | C* cptr = new C; 16 | 17 | A* aptr = bptr; 18 | aptr->Speak(); 19 | aptr = cptr; 20 | aptr->Speak(); 21 | 22 | delete bptr; 23 | delete cptr; 24 | } 25 | -------------------------------------------------------------------------------- /tests/exception-g++/hoge.cc: -------------------------------------------------------------------------------- 1 | #include "hoge.h" 2 | #include "fuga.h" 3 | 4 | void throw_exception_hoge() { 5 | throw std::runtime_error("hoge"); 6 | } 7 | 8 | void catch_exception_hoge() { 9 | try { 10 | throw_exception_hoge(); 11 | } catch (std::exception& e) { 12 | std::cout << e.what() << std::endl; 13 | } 14 | 15 | try { 16 | throw_exception_fuga(); 17 | } catch (std::exception& e) { 18 | std::cout << e.what() << std::endl; 19 | } 20 | } 21 | -------------------------------------------------------------------------------- /tests/mprotect/test.sh: -------------------------------------------------------------------------------- 1 | #! /bin/bash 2 | 3 | gcc -shared -fPIC base.c -o base.so -Wl,-soname,base.so 4 | gcc -shared -fPIC mprotect_check.c base.so -o mprotect_check.so 5 | gcc main.c mprotect_check.so -o main 6 | 7 | LD_LIBRARY_PATH=. ../../build/sold -i mprotect_check.so -o mprotect_check.so.soldout 8 | mv mprotect_check.so mprotect_check.so.original 9 | ln -sf mprotect_check.so.soldout mprotect_check.so 10 | # ln -sf mprotect_check.so.original mprotect_check.so 11 | 12 | LD_LIBRARY_PATH=. ./main 13 | -------------------------------------------------------------------------------- /tests/simple-lib-g++-aarch64/test.sh: -------------------------------------------------------------------------------- 1 | #! /bin/bash -eu 2 | 3 | aarch64-linux-gnu-g++ -fPIC -c -o libmax.o libmax.cc 4 | aarch64-linux-gnu-g++ -Wl,--hash-style=gnu -shared -Wl,-soname,libmax.so -o libmax.so libmax.o 5 | aarch64-linux-gnu-g++ -Wl,--hash-style=gnu -o main.out main.cc libmax.so 6 | 7 | LD_LIBRARY_PATH=. ../../build/sold main.out -o main.soldout --section-headers --check-output --custom-library-path /usr/aarch64-linux-gnu/lib 8 | LD_LIBRARY_PATH=. qemu-aarch64 -L /usr/aarch64-linux-gnu ./main.soldout 9 | -------------------------------------------------------------------------------- /tests/simple-lib-gcc-aarch64/test.sh: -------------------------------------------------------------------------------- 1 | #! /bin/bash -eu 2 | 3 | aarch64-linux-gnu-gcc -fPIC -c -o libmax.o libmax.c 4 | aarch64-linux-gnu-gcc -Wl,--hash-style=gnu -shared -Wl,-soname,libmax.so -o libmax.so libmax.o 5 | aarch64-linux-gnu-gcc -Wl,--hash-style=gnu -o main.out main.c libmax.so 6 | 7 | LD_LIBRARY_PATH=. ../../build/sold main.out -o main.soldout --section-headers --check-output --custom-library-path /usr/aarch64-linux-gnu/lib 8 | LD_LIBRARY_PATH=. qemu-aarch64 -L /usr/aarch64-linux-gnu ./main.soldout 9 | -------------------------------------------------------------------------------- /tests/tls-thread-g++/test.sh: -------------------------------------------------------------------------------- 1 | #! /bin/bash -eu 2 | 3 | g++ -fPIC -c -o lib.o lib.cc 4 | g++ -lpthread -Wl,--hash-style=gnu -shared -Wl,-soname,lib.so -o lib.so lib.o 5 | g++ -Wl,--hash-style=gnu -o main main.cc lib.so -lpthread 6 | 7 | mv lib.so lib.so.original 8 | ../../build/sold -i lib.so.original -o lib.so.soldout --section-headers --check-output 9 | 10 | # Use sold 11 | ln -sf lib.so.soldout lib.so 12 | 13 | # Use original 14 | # ln -sf lib.so.original lib.so 15 | 16 | LD_LIBRARY_PATH=. ./main 17 | -------------------------------------------------------------------------------- /tests/inheritance-g++-aarch64/lib.cc: -------------------------------------------------------------------------------- 1 | #include "lib.h" 2 | 3 | void B::Speak() { 4 | std::cout << "I am B." << std::endl; 5 | } 6 | 7 | void C::Speak() { 8 | std::cout << "I am C." << std::endl; 9 | } 10 | 11 | void JustHelloFun() { 12 | std::cout << "Hello from lib" << std::endl; 13 | 14 | B* bptr = new B; 15 | C* cptr = new C; 16 | 17 | A* aptr = bptr; 18 | aptr->Speak(); 19 | aptr = cptr; 20 | aptr->Speak(); 21 | 22 | delete bptr; 23 | delete cptr; 24 | } 25 | -------------------------------------------------------------------------------- /tests/unique_ptr-aarch64/test.sh: -------------------------------------------------------------------------------- 1 | #! /bin/bash -eux 2 | 3 | aarch64-linux-gnu-g++ -fPIC -shared -o libhoge.so -Wl,-soname,libhoge.so hoge.cc 4 | aarch64-linux-gnu-g++ -o main main.cc libhoge.so 5 | 6 | mv libhoge.so libhoge.so.original 7 | GLOG_log_dir=. ../../build/sold -i libhoge.so.original -o libhoge.so.soldout --section-headers --check-output --custom-library-path /usr/aarch64-linux-gnu/lib 8 | ln -sf libhoge.so.soldout libhoge.so 9 | 10 | LD_LIBRARY_PATH=. qemu-aarch64 -L /usr/aarch64-linux-gnu ./main 11 | -------------------------------------------------------------------------------- /tests/exception-g++-aarch64/hoge.cc: -------------------------------------------------------------------------------- 1 | #include "hoge.h" 2 | #include "fuga.h" 3 | 4 | void throw_exception_hoge() { 5 | throw std::runtime_error("hoge"); 6 | } 7 | 8 | void catch_exception_hoge() { 9 | try { 10 | throw_exception_hoge(); 11 | } catch (std::exception& e) { 12 | std::cout << e.what() << std::endl; 13 | } 14 | 15 | try { 16 | throw_exception_fuga(); 17 | } catch (std::exception& e) { 18 | std::cout << e.what() << std::endl; 19 | } 20 | } 21 | -------------------------------------------------------------------------------- /tests/static-in-function-g++/test.sh: -------------------------------------------------------------------------------- 1 | #! /bin/bash -eu 2 | 3 | g++ -fPIC -c -o lib.o lib.cc 4 | g++ -lpthread -Wl,--hash-style=gnu -shared -Wl,-soname,lib.so -o lib.so lib.o 5 | g++ -Wl,--hash-style=gnu -o main.out main.cc lib.so -lpthread 6 | 7 | mv lib.so lib.so.original 8 | ../../build/sold -i lib.so.original -o lib.so.soldout --section-headers --check-output 9 | 10 | # Use sold 11 | ln -sf lib.so.soldout lib.so 12 | 13 | # Use original 14 | # ln -sf lib.so.original lib.so 15 | 16 | LD_LIBRARY_PATH=. ./main.out 17 | -------------------------------------------------------------------------------- /tests/stb_gnu_unique_tls-aarch64/test.sh: -------------------------------------------------------------------------------- 1 | #! /bin/bash -eux 2 | 3 | aarch64-linux-gnu-g++ -std=c++17 -fPIC -shared unique.cc -o libunique.so 4 | aarch64-linux-gnu-g++ -std=c++17 -o main main.cc libunique.so 5 | 6 | mv libunique.so libunique.so.original 7 | ../../build/sold -i libunique.so.original -o libunique.so.soldout --section-headers --check-output --custom-library-path /usr/aarch64-linux-gnu/lib 8 | ln -sf libunique.so.soldout libunique.so 9 | 10 | LD_LIBRARY_PATH=. qemu-aarch64 -L /usr/aarch64-linux-gnu ./main 11 | -------------------------------------------------------------------------------- /tests/exception-g++/test.sh: -------------------------------------------------------------------------------- 1 | #! /bin/bash -eu 2 | 3 | g++ -fPIC -shared -o libfuga.so -Wl,-soname,libfuga.so fuga.cc 4 | g++ -fPIC -shared -o libhoge.so.original -Wl,-soname,libhoge.so hoge.cc libfuga.so 5 | g++ main.cc -o main.out libhoge.so.original libfuga.so 6 | LD_LIBRARY_PATH=. ../../build/sold -i libhoge.so.original -o libhoge.so.soldout --section-headers --check-output 7 | 8 | # Use sold 9 | ln -sf libhoge.so.soldout libhoge.so 10 | # Use original 11 | # ln -sf libhoge.so.original libhoge.so 12 | 13 | LD_LIBRARY_PATH=. ./main.out 14 | -------------------------------------------------------------------------------- /tests/exception-str-g++-aarch64/fuga.cc: -------------------------------------------------------------------------------- 1 | #include "fuga.h" 2 | 3 | void throw_exception_fuga() { 4 | std::cout << "QWERHOGETYUIOPASDFGHJKLZXCVBNM" << std::endl; 5 | throw std::runtime_error("fuga"); 6 | } 7 | 8 | void catch_exception_fuga() { 9 | try { 10 | std::cout << "QWERTYUIOPASDFGHJKLZXCVBNM" << std::endl; 11 | throw_exception_fuga(); 12 | } catch (std::exception& e) { 13 | std::cout << "QWERHOGETYUIOPASDFGHJKLZXCVBNM" << std::endl; 14 | std::cout << e.what() << std::endl; 15 | } 16 | } 17 | -------------------------------------------------------------------------------- /tools/search-symbol.sh: -------------------------------------------------------------------------------- 1 | #! /bin/bash 2 | # This shellscript find all shared object which contains the specified 3 | # symbol. 4 | 5 | if [ -z $1 ] 6 | then 7 | echo You must specify the name of the symbol. 8 | exit 1 9 | fi 10 | 11 | sym=$1 12 | sos=`ldconfig -p | awk -F '=>' '{print $2}' | grep so | sort | uniq` 13 | 14 | for s in ${sos} 15 | do 16 | PRE_IFS=$IFS 17 | IFS=$'\n' 18 | for l in `readelf -s $s | grep -e ${sym} | grep -v UND` 19 | do 20 | echo ${l} in ${s} 21 | done 22 | IFS=$PRE_IFS 23 | done 24 | -------------------------------------------------------------------------------- /tests/setjmp-gcc-aarch64/test.sh: -------------------------------------------------------------------------------- 1 | #! /bin/bash -eux 2 | 3 | aarch64-linux-gnu-gcc -shared -fPIC -Wl,-soname,libhoge.so -o libhoge.so hoge.c 4 | aarch64-linux-gnu-gcc -o main main.c libhoge.so 5 | 6 | mv libhoge.so libhoge.so.original 7 | ../../build/sold -i libhoge.so.original -o libhoge.so.soldout --section-headers --custom-library-path /usr/aarch64-linux-gnu/lib 8 | 9 | # Use sold 10 | ln -sf libhoge.so.soldout libhoge.so 11 | 12 | # Use original 13 | # ln -sf lib.so.original lib.so 14 | 15 | LD_LIBRARY_PATH=. qemu-aarch64 -L /usr/aarch64-linux-gnu ./main 16 | -------------------------------------------------------------------------------- /third_party/glog.cmake: -------------------------------------------------------------------------------- 1 | cmake_minimum_required(VERSION 3.4) 2 | project(glog-download NONE) 3 | 4 | include(ExternalProject) 5 | ExternalProject_Add(glog 6 | GIT_REPOSITORY https://github.com/google/glog.git 7 | GIT_TAG v0.4.0 8 | SOURCE_DIR "${CMAKE_CURRENT_BINARY_DIR}/glog" 9 | BINARY_DIR "" 10 | CONFIGURE_COMMAND "" 11 | BUILD_COMMAND "" 12 | INSTALL_COMMAND "" 13 | TEST_COMMAND "" 14 | CMAKE_ARGS 15 | -DCMAKE_INSTALL_MESSAGE=LAZY 16 | -DCMAKE_POSITION_INDEPENDENT_CODE=ON 17 | ) 18 | -------------------------------------------------------------------------------- /third_party/pybind11.cmake: -------------------------------------------------------------------------------- 1 | cmake_minimum_required(VERSION 3.4) 2 | project(glog-download NONE) 3 | 4 | include(ExternalProject) 5 | ExternalProject_Add(pybind11 6 | GIT_REPOSITORY https://github.com/pybind/pybind11 7 | GIT_TAG v2.6.2 8 | SOURCE_DIR "${CMAKE_CURRENT_BINARY_DIR}/pybind11" 9 | BINARY_DIR "" 10 | CONFIGURE_COMMAND "" 11 | BUILD_COMMAND "" 12 | INSTALL_COMMAND "" 13 | TEST_COMMAND "" 14 | CMAKE_ARGS 15 | -DCMAKE_INSTALL_MESSAGE=LAZY 16 | -DCMAKE_POSITION_INDEPENDENT_CODE=ON 17 | ) 18 | -------------------------------------------------------------------------------- /pybind_test/add.cc: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | namespace py = pybind11; 4 | using namespace pybind11::literals; 5 | 6 | int add(int i, int j) { 7 | return i + j; 8 | } 9 | 10 | PYBIND11_MODULE(myadd, m) { 11 | m.doc() = "pybind11 example plugin"; // optional module docstring 12 | m.def("myadd", &add, "A function which adds two numbers"); 13 | m.def("myadd2", &add, "i"_a, "j"_a); 14 | m.def("myadd3", &add, "i"_a = 1, "j"_a = 2); 15 | 16 | m.attr("the_answer") = 42; 17 | py::object world = py::cast("World"); 18 | m.attr("what") = world; 19 | } 20 | -------------------------------------------------------------------------------- /tests/tls-thread-g++/main.cc: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | #include "lib.h" 4 | 5 | int main() { 6 | int t1_id1, t1_id2; 7 | std::thread t1([&t1_id1, &t1_id2] { 8 | t1_id1 = create_id(); 9 | t1_id2 = create_id(); 10 | }); 11 | 12 | int t2_id1, t2_id2; 13 | std::thread t2([&t2_id1, &t2_id2] { 14 | t2_id1 = create_id(); 15 | t2_id2 = create_id(); 16 | }); 17 | 18 | t1.join(); 19 | t2.join(); 20 | 21 | std::cout << "t1_id1=" << t1_id1 << " t1_id2=" << t1_id2 << " t2_id1=" << t2_id1 << " t2_id2=" << t2_id2 << std::endl; 22 | } 23 | -------------------------------------------------------------------------------- /tests/typeid-g++/test.sh: -------------------------------------------------------------------------------- 1 | #! /bin/bash -eu 2 | 3 | g++ -fPIC -c -o lib.o lib.cc 4 | g++ -Wl,--hash-style=gnu -shared -Wl,-soname,lib.so -o lib.so lib.o 5 | g++ -Wl,--hash-style=gnu -o main main.cc lib.so 6 | 7 | mv lib.so lib.so.original 8 | ../../build/sold -i lib.so.original -o lib.so.soldout --section-headers --check-output 9 | 10 | # Use sold 11 | ln -sf lib.so.soldout lib.so 12 | echo ----------- Use sold ----------- 13 | LD_LIBRARY_PATH=. ./main 14 | 15 | # Use original 16 | ln -sf lib.so.original lib.so 17 | echo ----------- Use original ----------- 18 | LD_LIBRARY_PATH=. ./main 19 | -------------------------------------------------------------------------------- /tests/dynamic_cast-g++/test.sh: -------------------------------------------------------------------------------- 1 | #! /bin/bash -eu 2 | 3 | g++ -fPIC -c -o lib.o lib.cc 4 | g++ -Wl,--hash-style=gnu -shared -Wl,-soname,lib.so -o lib.so lib.o 5 | g++ -Wl,--hash-style=gnu -o main main.cc lib.so 6 | 7 | mv lib.so lib.so.original 8 | ../../build/sold -i lib.so.original -o lib.so.soldout --section-headers --check-output 9 | 10 | # Use sold 11 | ln -sf lib.so.soldout lib.so 12 | echo ----------- Use sold ----------- 13 | LD_LIBRARY_PATH=. ./main 14 | 15 | # Use original 16 | ln -sf lib.so.original lib.so 17 | echo ----------- Use original ----------- 18 | LD_LIBRARY_PATH=. ./main 19 | -------------------------------------------------------------------------------- /tests/typeid-g++/lib.cc: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | 4 | class Base { 5 | public: 6 | virtual void f() {} 7 | }; 8 | 9 | class Derived : public Base {}; 10 | 11 | void PrintTypeid() { 12 | Base b; 13 | Derived d; 14 | Base* p1 = &b; 15 | Base* p2 = &d; 16 | 17 | std::cout << typeid(b).name() << "\n" 18 | << typeid(d).name() << "\n" 19 | << typeid(p1).name() << "\n" 20 | << typeid(*p1).name() << "\n" 21 | << typeid(p2).name() << "\n" 22 | << typeid(*p2).name() << std::endl; 23 | } 24 | -------------------------------------------------------------------------------- /tools/relocation-list-up.sh: -------------------------------------------------------------------------------- 1 | #! /bin/bash 2 | # List up all relocation entries for the given shared object. 3 | # When you give the second argument, this script filter the output with it. 4 | # ./relocation-check.sh SHARED_OBJECT [RELOCATION_ENTRY] 5 | 6 | depends=$(ldd $1 | awk 'NR>1' | awk '{print $3}') 7 | 8 | for d in $1 ${depends} 9 | do 10 | if [ -z $2 ] 11 | then 12 | relos=$(readelf -r ${d}) 13 | else 14 | relos=$(readelf -r ${d} | grep $2) 15 | fi 16 | IFS=$'\n' 17 | for r in ${relos} 18 | do 19 | echo ${d} ${r} 20 | done 21 | done 22 | -------------------------------------------------------------------------------- /tests/tls-thread-g++-aarch64/main.cc: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | #include "lib.h" 4 | 5 | int main() { 6 | int t1_id1, t1_id2; 7 | std::thread t1([&t1_id1, &t1_id2] { 8 | t1_id1 = create_id(); 9 | t1_id2 = create_id(); 10 | }); 11 | 12 | int t2_id1, t2_id2; 13 | std::thread t2([&t2_id1, &t2_id2] { 14 | t2_id1 = create_id(); 15 | t2_id2 = create_id(); 16 | }); 17 | 18 | t1.join(); 19 | t2.join(); 20 | 21 | std::cout << "t1_id1=" << t1_id1 << " t1_id2=" << t1_id2 << " t2_id1=" << t2_id1 << " t2_id2=" << t2_id2 << std::endl; 22 | } 23 | -------------------------------------------------------------------------------- /tests/typeid-g++-aarch64/lib.cc: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | 4 | class Base { 5 | public: 6 | virtual void f() {} 7 | }; 8 | 9 | class Derived : public Base {}; 10 | 11 | void PrintTypeid() { 12 | Base b; 13 | Derived d; 14 | Base* p1 = &b; 15 | Base* p2 = &d; 16 | 17 | std::cout << typeid(b).name() << "\n" 18 | << typeid(d).name() << "\n" 19 | << typeid(p1).name() << "\n" 20 | << typeid(*p1).name() << "\n" 21 | << typeid(p2).name() << "\n" 22 | << typeid(*p2).name() << std::endl; 23 | } 24 | -------------------------------------------------------------------------------- /tests/static-in-class-g++-aarch64/test.sh: -------------------------------------------------------------------------------- 1 | #! /bin/bash -eu 2 | 3 | aarch64-linux-gnu-g++ -fPIC -c -o lib.o lib.cc 4 | aarch64-linux-gnu-g++ -shared -Wl,-soname,lib.so -o lib.so lib.o 5 | aarch64-linux-gnu-g++ -Wl,--hash-style=gnu -o main.out main.cc lib.so 6 | 7 | mv lib.so lib.so.original 8 | ../../build/sold -i lib.so.original -o lib.so.soldout --section-headers --check-output --custom-library-path /usr/aarch64-linux-gnu/lib 9 | 10 | # Use sold 11 | ln -sf lib.so.soldout lib.so 12 | 13 | # Use original 14 | # ln -sf lib.so.original lib.so 15 | 16 | LD_LIBRARY_PATH=. qemu-aarch64 -L /usr/aarch64-linux-gnu ./main.out 17 | -------------------------------------------------------------------------------- /tests/tls-dlopen-gcc-aarch64/test.sh: -------------------------------------------------------------------------------- 1 | #! /bin/bash -eu 2 | 3 | aarch64-linux-gnu-gcc -fPIC -c -o lib.o lib.c 4 | aarch64-linux-gnu-gcc -Wl,--hash-style=gnu -shared -Wl,-soname,lib.so -o lib.so lib.o 5 | aarch64-linux-gnu-gcc -Wl,--hash-style=gnu -o main main.c -ldl 6 | 7 | mv lib.so lib.so.original 8 | ../../build/sold -i lib.so.original -o lib.so.soldout --section-headers --check-output --custom-library-path /usr/aarch64-linux-gnu/lib 9 | 10 | # Use sold 11 | ln -sf lib.so.soldout lib.so 12 | 13 | # Use original 14 | # ln -sf lib.so.original lib.so 15 | 16 | LD_LIBRARY_PATH=. qemu-aarch64 -L /usr/aarch64-linux-gnu ./main 17 | -------------------------------------------------------------------------------- /tests/tls-lib-gcc-without-base/test.sh: -------------------------------------------------------------------------------- 1 | #! /bin/bash -eu 2 | 3 | gcc -fPIC -c -o lib.o lib.c 4 | gcc -fPIC -c -o base.o base.c 5 | 6 | gcc -Wl,--hash-style=gnu -shared -Wl,-soname,base.so -o original/base.so base.o 7 | gcc -Wl,--hash-style=gnu -shared -Wl,-soname,lib.so -o original/lib.so lib.o original/base.so 8 | 9 | gcc -Wl,--hash-style=gnu -o main.out main.c original/lib.so original/base.so 10 | 11 | cp original/base.so sold_out/base.so 12 | 13 | LD_LIBRARY_PATH=original ../../build/sold original/lib.so -o sold_out/lib.so --section-headers --exclude-so base.so --check-output 14 | LD_LIBRARY_PATH=sold_out ./main.out 15 | -------------------------------------------------------------------------------- /tests/tls-multiple-module-g++-aarch64/test.sh: -------------------------------------------------------------------------------- 1 | #! /bin/bash -eu 2 | 3 | aarch64-linux-gnu-g++ -shared -fPIC -o libfuga.so -Wl,-soname,libfuga.so fuga.cc 4 | aarch64-linux-gnu-g++ -shared -fPIC -o libhoge.so -Wl,-soname,libhoge.so hoge.cc 5 | aarch64-linux-gnu-g++ -shared -fPIC -o libfugahoge.so.original fugahoge.cc libfuga.so libhoge.so 6 | aarch64-linux-gnu-g++ -o main main.cc -ldl 7 | 8 | LD_LIBRARY_PATH=. ../../build/sold -i libfugahoge.so.original -o libfugahoge.so.soldout --section-headers --check-output --custom-library-path /usr/aarch64-linux-gnu/lib 9 | 10 | LD_LIBRARY_PATH=. qemu-aarch64 -L /usr/aarch64-linux-gnu ./main 11 | -------------------------------------------------------------------------------- /ubuntu18.04.Dockerfile: -------------------------------------------------------------------------------- 1 | FROM ubuntu:18.04 2 | RUN apt-get update 3 | RUN apt-get install -y ninja-build cmake gcc g++ git python3 python3-distutils python3-dev python3-pip g++-aarch64-linux-gnu qemu qemu-system-aarch64 qemu-user 4 | RUN pip3 install pytest numpy torch==1.8.0+cpu -f https://download.pytorch.org/whl/torch_stable.html 5 | COPY . /sold 6 | WORKDIR /sold 7 | RUN rm -rf build 8 | RUN mkdir build && cd build && cmake -DTorch_DIR=$(python3 -c "import site; print (site.getsitepackages()[0])")/torch/share/cmake/Torch -GNinja -DSOLD_PYBIND_TEST=ON -DSOLD_LIBTORCH_TEST=ON .. 9 | RUN cmake --build build 10 | RUN cd build && ctest 11 | -------------------------------------------------------------------------------- /tests/call_once-g++-aarch64/test.sh: -------------------------------------------------------------------------------- 1 | #! /bin/bash -eux 2 | 3 | aarch64-linux-gnu-g++ -fPIC -shared -Wl,-soname,libhoge.so -o libhoge.so hoge.cc 4 | aarch64-linux-gnu-g++ -fPIC -shared -Wl,-soname,libfuga.so -o libfuga.so fuga.cc libhoge.so 5 | LD_LIBRARY_PATH=. aarch64-linux-gnu-g++ -o main main.cc libfuga.so libhoge.so -pthread 6 | 7 | mv libfuga.so libfuga.so.original 8 | GLOG_log_dir=. LD_LIBRARY_PATH=. ../../build/sold -i libfuga.so.original -o libfuga.so.soldout --section-headers --custom-library-path /usr/aarch64-linux-gnu/lib 9 | ln -sf libfuga.so.soldout libfuga.so 10 | LD_LIBRARY_PATH=. qemu-aarch64 -L /usr/aarch64-linux-gnu ./main 11 | -------------------------------------------------------------------------------- /tests/inheritance-g++-aarch64/test.sh: -------------------------------------------------------------------------------- 1 | #! /bin/bash -eu 2 | 3 | aarch64-linux-gnu-g++ -fPIC -c -o lib.o lib.cc 4 | aarch64-linux-gnu-g++ -Wl,--hash-style=gnu -shared -Wl,-soname,lib.so -o lib.so lib.o 5 | aarch64-linux-gnu-g++ -Wl,--hash-style=gnu -o main.out main.cc lib.so 6 | 7 | mv lib.so lib.so.original 8 | ../../build/sold -i lib.so.original -o lib.so.soldout --section-headers --check-output --custom-library-path /usr/aarch64-linux-gnu/lib 9 | 10 | # Use sold 11 | ln -sf lib.so.soldout lib.so 12 | 13 | # Use original 14 | # ln -sf lib.so.original lib.so 15 | 16 | LD_LIBRARY_PATH=. qemu-aarch64 -L /usr/aarch64-linux-gnu ./main.out 17 | -------------------------------------------------------------------------------- /tools/listup_duplicated_syms.py: -------------------------------------------------------------------------------- 1 | # How to use 2 | # readelf --dyn-syms --wide hoge.so | python3 listup_duplicated_syms.py 3 | 4 | import sys 5 | 6 | alllines = sys.stdin.readlines() 7 | head = alllines[:3] 8 | lines = alllines[4:] 9 | symcount = dict() 10 | 11 | for l in lines: 12 | ws = l.split() 13 | name = ws[7].split('@')[0] 14 | if name in symcount: 15 | symcount[name] += 1 16 | else: 17 | symcount[name] = 1 18 | 19 | for l in head: 20 | print(l, end="") 21 | 22 | for l in lines: 23 | ws = l.split() 24 | name = ws[7].split('@')[0] 25 | if symcount[name] >= 2: 26 | print(l,end="") 27 | -------------------------------------------------------------------------------- /tests/exception-str-g++-aarch64/hoge.cc: -------------------------------------------------------------------------------- 1 | #include "hoge.h" 2 | #include "fuga.h" 3 | 4 | void throw_exception_hoge() { 5 | throw std::runtime_error("hoge"); 6 | } 7 | 8 | void catch_exception_hoge() { 9 | try { 10 | std::cout << "QWERTYUIOPASDFGHJKLZXCVBNM" << std::endl; 11 | throw_exception_hoge(); 12 | } catch (std::exception& e) { 13 | std::cout << e.what() << std::endl; 14 | } 15 | 16 | try { 17 | std::cout << "QWERTYUIOPASDFGHJKLZXCVBNM" << std::endl; 18 | throw_exception_fuga(); 19 | } catch (std::exception& e) { 20 | std::cout << e.what() << std::endl; 21 | } 22 | } 23 | -------------------------------------------------------------------------------- /tests/mprotect-aarch64/test.sh: -------------------------------------------------------------------------------- 1 | #! /bin/bash 2 | 3 | aarch64-linux-gnu-gcc -shared -fPIC base.c -o base.so -Wl,-soname,base.so 4 | aarch64-linux-gnu-gcc -shared -fPIC mprotect_check.c base.so -o mprotect_check.so 5 | aarch64-linux-gnu-gcc main.c mprotect_check.so -o main 6 | 7 | LD_LIBRARY_PATH=. ../../build/sold -i mprotect_check.so -o mprotect_check.so.soldout --custom-library-path /usr/aarch64-linux-gnu/lib 8 | mv mprotect_check.so mprotect_check.so.original 9 | ln -sf mprotect_check.so.soldout mprotect_check.so 10 | # ln -sf mprotect_check.so.original mprotect_check.so 11 | 12 | LD_LIBRARY_PATH=. qemu-aarch64 -L /usr/aarch64-linux-gnu ./main 13 | -------------------------------------------------------------------------------- /tests/tls-thread-g++-aarch64/test.sh: -------------------------------------------------------------------------------- 1 | #! /bin/bash -eu 2 | 3 | aarch64-linux-gnu-g++ -fPIC -c -o lib.o lib.cc 4 | aarch64-linux-gnu-g++ -lpthread -Wl,--hash-style=gnu -shared -Wl,-soname,lib.so -o lib.so lib.o 5 | aarch64-linux-gnu-g++ -Wl,--hash-style=gnu -o main main.cc lib.so -lpthread 6 | 7 | mv lib.so lib.so.original 8 | ../../build/sold -i lib.so.original -o lib.so.soldout --section-headers --check-output --custom-library-path /usr/aarch64-linux-gnu/lib 9 | 10 | # Use sold 11 | ln -sf lib.so.soldout lib.so 12 | 13 | # Use original 14 | # ln -sf lib.so.original lib.so 15 | 16 | LD_LIBRARY_PATH=. qemu-aarch64 -L /usr/aarch64-linux-gnu ./main 17 | -------------------------------------------------------------------------------- /tests/static-in-function-g++-aarch64/test.sh: -------------------------------------------------------------------------------- 1 | #! /bin/bash -eu 2 | 3 | aarch64-linux-gnu-g++ -fPIC -c -o lib.o lib.cc 4 | aarch64-linux-gnu-g++ -lpthread -Wl,--hash-style=gnu -shared -Wl,-soname,lib.so -o lib.so lib.o 5 | aarch64-linux-gnu-g++ -Wl,--hash-style=gnu -o main.out main.cc lib.so -lpthread 6 | 7 | mv lib.so lib.so.original 8 | ../../build/sold -i lib.so.original -o lib.so.soldout --section-headers --check-output --custom-library-path /usr/aarch64-linux-gnu/lib 9 | 10 | # Use sold 11 | ln -sf lib.so.soldout lib.so 12 | 13 | # Use original 14 | # ln -sf lib.so.original lib.so 15 | 16 | LD_LIBRARY_PATH=. qemu-aarch64 -L /usr/aarch64-linux-gnu ./main.out 17 | -------------------------------------------------------------------------------- /ubuntu20.04.Dockerfile: -------------------------------------------------------------------------------- 1 | FROM ubuntu:20.04 2 | ENV DEBIAN_FRONTEND=noninteractive 3 | RUN apt-get update 4 | RUN apt-get install -y ninja-build cmake gcc g++ git python3 python3-distutils python3-dev python3-pip g++-aarch64-linux-gnu qemu qemu-system-aarch64 qemu-user 5 | RUN pip3 install pytest numpy torch==1.8.0+cpu -f https://download.pytorch.org/whl/torch_stable.html 6 | COPY . /sold 7 | WORKDIR /sold 8 | RUN rm -rf build 9 | RUN mkdir build && cd build && cmake -DTorch_DIR=$(python3 -c "import site; print (site.getsitepackages()[0])")/torch/share/cmake/Torch -GNinja -DSOLD_PYBIND_TEST=ON -DSOLD_LIBTORCH_TEST=ON .. 10 | RUN cmake --build build 11 | RUN cd build && ctest 12 | -------------------------------------------------------------------------------- /tests/exception-str-g++-aarch64/test.sh: -------------------------------------------------------------------------------- 1 | #! /bin/bash -eu 2 | 3 | aarch64-linux-gnu-g++ -fPIC -shared -o libfuga.so -Wl,-soname,libfuga.so fuga.cc 4 | aarch64-linux-gnu-g++ -fPIC -shared -o libhoge.so.original -Wl,-soname,libhoge.so hoge.cc libfuga.so 5 | aarch64-linux-gnu-g++ main.cc -o main libhoge.so.original libfuga.so 6 | LD_LIBRARY_PATH=. ../../build/sold -i libhoge.so.original -o libhoge.so.soldout --section-headers --check-output --custom-library-path /usr/aarch64-linux-gnu/lib 7 | 8 | # Use sold 9 | ln -sf libhoge.so.soldout libhoge.so 10 | # Use original 11 | # ln -sf libhoge.so.original libhoge.so 12 | 13 | LD_LIBRARY_PATH=. qemu-aarch64 -L /usr/aarch64-linux-gnu ./main 14 | -------------------------------------------------------------------------------- /tests/exception-g++-aarch64/test.sh: -------------------------------------------------------------------------------- 1 | #! /bin/bash -eu 2 | 3 | aarch64-linux-gnu-g++ -fPIC -shared -o libfuga.so -Wl,-soname,libfuga.so fuga.cc 4 | aarch64-linux-gnu-g++ -fPIC -shared -o libhoge.so.original -Wl,-soname,libhoge.so hoge.cc libfuga.so 5 | aarch64-linux-gnu-g++ main.cc -o main.out libhoge.so.original libfuga.so 6 | LD_LIBRARY_PATH=. ../../build/sold -i libhoge.so.original -o libhoge.so.soldout --section-headers --check-output --custom-library-path /usr/aarch64-linux-gnu/lib 7 | 8 | # Use sold 9 | ln -sf libhoge.so.soldout libhoge.so 10 | # Use original 11 | # ln -sf libhoge.so.original libhoge.so 12 | 13 | LD_LIBRARY_PATH=. qemu-aarch64 -L /usr/aarch64-linux-gnu ./main.out 14 | -------------------------------------------------------------------------------- /tests/tls-dlopen-gcc/main.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | 4 | int main() { 5 | void* handle = dlopen("lib.so", RTLD_LAZY); 6 | if (handle != NULL) { 7 | void (*func)() = (void (*)())dlsym(handle, "show_tls_variables"); 8 | func(); 9 | 10 | int* tls_with_init_value_p = (int*)dlsym(handle, "tls_with_init_value"); 11 | int* tls_without_init_value_p = (int*)dlsym(handle, "tls_without_init_value"); 12 | 13 | printf("*tls_with_init_value_p = %d, *tls_without_init_value_p = %d\n", *tls_with_init_value_p, *tls_without_init_value_p); 14 | 15 | } else { 16 | printf("Cannot open lib.so\n"); 17 | } 18 | return 0; 19 | } 20 | -------------------------------------------------------------------------------- /tests/tls-multiple-module-g++/fugahoge.cc: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | #include 4 | 5 | #include "fuga.h" 6 | #include "hoge.h" 7 | 8 | extern "C" void show_fuga_hoge() { 9 | uint64_t fuga_data = get_fuga_data(); 10 | uint64_t fuga_bss = get_fuga_bss(); 11 | uint64_t hoge_data = get_hoge_data(); 12 | uint64_t hoge_bss = get_hoge_bss(); 13 | 14 | std::cout << std::hex << "fuga_data = " << fuga_data << ", fuga_bss = " << fuga_bss << std::endl 15 | << "hoge_data = " << hoge_data << ", hoge_bss = " << hoge_bss << std::endl; 16 | 17 | assert(fuga_data == 0xDEADBEEFDEADBEEF && fuga_bss == 0 && hoge_data == 0xABCDEFABCDEFABCD && hoge_bss == 0); 18 | } 19 | -------------------------------------------------------------------------------- /tests/tls-dlopen-gcc-aarch64/main.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | 4 | int main() { 5 | void* handle = dlopen("lib.so", RTLD_LAZY); 6 | if (handle != NULL) { 7 | void (*func)() = (void (*)())dlsym(handle, "show_tls_variables"); 8 | func(); 9 | 10 | int* tls_with_init_value_p = (int*)dlsym(handle, "tls_with_init_value"); 11 | int* tls_without_init_value_p = (int*)dlsym(handle, "tls_without_init_value"); 12 | 13 | printf("*tls_with_init_value_p = %d, *tls_without_init_value_p = %d\n", *tls_with_init_value_p, *tls_without_init_value_p); 14 | 15 | } else { 16 | printf("Cannot open lib.so\n"); 17 | } 18 | return 0; 19 | } 20 | -------------------------------------------------------------------------------- /tests/tls-multiple-module-g++-aarch64/fugahoge.cc: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | #include 4 | 5 | #include "fuga.h" 6 | #include "hoge.h" 7 | 8 | extern "C" void show_fuga_hoge() { 9 | uint64_t fuga_data = get_fuga_data(); 10 | uint64_t fuga_bss = get_fuga_bss(); 11 | uint64_t hoge_data = get_hoge_data(); 12 | uint64_t hoge_bss = get_hoge_bss(); 13 | 14 | std::cout << std::hex << "fuga_data = " << fuga_data << ", fuga_bss = " << fuga_bss << std::endl 15 | << "hoge_data = " << hoge_data << ", hoge_bss = " << hoge_bss << std::endl; 16 | 17 | assert(fuga_data == 0xDEADBEEFDEADBEEF && fuga_bss == 0 && hoge_data == 0xABCDEFABCDEFABCD && hoge_bss == 0); 18 | } 19 | -------------------------------------------------------------------------------- /.github/workflows/build.yml: -------------------------------------------------------------------------------- 1 | name: Build and test 2 | 3 | on: [push, pull_request] 4 | 5 | jobs: 6 | build: 7 | 8 | runs-on: ubuntu-latest 9 | 10 | steps: 11 | - uses: actions/checkout@v2 12 | - name: Install requirements 13 | run: sudo apt install ninja-build g++-aarch64-linux-gnu qemu qemu-system-aarch64 qemu-user 14 | - name: Install Python packages 15 | run: pip install pytest numpy cmake-format 16 | - name: format 17 | run: ./run-format.sh 18 | - name: CMake 19 | run: mkdir build && cd build && cmake -GNinja -DSOLD_PYBIND_TEST=ON .. 20 | - name: Build 21 | run: cmake --build build 22 | - name: Test 23 | run: cd build && ctest --output-on-failure 24 | -------------------------------------------------------------------------------- /tests/typeid-g++-aarch64/test.sh: -------------------------------------------------------------------------------- 1 | #! /bin/bash -eu 2 | 3 | aarch64-linux-gnu-g++ -fPIC -c -o lib.o lib.cc 4 | aarch64-linux-gnu-g++ -Wl,--hash-style=gnu -shared -Wl,-soname,lib.so -o lib.so lib.o 5 | aarch64-linux-gnu-g++ -Wl,--hash-style=gnu -o main main.cc lib.so 6 | 7 | mv lib.so lib.so.original 8 | ../../build/sold -i lib.so.original -o lib.so.soldout --section-headers --check-output --custom-library-path /usr/aarch64-linux-gnu/lib 9 | 10 | # Use sold 11 | ln -sf lib.so.soldout lib.so 12 | echo ----------- Use sold ----------- 13 | LD_LIBRARY_PATH=. qemu-aarch64 -L /usr/aarch64-linux-gnu ./main 14 | 15 | # Use original 16 | ln -sf lib.so.original lib.so 17 | echo ----------- Use original ----------- 18 | LD_LIBRARY_PATH=. qemu-aarch64 -L /usr/aarch64-linux-gnu ./main 19 | -------------------------------------------------------------------------------- /tests/dynamic_cast-g++-aarch64/test.sh: -------------------------------------------------------------------------------- 1 | #! /bin/bash -eu 2 | 3 | aarch64-linux-gnu-g++ -fPIC -c -o lib.o lib.cc 4 | aarch64-linux-gnu-g++ -Wl,--hash-style=gnu -shared -Wl,-soname,lib.so -o lib.so lib.o 5 | aarch64-linux-gnu-g++ -Wl,--hash-style=gnu -o main main.cc lib.so 6 | 7 | mv lib.so lib.so.original 8 | ../../build/sold -i lib.so.original -o lib.so.soldout --section-headers --check-output --custom-library-path /usr/aarch64-linux-gnu/lib 9 | 10 | # Use sold 11 | ln -sf lib.so.soldout lib.so 12 | echo ----------- Use sold ----------- 13 | LD_LIBRARY_PATH=. qemu-aarch64 -L /usr/aarch64-linux-gnu ./main 14 | 15 | # Use original 16 | ln -sf lib.so.original lib.so 17 | echo ----------- Use original ----------- 18 | LD_LIBRARY_PATH=. qemu-aarch64 -L /usr/aarch64-linux-gnu ./main 19 | -------------------------------------------------------------------------------- /tests/tls-lib-gcc-without-base-aarch64/test.sh: -------------------------------------------------------------------------------- 1 | #! /bin/bash -eu 2 | 3 | aarch64-linux-gnu-gcc -fPIC -c -o lib.o lib.c 4 | aarch64-linux-gnu-gcc -fPIC -c -o base.o base.c 5 | aarch64-linux-gnu-gcc -Wl,--hash-style=gnu -shared -Wl,-soname,base.so -o original/base.so base.o 6 | aarch64-linux-gnu-gcc -Wl,--hash-style=gnu -shared -Wl,-soname,lib.so -o original/lib.so lib.o original/base.so 7 | aarch64-linux-gnu-gcc -Wl,--hash-style=gnu -o main.out main.c original/lib.so original/base.so 8 | 9 | cp original/base.so sold_out/base.so 10 | 11 | LD_LIBRARY_PATH=original ../../build/sold original/lib.so -o sold_out/lib.so --section-headers --exclude-so base.so --check-output --custom-library-path /usr/aarch64-linux-gnu/lib 12 | LD_LIBRARY_PATH=sold_out qemu-aarch64 -L /usr/aarch64-linux-gnu ./main.out 13 | -------------------------------------------------------------------------------- /tests/tls-lib-gcc/test.sh: -------------------------------------------------------------------------------- 1 | #! /bin/bash -eu 2 | 3 | gcc -fPIC -c -o lib.o lib.c 4 | gcc -fPIC -c -o base.o base.c 5 | gcc -Wl,--hash-style=gnu -shared -Wl,-soname,base.so -o original/base.so base.o 6 | gcc -Wl,--hash-style=gnu -shared -Wl,-soname,lib.so -o original/lib.so lib.o original/base.so 7 | gcc -Wl,--hash-style=gnu -shared -Wl,-soname,lib.so -o answer/lib.so lib.o base.o 8 | 9 | # Without sold 10 | # LD_LIBRARY_PATH=original gcc -Wl,--hash-style=gnu -o main.out main.c original/lib.so original/base.so 11 | # LD_LIBRARY_PATH=original ./main.out 12 | 13 | LD_LIBRARY_PATH=original ../../build/sold original/lib.so -o sold_out/lib.so --section-headers --check-output 14 | 15 | LD_LIBRARY_PATH=sold_out gcc -Wl,--hash-style=gnu -o main.out main.c sold_out/lib.so 16 | LD_LIBRARY_PATH=sold_out ./main.out 17 | 18 | -------------------------------------------------------------------------------- /tests/version-gcc/test.sh: -------------------------------------------------------------------------------- 1 | #! /bin/bash -eu 2 | 3 | gcc -fPIC -c -o libmax1.o libmax1.c 4 | gcc -Wl,--hash-style=gnu -shared -Wl,-soname,libmax.so -o libmax.so.1 libmax1.o 5 | ln -sf libmax.so.1 libmax.so 6 | gcc -Wl,--hash-style=gnu -o vertest1 vertest1.c libmax.so 7 | 8 | gcc -fPIC -c -o libmax2.o libmax2.c 9 | gcc -Wl,--hash-style=gnu -shared -Wl,-soname,libmax.so -Wl,--version-script,libmax2.def -o libmax.so.2 libmax2.o 10 | ln -sf libmax.so.2 libmax.so 11 | gcc -Wl,--hash-style=gnu -o vertest2 vertest2.c libmax.so 12 | 13 | LD_LIBRARY_PATH=. ../../build/sold -e libmax.so -o vertest1.out vertest1 --section-headers --check-output 14 | LD_LIBRARY_PATH=. ./vertest1.out 15 | LD_LIBRARY_PATH=. ../../build/sold -e libmax.so -o vertest2.out vertest2 --section-headers --check-output 16 | LD_LIBRARY_PATH=. ./vertest2.out 17 | -------------------------------------------------------------------------------- /ldsoconf.h: -------------------------------------------------------------------------------- 1 | // Copyright (C) 2021 The sold authors 2 | // 3 | // This program is free software: you can redistribute it and/or modify 4 | // it under the terms of the GNU General Public License as published by 5 | // the Free Software Foundation, either version 3 of the License, or 6 | // (at your option) any later version. 7 | // 8 | // This program is distributed in the hope that it will be useful, 9 | // but WITHOUT ANY WARRANTY; without even the implied warranty of 10 | // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 11 | // GNU General Public License for more details. 12 | // 13 | // You should have received a copy of the GNU General Public License 14 | // along with this program. If not, see . 15 | 16 | #pragma once 17 | 18 | #include 19 | #include 20 | 21 | namespace ldsoconf { 22 | std::vector read_ldsoconf(); 23 | } 24 | -------------------------------------------------------------------------------- /tests/tls-multiple-lib-gcc/test.sh: -------------------------------------------------------------------------------- 1 | #! /bin/bash -eu 2 | 3 | gcc -fPIC -c -o base.o base.c 4 | gcc -fPIC -c -o base2.o base2.c 5 | gcc -fPIC -c -o lib.o lib.c 6 | gcc -Wl,--hash-style=gnu -shared -Wl,-soname,base.so -o original/base.so base.o 7 | gcc -Wl,--hash-style=gnu -shared -Wl,-soname,base2.so -o original/base2.so base2.o 8 | gcc -Wl,--hash-style=gnu -shared -Wl,-soname,lib.so -o original/lib.so lib.o original/base2.so original/base.so 9 | gcc -Wl,--hash-style=gnu -shared -Wl,-soname,lib.so -o answer/lib.so lib.o base2.o base.o 10 | 11 | # Without sold 12 | # LD_LIBRARY_PATH=original gcc -Wl,--hash-style=gnu -o main.out main.c original/lib.so original/base2.so original/base.so 13 | # LD_LIBRARY_PATH=original ./main.out 14 | 15 | LD_LIBRARY_PATH=original ../../build/sold original/lib.so -o sold_out/lib.so --section-headers --check-output 16 | 17 | LD_LIBRARY_PATH=sold_out gcc -Wl,--hash-style=gnu -o main.out main.c sold_out/lib.so 18 | LD_LIBRARY_PATH=sold_out ./main.out 19 | -------------------------------------------------------------------------------- /tests/tls-lib-gcc-aarch64/test.sh: -------------------------------------------------------------------------------- 1 | #! /bin/bash -eu 2 | 3 | aarch64-linux-gnu-gcc -fPIC -c -o lib.o lib.c 4 | aarch64-linux-gnu-gcc -fPIC -c -o base.o base.c 5 | aarch64-linux-gnu-gcc -Wl,--hash-style=gnu -shared -Wl,-soname,base.so -o original/base.so base.o 6 | aarch64-linux-gnu-gcc -Wl,--hash-style=gnu -shared -Wl,-soname,lib.so -o original/lib.so lib.o original/base.so 7 | aarch64-linux-gnu-gcc -Wl,--hash-style=gnu -shared -Wl,-soname,lib.so -o answer/lib.so lib.o base.o 8 | 9 | # Without sold 10 | # LD_LIBRARY_PATH=original gcc -Wl,--hash-style=gnu -o main.out main.c original/lib.so original/base.so 11 | # LD_LIBRARY_PATH=original ./main.out 12 | 13 | LD_LIBRARY_PATH=original ../../build/sold original/lib.so -o sold_out/lib.so --section-headers --check-output aarch64-linux-gnu-gcc 14 | 15 | LD_LIBRARY_PATH=sold_out aarch64-linux-gnu-gcc -Wl,--hash-style=gnu -o main.out main.c sold_out/lib.so 16 | LD_LIBRARY_PATH=sold_out qemu-aarch64 -L /usr/aarch64-linux-gnu ./main.out 17 | 18 | -------------------------------------------------------------------------------- /tests/stb_gnu_unique_tls/unique.cc: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | // OK 4 | // No symbol 5 | // int inline_fn() { 6 | // thread_local int c = 0; 7 | // return c++; 8 | // } 9 | 10 | // OK 11 | // No symbol 12 | // static int inline_fn() { 13 | // thread_local int c = 0; 14 | // return c++; 15 | // } 16 | 17 | // OK 18 | // OBJECT UNIQUE 19 | // Deleted by sold 20 | // inline int inline_fn() { 21 | // static int c = 0; 22 | // return c++; 23 | // } 24 | 25 | // NG 26 | // TLS UNIQUE 27 | inline int inline_fn() { 28 | thread_local int c = 0; 29 | return c++; 30 | } 31 | 32 | // NG 33 | // TLS UNIQUE 34 | // inline thread_local int x = 10; 35 | // int inline_fn() { 36 | // return x; 37 | // } 38 | 39 | // NG 40 | // TLS UNIQUE 41 | // inline int inline_fn() { 42 | // static thread_local int c = 0; 43 | // return c++; 44 | // } 45 | 46 | int fn() { 47 | printf("%d\n", inline_fn()); 48 | printf("%d\n", inline_fn()); 49 | return 0; 50 | } 51 | -------------------------------------------------------------------------------- /tests/stb_gnu_unique_tls-aarch64/unique.cc: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | // OK 4 | // No symbol 5 | // int inline_fn() { 6 | // thread_local int c = 0; 7 | // return c++; 8 | // } 9 | 10 | // OK 11 | // No symbol 12 | // static int inline_fn() { 13 | // thread_local int c = 0; 14 | // return c++; 15 | // } 16 | 17 | // OK 18 | // OBJECT UNIQUE 19 | // Deleted by sold 20 | // inline int inline_fn() { 21 | // static int c = 0; 22 | // return c++; 23 | // } 24 | 25 | // NG 26 | // TLS UNIQUE 27 | inline int inline_fn() { 28 | thread_local int c = 0; 29 | return c++; 30 | } 31 | 32 | // NG 33 | // TLS UNIQUE 34 | // inline thread_local int x = 10; 35 | // int inline_fn() { 36 | // return x; 37 | // } 38 | 39 | // NG 40 | // TLS UNIQUE 41 | // inline int inline_fn() { 42 | // static thread_local int c = 0; 43 | // return c++; 44 | // } 45 | 46 | int fn() { 47 | printf("%d\n", inline_fn()); 48 | printf("%d\n", inline_fn()); 49 | return 0; 50 | } 51 | -------------------------------------------------------------------------------- /cmake/third-party.cmake: -------------------------------------------------------------------------------- 1 | # Download and unpack a third-party library at configure time 2 | # The original code is at the README of google-test: 3 | # https://github.com/google/googletest/tree/master/googletest 4 | function(get_third_party name) 5 | configure_file( 6 | "${PROJECT_SOURCE_DIR}/third_party/${name}.cmake" 7 | "${CMAKE_CURRENT_BINARY_DIR}/${name}-download/CMakeLists.txt") 8 | execute_process(COMMAND ${CMAKE_COMMAND} -G "${CMAKE_GENERATOR}" . 9 | RESULT_VARIABLE result 10 | WORKING_DIRECTORY "${CMAKE_CURRENT_BINARY_DIR}/${name}-download") 11 | if(result) 12 | message(FATAL_ERROR "CMake step for ${name} failed: ${result}") 13 | endif() 14 | execute_process(COMMAND ${CMAKE_COMMAND} --build . 15 | RESULT_VARIABLE result 16 | WORKING_DIRECTORY "${CMAKE_CURRENT_BINARY_DIR}/${name}-download") 17 | if(result) 18 | message(FATAL_ERROR "Build step for ${name} failed: ${result}") 19 | endif() 20 | endfunction() 21 | -------------------------------------------------------------------------------- /libtorch_test/torch_test.cc: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | #include 4 | #include 5 | #include 6 | #include 7 | #include 8 | #include 9 | 10 | #define SLOG() std::cout << __FILE__ << ":" << __LINE__ << " " 11 | #define SSHOW_KV(key, value) " " << key << "=" << (value) 12 | #define SSHOW(x) SSHOW_KV(#x, x) 13 | 14 | extern "C" void test() { 15 | SLOG() << "add test" << std::endl; 16 | auto x = at::randn({1, 128, 224, 224}, at::kFloat); 17 | auto y = at::randn({1, 128, 224, 224}, at::kFloat); 18 | auto z = at::add(x, y); 19 | SLOG() << SSHOW(z.toString()) << std::endl; 20 | 21 | SLOG() << "convolution test" << std::endl; 22 | auto w = at::randn({32, 128, 224, 224}, at::kFloat); 23 | auto r2 = at::convolution(x, w, c10::nullopt, c10::IntArrayRef({1, 1}), c10::IntArrayRef({0}), c10::IntArrayRef({1, 1}), false, 24 | c10::IntArrayRef({0}), 1); 25 | SLOG() << SSHOW(r2.toString()) << std::endl; 26 | } 27 | -------------------------------------------------------------------------------- /pybind_test/numpy.cc: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | 4 | namespace py = pybind11; 5 | 6 | py::array_t add_arrays(py::array_t input1, py::array_t input2) { 7 | py::buffer_info buf1 = input1.request(), buf2 = input2.request(); 8 | 9 | if (buf1.ndim != 1 || buf2.ndim != 1) throw std::runtime_error("Number of dimensions must be one"); 10 | 11 | if (buf1.size != buf2.size) throw std::runtime_error("Input shapes must match"); 12 | 13 | /* No pointer is passed, so NumPy will allocate the buffer */ 14 | auto result = py::array_t(buf1.size); 15 | 16 | py::buffer_info buf3 = result.request(); 17 | 18 | double* ptr1 = static_cast(buf1.ptr); 19 | double* ptr2 = static_cast(buf2.ptr); 20 | double* ptr3 = static_cast(buf3.ptr); 21 | 22 | for (size_t idx = 0; idx < buf1.shape[0]; idx++) ptr3[idx] = ptr1[idx] + ptr2[idx]; 23 | 24 | return result; 25 | } 26 | 27 | PYBIND11_MODULE(mynumpy, m) { 28 | m.def("add_arrays", &add_arrays, "Add two NumPy arrays"); 29 | } 30 | -------------------------------------------------------------------------------- /tests/version-gcc-aarch64/test.sh: -------------------------------------------------------------------------------- 1 | #! /bin/bash -eu 2 | 3 | aarch64-linux-gnu-gcc -fPIC -c -o libmax1.o libmax1.c 4 | aarch64-linux-gnu-gcc -Wl,--hash-style=gnu -shared -Wl,-soname,libmax.so -o libmax.so.1 libmax1.o 5 | ln -sf libmax.so.1 libmax.so 6 | aarch64-linux-gnu-gcc -Wl,--hash-style=gnu -o vertest1 vertest1.c libmax.so 7 | 8 | aarch64-linux-gnu-gcc -fPIC -c -o libmax2.o libmax2.c 9 | aarch64-linux-gnu-gcc -Wl,--hash-style=gnu -shared -Wl,-soname,libmax.so -Wl,--version-script,libmax2.def -o libmax.so.2 libmax2.o 10 | ln -sf libmax.so.2 libmax.so 11 | aarch64-linux-gnu-gcc -Wl,--hash-style=gnu -o vertest2 vertest2.c libmax.so 12 | 13 | LD_LIBRARY_PATH=. ../../build/sold -e libmax.so -o vertest1.out vertest1 --section-headers --check-output --custom-library-path /usr/aarch64-linux-gnu/lib 14 | LD_LIBRARY_PATH=. qemu-aarch64 -L /usr/aarch64-linux-gnu ./vertest1.out 15 | LD_LIBRARY_PATH=. ../../build/sold -e libmax.so -o vertest2.out vertest2 --section-headers --check-output --custom-library-path /usr/aarch64-linux-gnu/lib 16 | LD_LIBRARY_PATH=. qemu-aarch64 -L /usr/aarch64-linux-gnu ./vertest2.out 17 | -------------------------------------------------------------------------------- /tests/tls-multiple-module-g++/main.cc: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | #include 4 | 5 | int main() { 6 | std::cout << "---------- libfugahoge.so.original ----------" << std::endl; 7 | void* handle = dlopen("./libfugahoge.so.original", RTLD_LAZY); 8 | if (handle == NULL) { 9 | std::cout << "Cannot find libfugahoge.so.original" << std::endl; 10 | return 0; 11 | } 12 | int (*show_fuga_hoge)() = (int (*)())dlsym(handle, "show_fuga_hoge"); 13 | if (show_fuga_hoge == NULL) { 14 | std::cout << "Cannot find show_fuga_hoge" << std::endl; 15 | return 0; 16 | } 17 | show_fuga_hoge(); 18 | 19 | std::cout << "---------- libfugahoge.so.soldout ----------" << std::endl; 20 | handle = dlopen("./libfugahoge.so.soldout", RTLD_LAZY); 21 | if (handle == NULL) { 22 | std::cout << "Cannot find libfugahoge.so.soldout" << std::endl; 23 | return 0; 24 | } 25 | show_fuga_hoge = (int (*)())dlsym(handle, "show_fuga_hoge"); 26 | if (show_fuga_hoge == NULL) { 27 | std::cout << "Cannot find show_fuga_hoge" << std::endl; 28 | return 0; 29 | } 30 | show_fuga_hoge(); 31 | return 0; 32 | } 33 | -------------------------------------------------------------------------------- /tests/tls-multiple-module-g++-aarch64/main.cc: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | #include 4 | 5 | int main() { 6 | std::cout << "---------- libfugahoge.so.original ----------" << std::endl; 7 | void* handle = dlopen("./libfugahoge.so.original", RTLD_LAZY); 8 | if (handle == NULL) { 9 | std::cout << "Cannot find libfugahoge.so.original" << std::endl; 10 | return 0; 11 | } 12 | int (*show_fuga_hoge)() = (int (*)())dlsym(handle, "show_fuga_hoge"); 13 | if (show_fuga_hoge == NULL) { 14 | std::cout << "Cannot find show_fuga_hoge" << std::endl; 15 | return 0; 16 | } 17 | show_fuga_hoge(); 18 | 19 | std::cout << "---------- libfugahoge.so.soldout ----------" << std::endl; 20 | handle = dlopen("./libfugahoge.so.soldout", RTLD_LAZY); 21 | if (handle == NULL) { 22 | std::cout << "Cannot find libfugahoge.so.soldout" << std::endl; 23 | return 0; 24 | } 25 | show_fuga_hoge = (int (*)())dlsym(handle, "show_fuga_hoge"); 26 | if (show_fuga_hoge == NULL) { 27 | std::cout << "Cannot find show_fuga_hoge" << std::endl; 28 | return 0; 29 | } 30 | show_fuga_hoge(); 31 | return 0; 32 | } 33 | -------------------------------------------------------------------------------- /tests/tls-multiple-lib-gcc-aarch64/test.sh: -------------------------------------------------------------------------------- 1 | #! /bin/bash -eu 2 | 3 | aarch64-linux-gnu-gcc -fPIC -c -o base.o base.c 4 | aarch64-linux-gnu-gcc -fPIC -c -o base2.o base2.c 5 | aarch64-linux-gnu-gcc -fPIC -c -o lib.o lib.c 6 | aarch64-linux-gnu-gcc -Wl,--hash-style=gnu -shared -Wl,-soname,base.so -o original/base.so base.o 7 | aarch64-linux-gnu-gcc -Wl,--hash-style=gnu -shared -Wl,-soname,base2.so -o original/base2.so base2.o 8 | aarch64-linux-gnu-gcc -Wl,--hash-style=gnu -shared -Wl,-soname,lib.so -o original/lib.so lib.o original/base2.so original/base.so 9 | aarch64-linux-gnu-gcc -Wl,--hash-style=gnu -shared -Wl,-soname,lib.so -o answer/lib.so lib.o base2.o base.o 10 | 11 | # Without sold 12 | # LD_LIBRARY_PATH=original gcc -Wl,--hash-style=gnu -o main.out main.c original/lib.so original/base2.so original/base.so 13 | # LD_LIBRARY_PATH=original ./main.out 14 | 15 | LD_LIBRARY_PATH=original ../../build/sold original/lib.so -o sold_out/lib.so --section-headers --check-output --custom-library-path /usr/aarch64-linux-gnu/lib 16 | 17 | LD_LIBRARY_PATH=sold_out aarch64-linux-gnu-gcc -Wl,--hash-style=gnu -o main.out main.c sold_out/lib.so 18 | LD_LIBRARY_PATH=sold_out qemu-aarch64 -L /usr/aarch64-linux-gnu ./main.out 19 | -------------------------------------------------------------------------------- /hash.cc: -------------------------------------------------------------------------------- 1 | // Copyright (C) 2021 The sold authors 2 | // 3 | // This program is free software: you can redistribute it and/or modify 4 | // it under the terms of the GNU General Public License as published by 5 | // the Free Software Foundation, either version 3 of the License, or 6 | // (at your option) any later version. 7 | // 8 | // This program is distributed in the hope that it will be useful, 9 | // but WITHOUT ANY WARRANTY; without even the implied warranty of 10 | // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 11 | // GNU General Public License for more details. 12 | // 13 | // You should have received a copy of the GNU General Public License 14 | // along with this program. If not, see . 15 | 16 | #include "hash.h" 17 | 18 | uint32_t CalcGnuHash(const std::string& name) { 19 | uint32_t h = 5381; 20 | for (unsigned char c : name) { 21 | h = h * 33 + c; 22 | } 23 | return h; 24 | } 25 | 26 | uint32_t CalcHash(const std::string& name) { 27 | uint32_t h = 0, g; 28 | for (unsigned char c : name) { 29 | h = (h << 4) + c; 30 | g = h & 0xf0000000; 31 | h ^= g >> 24; 32 | h ^= g; 33 | } 34 | return h; 35 | } 36 | -------------------------------------------------------------------------------- /tests/exe.cc: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | 4 | #include "lib.h" 5 | 6 | static int g_init; 7 | __attribute__((constructor)) static void init() { 8 | puts("Constructor in exe"); 9 | g_init = 42; 10 | } 11 | 12 | __attribute__((destructor)) static void quit() { 13 | puts("Destructor in exe"); 14 | } 15 | 16 | int main(int argc, char** argv) { 17 | int is_exe = (argc == 1); 18 | 19 | puts("Start main"); 20 | if (lib_add_42_via_base(10) != 52) abort(); 21 | if (in_both_lib_and_base() != 100) abort(); 22 | 23 | fprintf(stderr, "Use stderr from main\n"); 24 | lib_use_stderr(); 25 | 26 | if (g_init != 42) abort(); 27 | // TODO(hamaji): Fix .init_array for the main binary. 28 | if (!is_exe) { 29 | if (lib_init_value() != 43) abort(); 30 | if (lib_base_init_value() != 44) abort(); 31 | puts("Constructors are OK"); 32 | } 33 | 34 | if (lib_base_global() != 98) abort(); 35 | 36 | if (lib_base_vf() != 1234) abort(); 37 | 38 | if (lib_base_thread_var() != 121) abort(); 39 | if (lib_base_thread_var_reloc() != 42) abort(); 40 | if (lib_thread_var() != 111) abort(); 41 | if (lib_thread_var_reloc() != 32) abort(); 42 | 43 | puts("OK"); 44 | } 45 | -------------------------------------------------------------------------------- /print_tls.cc: -------------------------------------------------------------------------------- 1 | // 2 | // print_tls 3 | // 4 | // This program shows tls entries. 5 | // 6 | // Copyright (C) 2021 The sold authors 7 | // 8 | // This program is free software: you can redistribute it and/or modify 9 | // it under the terms of the GNU General Public License as published by 10 | // the Free Software Foundation, either version 3 of the License, or 11 | // (at your option) any later version. 12 | // 13 | // This program is distributed in the hope that it will be useful, 14 | // but WITHOUT ANY WARRANTY; without even the implied warranty of 15 | // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 16 | // GNU General Public License for more details. 17 | // 18 | // You should have received a copy of the GNU General Public License 19 | // along with this program. If not, see . 20 | 21 | #include "elf_binary.h" 22 | 23 | #include 24 | 25 | int main(int argc, const char* argv[]) { 26 | google::InitGoogleLogging(argv[0]); 27 | 28 | if (argc != 2) { 29 | std::cerr << "Usage: " << argv[0] << " \nThis program shows TLS entries of the given ELF file." << std::endl; 30 | return 1; 31 | } 32 | 33 | auto b = ReadELF(argv[1]); 34 | std::cout << b->ShowTLS(); 35 | return 0; 36 | } 37 | -------------------------------------------------------------------------------- /print_dtrela.cc: -------------------------------------------------------------------------------- 1 | // print_dtrela 2 | // This program shows relocation entries in DT_RELA. 3 | // 4 | // Copyright (C) 2021 The sold authors 5 | // 6 | // This program is free software: you can redistribute it and/or modify 7 | // it under the terms of the GNU General Public License as published by 8 | // the Free Software Foundation, either version 3 of the License, or 9 | // (at your option) any later version. 10 | // 11 | // This program is distributed in the hope that it will be useful, 12 | // but WITHOUT ANY WARRANTY; without even the implied warranty of 13 | // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 14 | // GNU General Public License for more details. 15 | // 16 | // You should have received a copy of the GNU General Public License 17 | // along with this program. If not, see . 18 | 19 | #include "elf_binary.h" 20 | 21 | #include 22 | 23 | int main(int argc, const char* argv[]) { 24 | google::InitGoogleLogging(argv[0]); 25 | 26 | if (argc != 2) { 27 | std::cerr << "Usage: " << argv[0] << " \nThis program parse DT_RELA of the given ELF file." << std::endl; 28 | return 1; 29 | } 30 | 31 | auto b = ReadELF(argv[1]); 32 | std::cout << b->ShowDtRela(); 33 | return 0; 34 | } 35 | -------------------------------------------------------------------------------- /print_version.cc: -------------------------------------------------------------------------------- 1 | // 2 | // print_verneed 3 | // 4 | // This program shows version information. 5 | // 6 | // Copyright (C) 2021 The sold authors 7 | // 8 | // This program is free software: you can redistribute it and/or modify 9 | // it under the terms of the GNU General Public License as published by 10 | // the Free Software Foundation, either version 3 of the License, or 11 | // (at your option) any later version. 12 | // 13 | // This program is distributed in the hope that it will be useful, 14 | // but WITHOUT ANY WARRANTY; without even the implied warranty of 15 | // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 16 | // GNU General Public License for more details. 17 | // 18 | // You should have received a copy of the GNU General Public License 19 | // along with this program. If not, see . 20 | 21 | #include "elf_binary.h" 22 | 23 | #include 24 | 25 | int main(int argc, const char* argv[]) { 26 | google::InitGoogleLogging(argv[0]); 27 | 28 | if (argc != 2) { 29 | std::cerr << "Usage: " << argv[0] << " \nThis program shows verneed information of the given ELF file." << std::endl; 30 | return 1; 31 | } 32 | 33 | auto b = ReadELF(argv[1]); 34 | std::cout << b->ShowVersion(); 35 | return 0; 36 | } 37 | -------------------------------------------------------------------------------- /print_ehframe.cc: -------------------------------------------------------------------------------- 1 | // 2 | // print_ehframe 3 | // 4 | // This program shows .eh_frame_hdr 5 | // 6 | // Copyright (C) 2021 The sold authors 7 | // 8 | // This program is free software: you can redistribute it and/or modify 9 | // it under the terms of the GNU General Public License as published by 10 | // the Free Software Foundation, either version 3 of the License, or 11 | // (at your option) any later version. 12 | // 13 | // This program is distributed in the hope that it will be useful, 14 | // but WITHOUT ANY WARRANTY; without even the implied warranty of 15 | // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 16 | // GNU General Public License for more details. 17 | // 18 | // You should have received a copy of the GNU General Public License 19 | // along with this program. If not, see . 20 | 21 | #include "elf_binary.h" 22 | 23 | #include 24 | 25 | int main(int argc, const char* argv[]) { 26 | google::InitGoogleLogging(argv[0]); 27 | google::InstallFailureSignalHandler(); 28 | 29 | if (argc != 2) { 30 | std::cerr << "Usage: " << argv[0] << " \nThis program shows .eh_frame_hdr." << std::endl; 31 | return 1; 32 | } 33 | 34 | auto b = ReadELF(argv[1]); 35 | std::cout << b->ShowEHFrame(); 36 | return 0; 37 | } 38 | -------------------------------------------------------------------------------- /tests/base.cc: -------------------------------------------------------------------------------- 1 | #include "base.h" 2 | 3 | #include 4 | #include 5 | 6 | static int g_init; 7 | __attribute__((constructor)) static void init() { 8 | puts("Constructor in base"); 9 | g_init = 44; 10 | } 11 | 12 | __attribute__((destructor)) static void quit() { 13 | puts("Destructor in base"); 14 | } 15 | 16 | int base_init_value() { 17 | return g_init; 18 | } 19 | 20 | int base_42() { 21 | printf("called %s\n", __func__); 22 | return 42; 23 | } 24 | 25 | int base_add_42(int x) { 26 | printf("called %s\n", __func__); 27 | return x + 42; 28 | } 29 | 30 | int in_both_lib_and_base() { 31 | fprintf(stderr, "Must have been overriden\n"); 32 | abort(); 33 | } 34 | 35 | void base_use_stderr() { 36 | fprintf(stderr, "Use stderr from base\n"); 37 | } 38 | 39 | int base_global = 98; 40 | 41 | class BaseImpl : public Base { 42 | public: 43 | int vf() override { return 1234; } 44 | }; 45 | 46 | Base* MakeBase() { 47 | return new BaseImpl(); 48 | } 49 | 50 | thread_local int g_base_thread_var = 190; 51 | thread_local int g_base_thread_var2 = 70; 52 | thread_local int g_base_thread_bss; 53 | thread_local int g_base_thread_bss2; 54 | static int g_buf[] = {42}; 55 | thread_local int* g_base_thread_buf = g_buf; 56 | 57 | int base_thread_var() { 58 | return (g_base_thread_var - g_base_thread_var2 - --g_base_thread_bss) * ++g_base_thread_bss2; 59 | } 60 | 61 | int base_thread_var_reloc() { 62 | return g_base_thread_buf[0]; 63 | } 64 | -------------------------------------------------------------------------------- /strtab_builder.h: -------------------------------------------------------------------------------- 1 | // Copyright (C) 2021 The sold authors 2 | // 3 | // This program is free software: you can redistribute it and/or modify 4 | // it under the terms of the GNU General Public License as published by 5 | // the Free Software Foundation, either version 3 of the License, or 6 | // (at your option) any later version. 7 | // 8 | // This program is distributed in the hope that it will be useful, 9 | // but WITHOUT ANY WARRANTY; without even the implied warranty of 10 | // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 11 | // GNU General Public License for more details. 12 | // 13 | // You should have received a copy of the GNU General Public License 14 | // along with this program. If not, see . 15 | 16 | #pragma once 17 | 18 | #include 19 | #include 20 | #include 21 | 22 | class StrtabBuilder { 23 | public: 24 | StrtabBuilder() {} 25 | StrtabBuilder(std::map rename_mapping) : rename_mapping_(rename_mapping) {} 26 | 27 | uintptr_t Add(const std::string& s); 28 | 29 | uintptr_t GetPos(const std::string& s); 30 | 31 | void Freeze() { is_freezed_ = true; } 32 | 33 | size_t size() const { return strtab_.size(); } 34 | 35 | const void* data() const { return strtab_.data(); } 36 | 37 | private: 38 | std::string strtab_; 39 | std::map cache; 40 | bool is_freezed_{false}; 41 | const std::map rename_mapping_; 42 | }; 43 | -------------------------------------------------------------------------------- /tests/inheritance-g++/main.cc: -------------------------------------------------------------------------------- 1 | #include "lib.h" 2 | 3 | #include 4 | #include 5 | 6 | void JustHelloFunMain() { 7 | std::cout << "Hello from main" << std::endl; 8 | 9 | B* bptr = new B; 10 | C* cptr = new C; 11 | 12 | A* aptr = bptr; 13 | aptr->Speak(); 14 | aptr = cptr; 15 | aptr->Speak(); 16 | 17 | delete bptr; 18 | delete cptr; 19 | 20 | std::unique_ptr buptr = std::make_unique(); 21 | std::unique_ptr cuptr = std::make_unique(); 22 | buptr->Speak(); 23 | cuptr->Speak(); 24 | 25 | std::shared_ptr bsptr = std::make_unique(); 26 | std::shared_ptr csptr = std::make_unique(); 27 | bsptr->Speak(); 28 | csptr->Speak(); 29 | } 30 | 31 | void CallSpeak(A* aptr) { 32 | aptr->Speak(); 33 | } 34 | 35 | int main() { 36 | std::cout << "Before JustHelloFun" << std::endl; 37 | JustHelloFun(); 38 | std::cout << "After JustHelloFun\n" << std::endl; 39 | 40 | std::cout << "Before JustHelloFunMain" << std::endl; 41 | JustHelloFunMain(); 42 | std::cout << "After JustHelloFunMain\n" << std::endl; 43 | 44 | std::cout << "Before constructors" << std::endl; 45 | B b; 46 | C c; 47 | std::cout << "After constructors\n" << std::endl; 48 | 49 | std::cout << "Before member functions" << std::endl; 50 | b.Speak(); 51 | c.Speak(); 52 | std::cout << "After member functions\n" << std::endl; 53 | 54 | std::cout << "Before CallSpeak" << std::endl; 55 | CallSpeak(&b); 56 | CallSpeak(&c); 57 | std::cout << "After CallSpeak" << std::endl; 58 | return 0; 59 | } 60 | -------------------------------------------------------------------------------- /tests/inheritance-g++-aarch64/main.cc: -------------------------------------------------------------------------------- 1 | #include "lib.h" 2 | 3 | #include 4 | #include 5 | 6 | void JustHelloFunMain() { 7 | std::cout << "Hello from main" << std::endl; 8 | 9 | B* bptr = new B; 10 | C* cptr = new C; 11 | 12 | A* aptr = bptr; 13 | aptr->Speak(); 14 | aptr = cptr; 15 | aptr->Speak(); 16 | 17 | delete bptr; 18 | delete cptr; 19 | 20 | std::unique_ptr buptr = std::make_unique(); 21 | std::unique_ptr cuptr = std::make_unique(); 22 | buptr->Speak(); 23 | cuptr->Speak(); 24 | 25 | std::shared_ptr bsptr = std::make_unique(); 26 | std::shared_ptr csptr = std::make_unique(); 27 | bsptr->Speak(); 28 | csptr->Speak(); 29 | } 30 | 31 | void CallSpeak(A* aptr) { 32 | aptr->Speak(); 33 | } 34 | 35 | int main() { 36 | std::cout << "Before JustHelloFun" << std::endl; 37 | JustHelloFun(); 38 | std::cout << "After JustHelloFun\n" << std::endl; 39 | 40 | std::cout << "Before JustHelloFunMain" << std::endl; 41 | JustHelloFunMain(); 42 | std::cout << "After JustHelloFunMain\n" << std::endl; 43 | 44 | std::cout << "Before constructors" << std::endl; 45 | B b; 46 | C c; 47 | std::cout << "After constructors\n" << std::endl; 48 | 49 | std::cout << "Before member functions" << std::endl; 50 | b.Speak(); 51 | c.Speak(); 52 | std::cout << "After member functions\n" << std::endl; 53 | 54 | std::cout << "Before CallSpeak" << std::endl; 55 | CallSpeak(&b); 56 | CallSpeak(&c); 57 | std::cout << "After CallSpeak" << std::endl; 58 | return 0; 59 | } 60 | -------------------------------------------------------------------------------- /hash.h: -------------------------------------------------------------------------------- 1 | // Copyright (C) 2021 The sold authors 2 | // 3 | // This program is free software: you can redistribute it and/or modify 4 | // it under the terms of the GNU General Public License as published by 5 | // the Free Software Foundation, either version 3 of the License, or 6 | // (at your option) any later version. 7 | // 8 | // This program is distributed in the hope that it will be useful, 9 | // but WITHOUT ANY WARRANTY; without even the implied warranty of 10 | // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 11 | // GNU General Public License for more details. 12 | // 13 | // You should have received a copy of the GNU General Public License 14 | // along with this program. If not, see . 15 | 16 | #pragma once 17 | 18 | #include "utils.h" 19 | 20 | struct Elf_GnuHash { 21 | uint32_t nbuckets{0}; 22 | uint32_t symndx{0}; 23 | uint32_t maskwords{0}; 24 | uint32_t shift2{0}; 25 | uint8_t tail[1]; 26 | 27 | Elf_Addr* bloom_filter() { return reinterpret_cast(tail); } 28 | 29 | uint32_t* buckets() { return reinterpret_cast(&bloom_filter()[maskwords]); } 30 | 31 | uint32_t* hashvals() { return reinterpret_cast(&buckets()[nbuckets]); } 32 | }; 33 | 34 | uint32_t CalcGnuHash(const std::string& name); 35 | 36 | uint32_t CalcHash(const std::string& name); 37 | 38 | struct Elf_Hash { 39 | uint32_t nbuckets{0}; 40 | uint32_t nchains{0}; 41 | uint8_t tail[1]; 42 | 43 | const uint32_t* buckets() const { return reinterpret_cast(tail); } 44 | 45 | const uint32_t* chains() const { return buckets() + nbuckets; } 46 | }; 47 | -------------------------------------------------------------------------------- /pybind_test/test_soldout_modules.py: -------------------------------------------------------------------------------- 1 | import numpy 2 | 3 | import myadd 4 | import myobject 5 | import mynumpy 6 | 7 | def test_myadd(): 8 | assert myadd.myadd(1, 2) == 3 9 | 10 | def test_myadd_keyword(): 11 | assert myadd.myadd2(i=1, j=2) == 3 12 | 13 | def test_myadd_default(): 14 | assert myadd.myadd3() == 3 15 | 16 | def test_myadd_const(): 17 | assert myadd.the_answer == 42 18 | assert myadd.what == "World" 19 | 20 | def test_myobject_pet(): 21 | p = myobject.Pet('Molly') 22 | assert p.getName() == "Molly" 23 | p.setName('Charly') 24 | assert p.getName() == "Charly" 25 | 26 | def test_myobject_dog(): 27 | p = myobject.Dog('Molly') 28 | assert p.getName() == "Molly" 29 | assert p.bark() == "woof!" 30 | 31 | def test_myobject_pet_store(): 32 | p = myobject.pet_store() 33 | assert type(p).__name__ == "Pet" 34 | 35 | def test_myobject_pet_store2(): 36 | p = myobject.pet_store2() 37 | assert type(p).__name__ == "PolymorphicDog" 38 | assert p.bark() == "woof!" 39 | 40 | def test_myobject_overload(): 41 | p = myobject.Pet('Molly') 42 | p.set(10) 43 | p.set("hogehoge") 44 | assert p.getAge() == 10 45 | assert p.getName() == "hogehoge" 46 | 47 | def test_myobject_enum(): 48 | p = myobject.Pet('Lucy', myobject.Pet.Cat) 49 | assert p.type == 1 50 | 51 | def test_mynumpy_add(): 52 | # The size of arrays is pretty large because I had encountered a bug that 53 | # appears only for large arrays. 54 | a = numpy.random.rand(1024 * 1024 * 32) 55 | b = numpy.random.rand(1024 * 1024 * 32) 56 | r = mynumpy.add_arrays(a, b) 57 | assert numpy.allclose(a + b, r) 58 | -------------------------------------------------------------------------------- /strtab_builder.cc: -------------------------------------------------------------------------------- 1 | // Copyright (C) 2021 The sold authors 2 | // 3 | // This program is free software: you can redistribute it and/or modify 4 | // it under the terms of the GNU General Public License as published by 5 | // the Free Software Foundation, either version 3 of the License, or 6 | // (at your option) any later version. 7 | // 8 | // This program is distributed in the hope that it will be useful, 9 | // but WITHOUT ANY WARRANTY; without even the implied warranty of 10 | // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 11 | // GNU General Public License for more details. 12 | // 13 | // You should have received a copy of the GNU General Public License 14 | // along with this program. If not, see . 15 | 16 | #include "strtab_builder.h" 17 | 18 | #include "utils.h" 19 | 20 | uintptr_t StrtabBuilder::Add(const std::string& s) { 21 | std::string t = s; 22 | auto it = rename_mapping_.find(s); 23 | if (it != rename_mapping_.end()) t = it->second; 24 | 25 | CHECK(!is_freezed_); 26 | if (cache.find(t) != cache.end()) { 27 | return cache[t]; 28 | } 29 | uintptr_t pos = static_cast(strtab_.size()); 30 | strtab_ += t; 31 | strtab_ += '\0'; 32 | cache[t] = pos; 33 | return pos; 34 | } 35 | 36 | uintptr_t StrtabBuilder::GetPos(const std::string& s) { 37 | std::string t = s; 38 | auto it = rename_mapping_.find(s); 39 | if (it != rename_mapping_.end()) t = it->second; 40 | 41 | if (cache.find(t) != cache.end()) { 42 | return cache[t]; 43 | } else { 44 | LOG(FATAL) << t << " is not in StrtabBuilder."; 45 | exit(1); 46 | } 47 | } 48 | -------------------------------------------------------------------------------- /print_dynsymtab.cc: -------------------------------------------------------------------------------- 1 | // print_dynsymtab 2 | // 3 | // This program parses and prints DT_SYMTAB of a given ELF file. It prints all symbols 4 | // and version information. When the ELF file does not include version information, 5 | // it prints NO_VERSION_INFO instead of version information. 6 | // 7 | // Unlike nm -D --with-symbol-versions or readelf --dynsyms, it works without any shdrs 8 | // because print_dynsymtab gets all information only from phdrs. 9 | // 10 | // Copyright (C) 2021 The sold authors 11 | // 12 | // This program is free software: you can redistribute it and/or modify 13 | // it under the terms of the GNU General Public License as published by 14 | // the Free Software Foundation, either version 3 of the License, or 15 | // (at your option) any later version. 16 | // 17 | // This program is distributed in the hope that it will be useful, 18 | // but WITHOUT ANY WARRANTY; without even the implied warranty of 19 | // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 20 | // GNU General Public License for more details. 21 | // 22 | // You should have received a copy of the GNU General Public License 23 | // along with this program. If not, see . 24 | 25 | #include "elf_binary.h" 26 | 27 | #include 28 | 29 | #include "sold.h" 30 | 31 | int main(int argc, const char* argv[]) { 32 | google::InitGoogleLogging(argv[0]); 33 | 34 | if (argc != 2) { 35 | std::cerr << "Usage: " << argv[0] << " \nThis program parse DT_SYMTAB of the given ELF file." << std::endl; 36 | return 1; 37 | } 38 | 39 | // This Sold class instrance is used only to get filename_to_soname map. 40 | Sold sold(argv[1], {}, {}, {}, false); 41 | 42 | auto b = ReadELF(argv[1]); 43 | b->ReadDynSymtab(sold.filename_to_soname()); 44 | std::cout << b->ShowDynSymtab(); 45 | } 46 | -------------------------------------------------------------------------------- /tests/lib.cc: -------------------------------------------------------------------------------- 1 | #include "lib.h" 2 | 3 | #include 4 | 5 | #include 6 | 7 | #include "base.h" 8 | 9 | static int g_init; 10 | __attribute__((constructor)) static void init() { 11 | puts("Constructor in lib"); 12 | g_init = 43; 13 | } 14 | 15 | __attribute__((destructor)) static void quit() { 16 | puts("Destructor in lib"); 17 | } 18 | 19 | int lib_init_value() { 20 | return g_init; 21 | } 22 | 23 | int lib_base_init_value() { 24 | return base_init_value(); 25 | } 26 | 27 | int lib_42() { 28 | printf("called %s\n", __func__); 29 | return 42; 30 | } 31 | 32 | int lib_add_42_via_base(int v) { 33 | printf("called %s\n", __func__); 34 | return base_add_42(v); 35 | } 36 | 37 | int in_both_lib_and_base() { 38 | printf("called %s\n", __func__); 39 | return 100; 40 | } 41 | 42 | void lib_use_stderr() { 43 | fprintf(stderr, "Use stderr from lib\n"); 44 | } 45 | 46 | int lib_base_global() { 47 | return base_global; 48 | } 49 | 50 | int* lib_base_global_ptr() { 51 | return &base_global; 52 | } 53 | 54 | int lib_base_vf() { 55 | printf("called %s\n", __func__); 56 | std::unique_ptr base(MakeBase()); 57 | return base->vf(); 58 | } 59 | 60 | int lib_base_thread_var() { 61 | return base_thread_var(); 62 | } 63 | 64 | int lib_base_thread_var_reloc() { 65 | return base_thread_var_reloc(); 66 | } 67 | 68 | thread_local int g_lib_thread_var = 180; 69 | thread_local int g_lib_thread_var2 = 70; 70 | thread_local int g_lib_thread_bss; 71 | thread_local int g_lib_thread_bss2; 72 | static int g_buf[] = {32}; 73 | thread_local int* g_lib_thread_buf = g_buf; 74 | 75 | int lib_thread_var() { 76 | return (g_lib_thread_var - g_lib_thread_var2 - --g_lib_thread_bss) * ++g_lib_thread_bss2; 77 | } 78 | 79 | int lib_thread_var_reloc() { 80 | return g_lib_thread_buf[0]; 81 | } 82 | -------------------------------------------------------------------------------- /version_builder.h: -------------------------------------------------------------------------------- 1 | // Copyright (C) 2021 The sold authors 2 | // 3 | // This program is free software: you can redistribute it and/or modify 4 | // it under the terms of the GNU General Public License as published by 5 | // the Free Software Foundation, either version 3 of the License, or 6 | // (at your option) any later version. 7 | // 8 | // This program is distributed in the hope that it will be useful, 9 | // but WITHOUT ANY WARRANTY; without even the implied warranty of 10 | // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 11 | // GNU General Public License for more details. 12 | // 13 | // You should have received a copy of the GNU General Public License 14 | // along with this program. If not, see . 15 | 16 | #pragma once 17 | 18 | #include 19 | 20 | #include 21 | 22 | #include "hash.h" 23 | #include "strtab_builder.h" 24 | #include "utils.h" 25 | 26 | class VersionBuilder { 27 | public: 28 | void Add(Elf_Versym versym, const std::string& soname, const std::string& version, StrtabBuilder& strtab, const unsigned char st_info); 29 | 30 | uintptr_t SizeVersym() const { return (data.size() > 0) ? vers.size() * sizeof(Elf_Versym) : 0; } 31 | 32 | uintptr_t SizeVerneed() const; 33 | 34 | int NumVerneed() const { return data.size(); } 35 | 36 | void EmitVersym(FILE* fp); 37 | 38 | void EmitVerneed(FILE* fp, StrtabBuilder& strtab); 39 | 40 | void SetSonameToFilename(const std::map& soname_to_filename) { soname_to_filename_ = soname_to_filename; } 41 | 42 | private: 43 | // vernum starts from 2 because 0 and 1 are used as VER_NDX_LOCAL and VER_NDX_GLOBAL. 44 | int vernum = 2; 45 | std::map> data; 46 | std::vector vers; 47 | std::map soname_to_filename_; 48 | }; 49 | -------------------------------------------------------------------------------- /tools/tracer.cc: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | #include 6 | #include 7 | #include 8 | #include 9 | 10 | #if defined(__apple__) 11 | #define PTRACE_TRACEME PT_TRACE_ME 12 | #define PT_STEP PTRACE_SINGLESTEP 13 | #endif 14 | 15 | #ifdef __x86_64__ 16 | #define BP regs.rbp 17 | #define SP regs.rsp 18 | #define IP regs.rip 19 | #else 20 | #define BP regs.ebp 21 | #define SP regs.esp 22 | #define IP regs.eip 23 | #endif 24 | 25 | long checked_ptrace(enum __ptrace_request req, pid_t pid, long addr, long data, const char* req_str, const char* file, int line) { 26 | long r = ptrace(req, pid, addr, data); 27 | if (r == -1) { 28 | fprintf(stderr, "%s:%d: ptrace(%s): ", file, line, req_str); 29 | perror(""); 30 | // exit(1); 31 | } 32 | return r; 33 | } 34 | 35 | #define CHECKED_PTRACE(req, pid, addr, data) checked_ptrace(req, pid, addr, data, #req, __FILE__, __LINE__) 36 | 37 | int main(int argc, char* argv[]) { 38 | argc--; 39 | argv++; 40 | 41 | pid_t pid; 42 | if (!strcmp(argv[0], "-p")) { 43 | pid = strtol(argv[1], 0, 10); 44 | CHECKED_PTRACE(PTRACE_ATTACH, pid, 0, 0); 45 | } else { 46 | pid = fork(); 47 | if (!pid) { 48 | CHECKED_PTRACE(PTRACE_TRACEME, 0, 0, 0); 49 | execv(argv[0], argv); 50 | abort(); 51 | } 52 | } 53 | 54 | long prev = 0; 55 | while (true) { 56 | int status; 57 | wait(&status); 58 | if (!WIFSTOPPED(status)) break; 59 | 60 | struct user regs; 61 | CHECKED_PTRACE(PTRACE_GETREGS, pid, 0, (long)®s); 62 | if (prev != regs.IP) printf("%p\n", (void*)regs.IP); 63 | prev = regs.IP; 64 | 65 | CHECKED_PTRACE(PTRACE_SINGLESTEP, pid, 0, 0); 66 | } 67 | } 68 | -------------------------------------------------------------------------------- /pybind_test/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | cmake_minimum_required(VERSION 3.4) 2 | 3 | # I set PREFIX and SUFFIX here because I want to pass generated files to sold. 4 | # The default SUFFIX depends on the system configuration and is difficult to 5 | # infer. 6 | pybind11_add_module(myadd add.cc) 7 | set_target_properties(myadd PROPERTIES PREFIX "" SUFFIX ".so") 8 | pybind11_add_module(myobject object.cc) 9 | set_target_properties(myobject PROPERTIES PREFIX "" SUFFIX ".so") 10 | pybind11_add_module(mynumpy numpy.cc) 11 | set_target_properties(mynumpy PROPERTIES PREFIX "" SUFFIX ".so") 12 | 13 | file(MAKE_DIRECTORY "${CMAKE_CURRENT_BINARY_DIR}/soldout") 14 | add_custom_target( 15 | myadd_soldout ALL 16 | COMMAND 17 | "${PROJECT_BINARY_DIR}/sold" -i "${CMAKE_CURRENT_BINARY_DIR}/myadd.so" -o 18 | "${CMAKE_CURRENT_BINARY_DIR}/soldout/myadd.so" --section-headers 19 | --check-output 20 | DEPENDS sold myadd) 21 | add_custom_target( 22 | myobject_soldout ALL 23 | COMMAND 24 | "${PROJECT_BINARY_DIR}/sold" -i "${CMAKE_CURRENT_BINARY_DIR}/myobject.so" -o 25 | "${CMAKE_CURRENT_BINARY_DIR}/soldout/myobject.so" --section-headers 26 | --check-output 27 | DEPENDS sold myobject) 28 | add_custom_target( 29 | mynumpy_soldout ALL 30 | COMMAND 31 | "${PROJECT_BINARY_DIR}/sold" -i "${CMAKE_CURRENT_BINARY_DIR}/mynumpy.so" -o 32 | "${CMAKE_CURRENT_BINARY_DIR}/soldout/mynumpy.so" --section-headers 33 | --check-output 34 | DEPENDS sold mynumpy) 35 | 36 | # ${CMAKE_CURRENT_BINARY_DIR}/test_soldout_modules_original.py is for debug. 37 | configure_file( 38 | test_soldout_modules.py 39 | ${CMAKE_CURRENT_BINARY_DIR}/test_soldout_modules_original.py @ONLY) 40 | configure_file( 41 | test_soldout_modules.py 42 | ${CMAKE_CURRENT_BINARY_DIR}/soldout/test_soldout_modules.py @ONLY) 43 | 44 | add_test( 45 | NAME pybind_test 46 | WORKING_DIRECTORY "${CMAKE_CURRENT_BINARY_DIR}/soldout" 47 | COMMAND pytest -v) 48 | -------------------------------------------------------------------------------- /ldsoconf.cc: -------------------------------------------------------------------------------- 1 | // Copyright (C) 2021 The sold authors 2 | // 3 | // This program is free software: you can redistribute it and/or modify 4 | // it under the terms of the GNU General Public License as published by 5 | // the Free Software Foundation, either version 3 of the License, or 6 | // (at your option) any later version. 7 | // 8 | // This program is distributed in the hope that it will be useful, 9 | // but WITHOUT ANY WARRANTY; without even the implied warranty of 10 | // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 11 | // GNU General Public License for more details. 12 | // 13 | // You should have received a copy of the GNU General Public License 14 | // along with this program. If not, see . 15 | 16 | #include "ldsoconf.h" 17 | 18 | #include 19 | 20 | #include 21 | 22 | namespace ldsoconf { 23 | namespace { 24 | void read_ldsoconf_dfs(std::vector& res, const std::string& filename) { 25 | std::ifstream f; 26 | f.open(filename); 27 | if (!f) { 28 | return; 29 | } 30 | std::string head; 31 | while (f >> head) { 32 | if (head.substr(0, 1) == "#") { 33 | std::string comment; 34 | std::getline(f, comment); 35 | } else if (head == "include") { 36 | std::string descendants; 37 | f >> descendants; 38 | 39 | glob_t globbuf; 40 | glob(descendants.c_str(), 0, NULL, &globbuf); 41 | for (int i = 0; i < globbuf.gl_pathc; i++) { 42 | read_ldsoconf_dfs(res, globbuf.gl_pathv[i]); 43 | } 44 | globfree(&globbuf); 45 | } else { 46 | res.push_back(head); 47 | } 48 | } 49 | } 50 | 51 | } // namespace 52 | 53 | std::vector read_ldsoconf() { 54 | std::vector res; 55 | read_ldsoconf_dfs(res, "/etc/ld.so.conf"); 56 | 57 | return res; 58 | } 59 | } // namespace ldsoconf 60 | -------------------------------------------------------------------------------- /shdr_builder.h: -------------------------------------------------------------------------------- 1 | // Copyright (C) 2021 The sold authors 2 | // 3 | // This program is free software: you can redistribute it and/or modify 4 | // it under the terms of the GNU General Public License as published by 5 | // the Free Software Foundation, either version 3 of the License, or 6 | // (at your option) any later version. 7 | // 8 | // This program is distributed in the hope that it will be useful, 9 | // but WITHOUT ANY WARRANTY; without even the implied warranty of 10 | // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 11 | // GNU General Public License for more details. 12 | // 13 | // You should have received a copy of the GNU General Public License 14 | // along with this program. If not, see . 15 | 16 | #include 17 | #include 18 | #include 19 | 20 | #include "utils.h" 21 | 22 | class ShdrBuilder { 23 | public: 24 | enum ShdrType { GnuHash, Dynsym, GnuVersion, GnuVersionR, Dynstr, RelaDyn, InitArray, FiniArray, Strtab, Shstrtab, Dynamic, Text, TLS }; 25 | void EmitShstrtab(FILE* fp); 26 | void EmitShdrs(FILE* fp); 27 | uintptr_t ShstrtabSize() const; 28 | Elf_Half CountShdrs() const { return shdrs.size(); } 29 | void RegisterShdr(Elf_Off offset, uint64_t size, ShdrType type, uint64_t entsize = 0, Elf_Word info = 0); 30 | Elf_Half Shstrndx() const { return shdrs.size() - 1; } 31 | 32 | // After register all shdrs, you must call Freeze. 33 | void Freeze(); 34 | 35 | private: 36 | const std::map type_to_str = { 37 | {GnuHash, ".gnu.hash"}, {Dynsym, ".dynsym"}, {GnuVersion, ".gnu.version"}, {GnuVersionR, ".gnu.version_r"}, 38 | {Dynstr, ".dynstr"}, {RelaDyn, ".rela.dyn"}, {InitArray, ".init_array"}, {FiniArray, ".fini_array"}, 39 | {Strtab, ".strtab"}, {Shstrtab, ".shstrtab"}, {Dynamic, ".dynamic"}, {Text, ".text"}, 40 | {TLS, ".tls"}}; 41 | 42 | // The first section header must be NULL. 43 | std::vector shdrs = {Elf_Shdr{0}}; 44 | uint32_t GetShName(ShdrType type) const; 45 | uint32_t GetIndex(ShdrType type) const; 46 | }; 47 | -------------------------------------------------------------------------------- /tests/run-all-tests.sh: -------------------------------------------------------------------------------- 1 | #! /bin/bash -u 2 | 3 | unexpected_failed_tests= 4 | unexpected_succeeded_tests= 5 | 6 | for dir in hello-g++ hello-gcc just-return-g++ just-return-gcc simple-lib-g++ simple-lib-gcc version-gcc tls-lib-gcc tls-lib-gcc-without-base tls-multiple-lib-gcc tls-thread-g++ call_once-g++ inheritance-g++ typeid-g++ dynamic_cast-g++ tls-dlopen-gcc static-in-function-g++ static-in-class-g++ tls-multiple-module-g++ exception-g++ stb_gnu_unique_tls setjmp-gcc tls-bss-gcc tls-bss-g++ hello-g++-aarch64 hello-gcc-aarch64 just-return-g++-aarch64 simple-lib-g++-aarch64 simple-lib-gcc-aarch64 version-gcc-aarch64 tls-bss-gcc-aarch64 tls-bss-g++-aarch64 just-return-gcc-aarch64 setjmp-gcc-aarch64 exception-g++-aarch64 typeid-g++-aarch64 inheritance-g++-aarch64 dynamic_cast-g++-aarch64 static-in-class-g++-aarch64 static-in-function-g++-aarch64 tls-lib-gcc-aarch64 stb_gnu_unique_tls-aarch64 tls-multiple-module-g++-aarch64 tls-dlopen-gcc-aarch64 call_once-g++-aarch64 tls-thread-g++-aarch64 tls-lib-gcc-without-base-aarch64 7 | do 8 | pushd `pwd` 9 | cd $dir 10 | echo =========== $dir =========== 11 | ./test.sh 12 | if [ "$?" -ne 0 ];then 13 | if [ -z "${unexpected_failed_tests}" ];then 14 | unexpected_failed_tests=${dir} 15 | else 16 | unexpected_failed_tests=${unexpected_failed_tests},${dir} 17 | fi 18 | fi 19 | popd 20 | done 21 | 22 | # TODO(akawashiro): tls-multiple-lib-gcc-aarch64 fails on CI although it succeeds in containers. 23 | for dir in tls-multiple-lib-gcc-aarch64 24 | do 25 | pushd `pwd` 26 | cd $dir 27 | echo =========== $dir =========== 28 | ./test.sh 29 | if [ "$?" -eq 0 ];then 30 | if [ -z "${unexpected_succeeded_tests}" ];then 31 | unexpected_succeeded_tests=${dir} 32 | else 33 | unexpected_succeeded_tests=${unexpected_succeeded_tests},${dir} 34 | fi 35 | fi 36 | popd 37 | done 38 | 39 | echo Unexpected failed tests: ${unexpected_failed_tests} 40 | echo Unexpected succeeded tests: ${unexpected_succeeded_tests} 41 | 42 | if [ -z "${unexpected_failed_tests}" ] 43 | then 44 | exit 0 45 | else 46 | exit 1 47 | fi 48 | -------------------------------------------------------------------------------- /pybind_test/object.cc: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | namespace py = pybind11; 4 | 5 | struct Pet { 6 | enum Kind { Dog = 0, Cat }; 7 | 8 | Pet(const std::string& name) : name(name), type(Kind::Dog) {} 9 | Pet(const std::string& name, Kind type) : name(name), type(type) {} 10 | 11 | void set(int age_) { age = age_; } 12 | void set(const std::string& name_) { name = name_; } 13 | void setName(const std::string& name_) { name = name_; } 14 | const std::string& getName() const { return name; } 15 | const int getAge() const { return age; } 16 | 17 | int age; 18 | std::string name; 19 | Kind type; 20 | }; 21 | 22 | struct Dog : Pet { 23 | Dog(const std::string& name) : Pet(name) {} 24 | std::string bark() const { return "woof!"; } 25 | }; 26 | 27 | struct PolymorphicPet { 28 | virtual ~PolymorphicPet() = default; 29 | }; 30 | 31 | struct PolymorphicDog : PolymorphicPet { 32 | std::string bark() const { return "woof!"; } 33 | }; 34 | 35 | PYBIND11_MODULE(myobject, m) { 36 | py::class_ pet(m, "Pet"); 37 | 38 | pet.def(py::init()) 39 | .def(py::init()) 40 | .def("set", py::overload_cast(&Pet::set), "Set the pet's age") 41 | .def("set", py::overload_cast(&Pet::set), "Set the pet's name") 42 | .def("setName", &Pet::setName) 43 | .def("getName", &Pet::getName) 44 | .def("getAge", &Pet::getAge) 45 | .def("__repr__", [](const Pet& a) { return ""; }) 46 | .def_readwrite("type", &Pet::type); 47 | py::enum_(pet, "Kind").value("Dog", Pet::Kind::Dog).value("Cat", Pet::Kind::Cat).export_values(); 48 | 49 | py::class_(m, "Dog").def(py::init()).def("bark", &Dog::bark); 50 | 51 | m.def("pet_store", []() { return std::unique_ptr(new Dog("Molly")); }); 52 | 53 | py::class_(m, "PolymorphicPet"); 54 | py::class_(m, "PolymorphicDog").def(py::init<>()).def("bark", &PolymorphicDog::bark); 55 | 56 | m.def("pet_store2", []() { return std::unique_ptr(new PolymorphicDog); }); 57 | } 58 | -------------------------------------------------------------------------------- /symtab_builder.h: -------------------------------------------------------------------------------- 1 | // Copyright (C) 2021 The sold authors 2 | // 3 | // This program is free software: you can redistribute it and/or modify 4 | // it under the terms of the GNU General Public License as published by 5 | // the Free Software Foundation, either version 3 of the License, or 6 | // (at your option) any later version. 7 | // 8 | // This program is distributed in the hope that it will be useful, 9 | // but WITHOUT ANY WARRANTY; without even the implied warranty of 10 | // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 11 | // GNU General Public License for more details. 12 | // 13 | // You should have received a copy of the GNU General Public License 14 | // along with this program. If not, see . 15 | 16 | #pragma once 17 | 18 | #include 19 | #include 20 | #include 21 | 22 | #include "hash.h" 23 | #include "strtab_builder.h" 24 | #include "utils.h" 25 | #include "version_builder.h" 26 | 27 | class SymtabBuilder { 28 | public: 29 | SymtabBuilder(); 30 | 31 | void SetSrcSyms(std::vector syms); 32 | 33 | bool Resolve(const std::string& name, const std::string& filename, const std::string version_name, uintptr_t& val_or_index); 34 | 35 | uintptr_t ResolveCopy(const std::string& name, const std::string& filename, const std::string version_name); 36 | 37 | void Build(StrtabBuilder& strtab, VersionBuilder& version); 38 | 39 | void MergePublicSymbols(StrtabBuilder& strtab, VersionBuilder& version); 40 | 41 | void AddPublicSymbol(Syminfo s) { public_syms_.push_back(s); } 42 | 43 | uintptr_t size() const { return symtab_.size() + public_syms_.size(); } 44 | 45 | const Elf_GnuHash& gnu_hash() const { return gnu_hash_; } 46 | 47 | uintptr_t GnuHashSize() const; 48 | 49 | const std::vector& Get() { return symtab_; } 50 | 51 | const std::vector& GetExposedSyms() const { return exposed_syms_; } 52 | 53 | private: 54 | struct Symbol { 55 | Elf_Sym sym; 56 | uintptr_t index; 57 | }; 58 | 59 | // map from (name, soname, version) to (Versym, Sym*) 60 | std::map, std::pair > src_syms_; 61 | // map from name to (Versym, Sym*) 62 | // We use src_fallback_syms_ when we don't have version information. 63 | std::map > src_fallback_syms_; 64 | std::map, Symbol> syms_; 65 | 66 | std::vector exposed_syms_; 67 | std::vector symtab_; 68 | std::vector public_syms_; 69 | 70 | Elf_GnuHash gnu_hash_; 71 | 72 | uintptr_t AddSym(const Syminfo& sym); 73 | }; 74 | -------------------------------------------------------------------------------- /tools/resolve_addr.py: -------------------------------------------------------------------------------- 1 | # Usage: 2 | # 3 | # $ python3 resolve_addr.py sold.INFO /proc/27136/maps 0x7f41080088c9 4 | # 5 | 6 | 7 | import argparse 8 | import re 9 | 10 | 11 | def parse_log(log_filename): 12 | loads = [] 13 | for line in open(log_filename): 14 | matched = re.search(r'\] PT_LOAD mapping: (.*)', line) 15 | if not matched: 16 | continue 17 | load = {} 18 | for tok in matched[1].split(" "): 19 | key, value = tok.split("=", 1) 20 | if key != 'name': 21 | value = int(value) 22 | load[key] = value 23 | loads.append(load) 24 | return loads 25 | 26 | 27 | def parse_maps(maps_filename): 28 | base_addrs = {} 29 | maps = [] 30 | for line in open(maps_filename): 31 | toks = line.split() 32 | if len(toks) == 6: 33 | addrs, perms, off, dev, inode, path = toks 34 | else: 35 | assert len(toks) == 5 36 | addrs, perms, off, dev, inode = toks 37 | path = '' 38 | begin, end = [int(a, 16) for a in addrs.split('-')] 39 | if path not in base_addrs: 40 | base_addrs[path] = begin 41 | base = base_addrs[path] 42 | maps.append({ 43 | 'path': path, 44 | 'addr': begin, 45 | 'end': end, 46 | 'size': end - begin, 47 | 'base': base, 48 | }) 49 | return maps 50 | 51 | 52 | def show_addr(maps, addr, loads=None): 53 | print('Loaded address: %x' % addr) 54 | map_found = None 55 | for map in maps: 56 | if map['addr'] <= addr and addr < map['end']: 57 | map_found = map 58 | break 59 | else: 60 | print('Not found in maps') 61 | return 62 | 63 | print('Loaded path: %s' % map_found['path']) 64 | vaddr = addr - map['base'] 65 | print('Virtual address before reloc: %x' % vaddr) 66 | 67 | for load in loads: 68 | if load['vaddr'] > vaddr or vaddr >= load['vaddr'] + load['memsz']: 69 | continue 70 | orig_vaddr = vaddr - load['vaddr'] + load['orig_vaddr'] 71 | print('Address in %s: %x' % (load['name'], orig_vaddr)) 72 | 73 | 74 | def main(): 75 | parser = argparse.ArgumentParser() 76 | parser.add_argument('log', type=str, help="Path to the log file") 77 | parser.add_argument('maps', type=str, help="Path to the /proc//maps file") 78 | parser.add_argument('addr', type=str, help="Address to be resolved") 79 | args = parser.parse_args() 80 | 81 | loads = parse_log(args.log) 82 | maps = parse_maps(args.maps) 83 | addr = eval(args.addr) 84 | 85 | show_addr(maps, addr, loads=loads) 86 | 87 | 88 | if __name__ == "__main__": 89 | main() 90 | -------------------------------------------------------------------------------- /libtorch_test/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | cmake_minimum_required(VERSION 3.4) 2 | project(torch-test LANGUAGES CXX) 3 | 4 | set(CMAKE_CXX_STANDARD 14) 5 | set(CMAKE_CXX_STANDARD_REQUIRED ON) 6 | 7 | if(NOT CMAKE_BUILD_TYPE) 8 | set(CMAKE_BUILD_TYPE "RelWithDebInfo") 9 | endif() 10 | 11 | find_package(Torch REQUIRED) 12 | set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} ${TORCH_CXX_FLAGS}") 13 | 14 | add_library(torch_test SHARED torch_test.cc) 15 | target_link_libraries(torch_test PRIVATE "${TORCH_LIBRARIES}" 16 | -Wl,-soname,libtorch_test.so) 17 | set_target_properties(torch_test PROPERTIES SUFFIX ".so.original") 18 | 19 | add_custom_target( 20 | torch_test_soldout ALL 21 | COMMAND 22 | GLOG_log_dir=${CMAKE_CURRENT_BINARY_DIR} ${CMAKE_BINARY_DIR}/sold -i 23 | ${CMAKE_CURRENT_BINARY_DIR}/libtorch_test.so.original -o 24 | ${CMAKE_CURRENT_BINARY_DIR}/libtorch_test.so.soldout --section-headers 25 | --check-output && ln -sf libtorch_test.so.soldout libtorch_test.so 26 | DEPENDS torch_test sold 27 | WORKING_DIRECTORY ${CMAKE_CURRENT_BINARY_DIR}) 28 | 29 | add_custom_target( 30 | torch_test_soldout_wo_section 31 | EXCLUDE_FROM_ALL 32 | COMMAND 33 | GLOG_log_dir=${CMAKE_CURRENT_BINARY_DIR} ${CMAKE_BINARY_DIR}/sold -i 34 | ${CMAKE_CURRENT_BINARY_DIR}/libtorch_test.so.original -o 35 | ${CMAKE_CURRENT_BINARY_DIR}/libtorch_test.so.wosection.soldout 36 | --check-output 37 | DEPENDS torch_test sold 38 | WORKING_DIRECTORY ${CMAKE_CURRENT_BINARY_DIR}) 39 | 40 | add_custom_target( 41 | torch_test_main ALL 42 | COMMAND 43 | g++ ${CMAKE_CURRENT_SOURCE_DIR}/torch_test_main.cc 44 | ${CMAKE_CURRENT_BINARY_DIR}/libtorch_test.so.original -o torch_test_main 45 | DEPENDS torch_test 46 | WORKING_DIRECTORY ${CMAKE_CURRENT_BINARY_DIR}) 47 | 48 | add_custom_target( 49 | torch_test_main_linked_soldout 50 | EXCLUDE_FROM_ALL 51 | COMMAND 52 | g++ ${CMAKE_CURRENT_SOURCE_DIR}/torch_test_main.cc 53 | ${CMAKE_CURRENT_BINARY_DIR}/libtorch_test.so.soldout -o 54 | torch_test_main_linked_sold 55 | DEPENDS torch_test_soldout 56 | WORKING_DIRECTORY ${CMAKE_CURRENT_BINARY_DIR}) 57 | 58 | add_executable(torch_test_main_dlopen torch_test_main_dlopen.cc) 59 | target_link_libraries(torch_test_main_dlopen PRIVATE -ldl) 60 | 61 | add_test( 62 | NAME libtorch_test 63 | WORKING_DIRECTORY "${CMAKE_CURRENT_BINARY_DIR}" 64 | COMMAND ./torch_test_main) 65 | set_tests_properties( 66 | libtorch_test PROPERTIES ENVIRONMENT 67 | "LD_LIBRARY_PATH=${CMAKE_CURRENT_BINARY_DIR}") 68 | add_test( 69 | NAME libtorch_test_dlopen 70 | WORKING_DIRECTORY "${CMAKE_CURRENT_BINARY_DIR}" 71 | COMMAND ./torch_test_main_dlopen) 72 | set_tests_properties( 73 | libtorch_test_dlopen PROPERTIES ENVIRONMENT 74 | "LD_LIBRARY_PATH=${CMAKE_CURRENT_BINARY_DIR}") 75 | -------------------------------------------------------------------------------- /CMakeLists.txt: -------------------------------------------------------------------------------- 1 | cmake_minimum_required(VERSION 3.4) 2 | project(sold LANGUAGES CXX) 3 | 4 | set(CMAKE_CXX_STANDARD 14) 5 | set(CMAKE_CXX_STANDARD_REQUIRED ON) 6 | 7 | if(NOT CMAKE_BUILD_TYPE) 8 | set(CMAKE_BUILD_TYPE "RelWithDebInfo") 9 | endif() 10 | 11 | set(CMAKE_MODULE_PATH ${CMAKE_CURRENT_SOURCE_DIR}/cmake) 12 | 13 | include(third-party) 14 | get_third_party(glog) 15 | set(WITH_GFLAGS OFF CACHE INTERNAL "" FORCE) 16 | add_subdirectory(${CMAKE_CURRENT_BINARY_DIR}/glog ${CMAKE_CURRENT_BINARY_DIR}/glog EXCLUDE_FROM_ALL) 17 | include_directories(${CMAKE_CURRENT_BINARY_DIR}/glog ${CMAKE_CURRENT_BINARY_DIR}/glog/src) 18 | add_definitions(-DC10_USE_GLOG=1) 19 | 20 | add_library( 21 | sold_lib 22 | sold.cc 23 | elf_binary.cc 24 | hash.cc 25 | ldsoconf.cc 26 | mprotect_builder.cc 27 | strtab_builder.cc 28 | symtab_builder.cc 29 | shdr_builder.cc 30 | utils.cc 31 | version_builder.cc 32 | ) 33 | 34 | add_executable( 35 | sold 36 | sold_main.cc 37 | ) 38 | target_link_libraries(sold sold_lib glog) 39 | 40 | add_executable( 41 | print_dtrela 42 | print_dtrela.cc 43 | ) 44 | add_executable(renamer renamer_main.cc) 45 | target_link_libraries(renamer sold_lib glog) 46 | 47 | target_link_libraries(print_dtrela sold_lib glog) 48 | 49 | add_executable( 50 | print_dynsymtab 51 | print_dynsymtab.cc 52 | ) 53 | target_link_libraries(print_dynsymtab sold_lib glog) 54 | 55 | add_executable( 56 | print_tls 57 | print_tls.cc 58 | ) 59 | target_link_libraries(print_tls sold_lib glog) 60 | 61 | add_executable( 62 | print_version 63 | print_version.cc 64 | ) 65 | target_link_libraries(print_version sold_lib glog) 66 | 67 | add_executable( 68 | print_ehframe 69 | print_ehframe.cc 70 | ) 71 | target_link_libraries(print_ehframe sold_lib glog) 72 | 73 | add_subdirectory(tests) 74 | 75 | configure_file(${CMAKE_CURRENT_SOURCE_DIR}/CTestCustom.cmake ${CMAKE_CURRENT_BINARY_DIR}) 76 | include(CTest) 77 | 78 | if(BUILD_TESTING) 79 | foreach(t exe hash) 80 | add_custom_target( 81 | test_${t}_out ALL 82 | COMMAND "${CMAKE_CURRENT_BINARY_DIR}/sold" "${CMAKE_CURRENT_BINARY_DIR}/tests/test_${t}" -o "${CMAKE_CURRENT_BINARY_DIR}/tests/test_${t}_out" --section-headers 83 | DEPENDS sold test_${t} 84 | ) 85 | 86 | add_test( 87 | NAME ${t}_test 88 | COMMAND ${CMAKE_CURRENT_BINARY_DIR}/tests/test_${t}_out 89 | ) 90 | endforeach() 91 | add_test( 92 | NAME c++_features_test 93 | WORKING_DIRECTORY "${CMAKE_CURRENT_SOURCE_DIR}/tests" 94 | COMMAND run-all-tests.sh 95 | ) 96 | add_test( 97 | NAME renamer 98 | WORKING_DIRECTORY "${CMAKE_CURRENT_SOURCE_DIR}/tests/renamer" 99 | COMMAND test.sh) 100 | endif() 101 | 102 | if(SOLD_PYBIND_TEST) 103 | get_third_party(pybind11) 104 | add_subdirectory(${CMAKE_CURRENT_BINARY_DIR}/pybind11 ${CMAKE_CURRENT_BINARY_DIR}/pybind11 EXCLUDE_FROM_ALL) 105 | add_subdirectory(pybind_test) 106 | endif() 107 | 108 | if(SOLD_LIBTORCH_TEST) 109 | add_subdirectory(libtorch_test) 110 | endif() 111 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # sold 2 | 3 | **NOTE**: The development is taken over by @akawashiro. Check out this repository instead: https://github.com/akawashiro/sold/ 4 | 5 | `sold` is a linker software which links a shared objects and its depending 6 | shared objects. For example, 7 | ```bash 8 | % ldd libhoge.so 9 | linux-vdso.so.1 (0x00007ffee03bb000) 10 | libfuga.so (0x00007fb6550b2000) 11 | libstdc++.so.6 => /lib/x86_64-linux-gnu/libstdc++.so.6 (0x00007fb654eb5000) 12 | libc.so.6 => /lib/x86_64-linux-gnu/libc.so.6 (0x00007fb654cc3000) 13 | libm.so.6 => /lib/x86_64-linux-gnu/libm.so.6 (0x00007fb654b74000) 14 | /lib64/ld-linux-x86-64.so.2 (0x00007fb6550be000) 15 | libgcc_s.so.1 => /lib/x86_64-linux-gnu/libgcc_s.so.1 (0x00007fb654b59000) 16 | % sold -i libhoge.so -o libhoge2.so 17 | % ldd libhoge2.so 18 | /lib64/ld-linux-x86-64.so.2 (0x00007f78a666b000) 19 | linux-vdso.so.1 (0x00007fffd89d1000) 20 | libc.so.6 => /lib/x86_64-linux-gnu/libc.so.6 (0x00007f789644f000) 21 | libgcc_s.so.1 => /lib/x86_64-linux-gnu/libgcc_s.so.1 (0x00007f7896434000) 22 | libm.so.6 => /lib/x86_64-linux-gnu/libm.so.6 (0x00007f78962e5000) 23 | libstdc++.so.6 => /lib/x86_64-linux-gnu/libstdc++.so.6 (0x00007f7896104000) 24 | ``` 25 | 26 | ## Requirements 27 | `sold` works only on Linux on x86-64 and aarch64 architectures. 28 | 29 | ## How to build 30 | ```bash 31 | git clone https://github.com/shinh/sold.git 32 | cd sold 33 | mkdir -p build 34 | cd build 35 | cmake .. 36 | make 37 | ``` 38 | Now you can see the `sold` in `build` directory. 39 | 40 | ## How to use 41 | ```bash 42 | sold -i [INPUT] -o [OUTPUT] 43 | ``` 44 | Options 45 | - `--section-headers`: Emit section headers. Output shared objects work without section headers but they are useful for debugging. 46 | - `--check-output`: Check integrity of the output by parsing it again. 47 | - `--exclude-so`: Specify a shared object not to combine. 48 | 49 | # Renamer 50 | `renamer` is software to rename symbols in shared objects. You can rename symbols in shared objects like the following. 51 | ``` 52 | % cat mapping 53 | hoge fugafuga 54 | % renamer libhoge_original.so --output libhoge_renamed.so --rename-mapping-file mapping 55 | ``` 56 | 57 | ## Requirements & How to build 58 | Just same as `sold`. 59 | 60 | ## How to use 61 | ```bash 62 | renamer [INPUT] --output [OUTPUT] --rename-mapping-file [MAPPING] 63 | ``` 64 | All lines in [MAPPING] must be a space separated pair of the old name of a symbol and the new name. 65 | 66 | # For developers 67 | Please run "./run-format.sh" before merging to master branch. 68 | 69 | ## TODO 70 | - Executables 71 | - TLS in executables 72 | - Initial exec and local exec 73 | - x86-32 74 | - Test Fedora linux in CI 75 | 76 | ## Integration test with practical libraries 77 | ### pybind test 78 | The purpose of this test is to check `sold` can preserve the complex ABI. 79 | ```bash 80 | git clone https://github.com/shinh/sold.git 81 | cd sold 82 | mkdir -p build 83 | cd build 84 | cmake .. -DSOLD_PYBIND_TEST=ON 85 | make 86 | ctest 87 | ``` 88 | ## libtorch test 89 | ``` 90 | mkdir -p build 91 | cd build 92 | cmake -DCMAKE_PREFIX_PATH=/absolute/path/to/libtorch/dir -DSOLD_LIBTORCH_TEST=ON -GNinja .. 93 | ninja 94 | ``` 95 | 96 | ## Test with Docker 97 | ``` 98 | sudo docker build -f ubuntu18.04.Dockerfile . 99 | sudo docker build -f ubuntu20.04.Dockerfile . 100 | sudo docker build -f fedora-latest.Dockerfile . 101 | ``` 102 | -------------------------------------------------------------------------------- /ehframe_builder.h: -------------------------------------------------------------------------------- 1 | // Copyright (C) 2021 The sold authors 2 | // 3 | // This program is free software: you can redistribute it and/or modify 4 | // it under the terms of the GNU General Public License as published by 5 | // the Free Software Foundation, either version 3 of the License, or 6 | // (at your option) any later version. 7 | // 8 | // This program is distributed in the hope that it will be useful, 9 | // but WITHOUT ANY WARRANTY; without even the implied warranty of 10 | // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 11 | // GNU General Public License for more details. 12 | // 13 | // You should have received a copy of the GNU General Public License 14 | // along with this program. If not, see . 15 | 16 | #pragma once 17 | 18 | #include "utils.h" 19 | 20 | class EHFrameBuilder { 21 | public: 22 | EHFrameBuilder() { 23 | eh_frame_header_.version = 0x1; 24 | eh_frame_header_.eh_frame_ptr_enc = DW_EH_PE_sdata4 + DW_EH_PE_pcrel; 25 | eh_frame_header_.fde_count_enc = DW_EH_PE_udata4; 26 | eh_frame_header_.table_enc = DW_EH_PE_sdata4 | DW_EH_PE_datarel; 27 | eh_frame_header_.eh_frame_ptr = 0; 28 | eh_frame_header_.fde_count = 0; 29 | eh_frame_header_.table = std::vector(); 30 | } 31 | 32 | void Emit(FILE* fp) { 33 | Write(fp, eh_frame_header_.version); 34 | Write(fp, eh_frame_header_.eh_frame_ptr_enc); 35 | Write(fp, eh_frame_header_.fde_count_enc); 36 | Write(fp, eh_frame_header_.table_enc); 37 | Write(fp, eh_frame_header_.eh_frame_ptr); 38 | Write(fp, eh_frame_header_.fde_count); 39 | for (const EHFrameHeader::FDETableEntry te : eh_frame_header_.table) { 40 | Write(fp, te.initial_loc); 41 | Write(fp, te.fde_ptr); 42 | } 43 | } 44 | 45 | uintptr_t Size() const { 46 | return sizeof(eh_frame_header_.version) + sizeof(eh_frame_header_.eh_frame_ptr_enc) + sizeof(eh_frame_header_.fde_count_enc) + 47 | sizeof(eh_frame_header_.table_enc) + sizeof(eh_frame_header_.eh_frame_ptr) + sizeof(eh_frame_header_.fde_count) + 48 | eh_frame_header_.fde_count * 49 | (sizeof(EHFrameHeader::FDETableEntry::fde_ptr) + sizeof(EHFrameHeader::FDETableEntry::initial_loc)); 50 | } 51 | 52 | void Add(const std::string& name, const EHFrameHeader& efh, const uintptr_t efh_vaddr, const uintptr_t load_offset, 53 | const uintptr_t new_efh_vaddr) { 54 | LOG(INFO) << "EHFrameBuilder" << SOLD_LOG_BITS(efh.version) << SOLD_LOG_DWEHPE(efh.eh_frame_ptr_enc) 55 | << SOLD_LOG_DWEHPE(efh.fde_count_enc) << SOLD_LOG_DWEHPE(efh.table_enc) << SOLD_LOG_BITS(efh.eh_frame_ptr) 56 | << SOLD_LOG_BITS(efh.fde_count); 57 | for (const auto te : efh.table) { 58 | LOG(INFO) << "EHFrameBuilder" << SOLD_LOG_BITS(te.fde_ptr) << SOLD_LOG_BITS(te.initial_loc); 59 | } 60 | 61 | eh_frame_header_.fde_count += efh.fde_count; 62 | for (const auto te : efh.table) { 63 | EHFrameHeader::FDETableEntry new_te; 64 | new_te.fde_ptr = static_cast(efh_vaddr) + te.fde_ptr + static_cast(load_offset) - new_efh_vaddr; 65 | new_te.initial_loc = static_cast(efh_vaddr) + te.initial_loc + static_cast(load_offset) - new_efh_vaddr; 66 | eh_frame_header_.table.emplace_back(new_te); 67 | LOG(INFO) << "EHFrameBuilder" << SOLD_LOG_BITS(new_te.fde_ptr) << SOLD_LOG_BITS(new_te.initial_loc); 68 | } 69 | } 70 | 71 | uint32_t fde_count() const { return eh_frame_header_.fde_count; } 72 | 73 | private: 74 | EHFrameHeader eh_frame_header_; 75 | }; 76 | -------------------------------------------------------------------------------- /mprotect_builder.cc: -------------------------------------------------------------------------------- 1 | #include "mprotect_builder.h" 2 | 3 | constexpr uint8_t MprotectBuilder::memprotect_body_code_x86_64[]; 4 | constexpr uint8_t MprotectBuilder::memprotect_end_code_x86_64[]; 5 | constexpr uint8_t MprotectBuilder::memprotect_end_code_aarch64[]; 6 | 7 | void MprotectBuilder::EmitX86_64(FILE* fp, uintptr_t mprotect_code_offset) { 8 | uint8_t* mprotect_code = (uint8_t*)malloc(Size()); 9 | uint8_t* mprotect_code_head = mprotect_code; 10 | for (int i = 0; i < offsets.size(); i++) { 11 | LOG(INFO) << "MprotectBuilder::Emit: " << SOLD_LOG_BITS(offsets[i]) << SOLD_LOG_BITS(sizes[i]); 12 | 13 | memcpy(mprotect_code_head, memprotect_body_code_x86_64, sizeof(memprotect_body_code_x86_64)); 14 | int64_t* offset_p = (int64_t*)(mprotect_code_head + memprotect_body_addr_offset_x86_64); 15 | // 17 is the length of `mov $0xdeadbeefdeadbeef, %rdi; lea (%rip), %rsi' 16 | int64_t offset_v = (offsets[i] & (~(0x1000 - 1))) - 17 | (static_cast(mprotect_code_offset) + static_cast(mprotect_code_head - mprotect_code) + 17); 18 | LOG(INFO) << "MprotectBuilder::Emit" << SOLD_LOG_BITS(offset_v) << SOLD_LOG_KEY(offset_v); 19 | *offset_p = offset_v; 20 | uint32_t* size_p = (uint32_t*)(mprotect_code_head + memprotect_body_size_offset_x86_64); 21 | *size_p = ((offsets[i] + sizes[i]) & (~(0x1000 - 1))) - (offsets[i] & (~(0x1000 - 1))); 22 | mprotect_code_head += sizeof(memprotect_body_code_x86_64); 23 | } 24 | memcpy(mprotect_code_head, memprotect_end_code_x86_64, sizeof(memprotect_end_code_x86_64)); 25 | mprotect_code_head += sizeof(memprotect_end_code_x86_64); 26 | 27 | CHECK(fwrite(mprotect_code, sizeof(uint8_t), Size(), fp) == Size()); 28 | free(mprotect_code); 29 | } 30 | 31 | namespace { 32 | std::vector set_immediate_to_register_aarch64(int64_t value, uint8_t reg) { 33 | std::vector ret; 34 | for (int i = 0; i < 4; i++) { 35 | uint32_t u = 0b11110010'10000000'00000000'00000000; // movk instruction 36 | u |= (i << 21); 37 | u |= ((value >> (i * 16)) & 0xffff) << 5; 38 | u |= reg; 39 | ret.emplace_back(u); 40 | } 41 | return ret; 42 | } 43 | } // namespace 44 | 45 | void MprotectBuilder::EmitAarch64(FILE* fp, uintptr_t mprotect_code_offset) { 46 | long int old_pos = ftell(fp); 47 | 48 | LOG(INFO) << "MprotectBuilder::EmitAarch64"; 49 | std::vector insts; 50 | for (int i = 0; i < offsets.size(); i++) { 51 | // 5 is the length of x0 <- offsets[i] using 4 movk instructions; adr x3, 0 52 | int64_t offset = offsets[i] - (static_cast(mprotect_code_offset) + body_code_length_aarch64 + 5 * 4); 53 | auto set_x0 = set_immediate_to_register_aarch64(offset, 0); // x0 <- offsets[i] using 4 movk instructions 54 | insts.insert(insts.end(), set_x0.begin(), set_x0.end()); // 55 | insts.emplace_back(0b00010000'00000000'00000000'00000011); // adr x3, 0 56 | insts.emplace_back(0x8B030000); // add x0, x0,x3 57 | auto set_x1 = set_immediate_to_register_aarch64(sizes[i], 1); // x1 <- len[i] using 4 movk instructions 58 | insts.insert(insts.end(), set_x1.begin(), set_x1.end()); // 59 | insts.emplace_back(0xD2800022); // mov x2, 1(PROT_READ) 60 | insts.emplace_back(0x52800148); // mov w8, 10(mprotect) 61 | insts.emplace_back(0xD4000001); // svc 0 62 | } 63 | insts.emplace_back(0xD65F03C0); 64 | 65 | for (uint32_t i : insts) { 66 | CHECK(fwrite(&i, sizeof(uint32_t), 1, fp) == 1); 67 | } 68 | CHECK(ftell(fp) - old_pos == Size()); 69 | } 70 | 71 | -------------------------------------------------------------------------------- /mprotect_builder.h: -------------------------------------------------------------------------------- 1 | // Copyright (C) 2021 The sold authors 2 | // 3 | // This program is free software: you can redistribute it and/or modify 4 | // it under the terms of the GNU General Public License as published by 5 | // the Free Software Foundation, either version 3 of the License, or 6 | // (at your option) any later version. 7 | // 8 | // This program is distributed in the hope that it will be useful, 9 | // but WITHOUT ANY WARRANTY; without even the implied warranty of 10 | // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 11 | // GNU General Public License for more details. 12 | // 13 | // You should have received a copy of the GNU General Public License 14 | // along with this program. If not, see . 15 | 16 | #pragma once 17 | 18 | #include 19 | #include 20 | 21 | #include "utils.h" 22 | 23 | class MprotectBuilder { 24 | public: 25 | void SetMachineType(const Elf64_Half machine_type) { 26 | CHECK(machine_type == EM_X86_64 || machine_type == EM_AARCH64); 27 | machine_type_ = machine_type; 28 | } 29 | void Add(uintptr_t offset, uintptr_t size) { 30 | offsets.emplace_back(offset); 31 | sizes.emplace_back(size); 32 | } 33 | uintptr_t Size() const { 34 | CHECK(offsets.size() == sizes.size()); 35 | if (machine_type_ == EM_X86_64) { 36 | return sizeof(memprotect_body_code_x86_64) * offsets.size() + sizeof(memprotect_end_code_x86_64); 37 | } else if (machine_type_ == EM_AARCH64) { 38 | return body_code_length_aarch64 * offsets.size() + ret_code_length_aarch64; 39 | } else { 40 | CHECK(false) << SOLD_LOG_KEY(machine_type_) << " is not supported."; 41 | } 42 | } 43 | void Emit(FILE* fp, uintptr_t mprotect_code_offset) { 44 | CHECK(machine_type_ == EM_X86_64 || machine_type_ == EM_AARCH64) << "SetMachineType before Emit"; 45 | if (machine_type_ == EM_X86_64) { 46 | EmitX86_64(fp, mprotect_code_offset); 47 | } else if (machine_type_ == EM_AARCH64) { 48 | EmitAarch64(fp, mprotect_code_offset); 49 | } else { 50 | CHECK(false) << SOLD_LOG_KEY(machine_type_) << " is not supported."; 51 | } 52 | } 53 | 54 | // call SYS_mprotect syscall 55 | // 56 | // mov $0xdeadbeefdeadbeef, %rdi 57 | // lea (%rip), %rsi 58 | // add %rsi, %rdi 59 | // mov $0xaabbcc, %rsi (size) 60 | // mov $0x1, %rdx (0x1 = PROT_READ) 61 | // mov $10, %eax (10 = SYS_mprotect) 62 | // syscall 63 | // test %eax, %eax 64 | // jz ok 65 | // ud2 66 | // ok: 67 | static constexpr uint8_t memprotect_body_code_x86_64[] = {0x48, 0xbf, 0xef, 0xbe, 0xad, 0xde, 0xef, 0xbe, 0xad, 0xde, 0x48, 0x8d, 68 | 0x35, 0x00, 0x00, 0x00, 0x00, 0x48, 0x01, 0xf7, 0x48, 0xc7, 0xc6, 0xcc, 69 | 0xbb, 0xaa, 0x00, 0x48, 0xc7, 0xc2, 0x01, 0x00, 0x00, 0x00, 0xb8, 0x0a, 70 | 0x00, 0x00, 0x00, 0x0f, 0x05, 0x85, 0xc0, 0x74, 0x02, 0x0f, 0x0b}; 71 | // offset to 0xabbccdd 72 | static constexpr int memprotect_body_addr_offset_x86_64 = 2; 73 | // offset to 0xaabbcc 74 | static constexpr int memprotect_body_size_offset_x86_64 = 23; 75 | 76 | // ret 77 | static constexpr uint8_t memprotect_end_code_x86_64[] = {0xc3}; 78 | 79 | // ret 80 | static constexpr uint8_t memprotect_end_code_aarch64[] = {0xc0, 0x03, 0x5f, 0xd6}; 81 | 82 | static constexpr int body_code_length_aarch64 = 13 * 4; 83 | static constexpr int ret_code_length_aarch64 = 4; 84 | 85 | private: 86 | void EmitX86_64(FILE* fp, uintptr_t mprotect_code_offset); 87 | void EmitAarch64(FILE* fp, uintptr_t mprotect_code_offset); 88 | Elf64_Half machine_type_; 89 | std::vector offsets; 90 | std::vector sizes; 91 | }; 92 | -------------------------------------------------------------------------------- /version_builder.cc: -------------------------------------------------------------------------------- 1 | // Copyright (C) 2021 The sold authors 2 | // 3 | // This program is free software: you can redistribute it and/or modify 4 | // it under the terms of the GNU General Public License as published by 5 | // the Free Software Foundation, either version 3 of the License, or 6 | // (at your option) any later version. 7 | // 8 | // This program is distributed in the hope that it will be useful, 9 | // but WITHOUT ANY WARRANTY; without even the implied warranty of 10 | // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 11 | // GNU General Public License for more details. 12 | // 13 | // You should have received a copy of the GNU General Public License 14 | // along with this program. If not, see . 15 | 16 | #include "version_builder.h" 17 | 18 | void VersionBuilder::Add(Elf_Versym versym, const std::string& soname, const std::string& version, StrtabBuilder& strtab, 19 | const unsigned char st_info) { 20 | // When the corresponding shared object doesn't have version information, 21 | // we cannot help inferring it from st_info. 22 | if (versym == NO_VERSION_INFO) { 23 | versym = ((ELF_ST_BIND(st_info) != STB_LOCAL) ? VER_NDX_GLOBAL : VER_NDX_LOCAL); 24 | } 25 | 26 | if (is_special_ver_ndx(versym)) { 27 | CHECK(soname.empty() && version.empty()) << " excess soname or version information is given."; 28 | LOG(INFO) << "VersionBuilder::" << special_ver_ndx_to_str(versym); 29 | 30 | vers.push_back(versym); 31 | } else { 32 | CHECK(!soname.empty() && !version.empty()) << " versym=" << special_ver_ndx_to_str(versym); 33 | 34 | auto found_filename = soname_to_filename_.find(soname); 35 | CHECK(found_filename != soname_to_filename_.end()) 36 | << soname << " does not exists in soname_to_filename." << SOLD_LOG_KEY(soname) << SOLD_LOG_KEY(version); 37 | std::string filename = found_filename->second; 38 | 39 | strtab.Add(filename); 40 | strtab.Add(version); 41 | 42 | if (data.find(filename) != data.end()) { 43 | if (data[filename].find(version) != data[filename].end()) { 44 | ; 45 | } else { 46 | data[filename][version] = vernum; 47 | vernum++; 48 | } 49 | } else { 50 | std::map ma; 51 | ma[version] = vernum; 52 | data[filename] = ma; 53 | vernum++; 54 | } 55 | LOG(INFO) << "VersionBuilder::Add(" << data[filename][version] << ", " << soname << ", " << version << ")"; 56 | vers.push_back(data[filename][version]); 57 | } 58 | } 59 | 60 | uintptr_t VersionBuilder::SizeVerneed() const { 61 | uintptr_t s = 0; 62 | for (const auto& m1 : data) { 63 | s += sizeof(Elf_Verneed); 64 | for (const auto& m2 : m1.second) { 65 | s += sizeof(Elf_Vernaux); 66 | } 67 | } 68 | return s; 69 | } 70 | 71 | void VersionBuilder::EmitVersym(FILE* fp) { 72 | if (data.size() > 0) { 73 | for (auto v : vers) { 74 | CHECK(fwrite(&v, sizeof(v), 1, fp) == 1); 75 | } 76 | } 77 | } 78 | 79 | void VersionBuilder::EmitVerneed(FILE* fp, StrtabBuilder& strtab) { 80 | int n_verneed = 0; 81 | for (const auto& m1 : data) { 82 | n_verneed++; 83 | 84 | Elf_Verneed v; 85 | v.vn_version = VER_NEED_CURRENT; 86 | v.vn_cnt = m1.second.size(); 87 | v.vn_file = strtab.GetPos(m1.first); 88 | v.vn_aux = sizeof(Elf_Verneed); 89 | v.vn_next = (n_verneed == data.size()) ? 0 : sizeof(Elf_Verneed) + m1.second.size() * sizeof(Elf_Vernaux); 90 | 91 | CHECK(fwrite(&v, sizeof(v), 1, fp) == 1); 92 | 93 | int n_vernaux = 0; 94 | for (const auto& m2 : m1.second) { 95 | n_vernaux++; 96 | 97 | Elf_Vernaux a; 98 | a.vna_hash = CalcHash(m2.first); 99 | a.vna_flags = VER_FLG_WEAK; 100 | a.vna_other = m2.second; 101 | a.vna_name = strtab.GetPos(m2.first); 102 | a.vna_next = (n_vernaux == m1.second.size()) ? 0 : sizeof(Elf_Vernaux); 103 | 104 | CHECK(fwrite(&a, sizeof(a), 1, fp) == 1); 105 | } 106 | } 107 | } 108 | -------------------------------------------------------------------------------- /sold_main.cc: -------------------------------------------------------------------------------- 1 | // Copyright (C) 2021 The sold authors 2 | // 3 | // This program is free software: you can redistribute it and/or modify 4 | // it under the terms of the GNU General Public License as published by 5 | // the Free Software Foundation, either version 3 of the License, or 6 | // (at your option) any later version. 7 | // 8 | // This program is distributed in the hope that it will be useful, 9 | // but WITHOUT ANY WARRANTY; without even the implied warranty of 10 | // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 11 | // GNU General Public License for more details. 12 | // 13 | // You should have received a copy of the GNU General Public License 14 | // along with this program. If not, see . 15 | 16 | #include "sold.h" 17 | 18 | #include 19 | 20 | void print_help(std::ostream& os) { 21 | os << R"(usage: sold [option] [input] 22 | Options: 23 | -h, --help Show this help message and exit 24 | -o, --output-file OUTPUT_FILE Specify the ELF file to output (this option is mandatory) 25 | -i, --input-file INPUT_FILE Specify the ELF file to input 26 | -e, --exclude-so EXCLUDE_FILE Specify the ELF file to exclude (e.g. libmax.so) 27 | -L, --custom-library-path PATH Use PATH instead of the default path such as /usr/lib 28 | --section-headers Emit section headers 29 | --check-output Check the output using sold itself 30 | --exclude-from-fini Do not use .fini_array of the ELF file 31 | 32 | The last argument is interpreted as SOURCE_FILE when -i option isn't given. 33 | )" << std::endl; 34 | } 35 | 36 | int main(int argc, char* const argv[]) { 37 | google::InitGoogleLogging(argv[0]); 38 | 39 | static option long_options[] = { 40 | {"help", no_argument, nullptr, 'h'}, 41 | {"input-file", required_argument, nullptr, 'i'}, 42 | {"output-file", required_argument, nullptr, 'o'}, 43 | {"exclude-so", required_argument, nullptr, 'e'}, 44 | {"custom-library-path", required_argument, nullptr, 'L'}, 45 | {"section-headers", no_argument, nullptr, 1}, 46 | {"check-output", no_argument, nullptr, 2}, 47 | {"exclude-from-fini", required_argument, nullptr, 3}, 48 | {0, 0, 0, 0}, 49 | }; 50 | 51 | std::string input_file; 52 | std::string output_file; 53 | std::vector exclude_sos; 54 | std::vector exclude_finis; 55 | std::vector custome_library_path; 56 | bool emit_section_header = false; 57 | bool check_output = false; 58 | 59 | int opt; 60 | while ((opt = getopt_long(argc, argv, "hi:o:e:", long_options, nullptr)) != -1) { 61 | switch (opt) { 62 | case 1: 63 | emit_section_header = true; 64 | break; 65 | case 2: 66 | check_output = true; 67 | break; 68 | case 3: 69 | exclude_finis.push_back(optarg); 70 | break; 71 | case 'e': 72 | exclude_sos.push_back(optarg); 73 | break; 74 | case 'L': 75 | custome_library_path.emplace_back(optarg); 76 | break; 77 | case 'i': 78 | input_file = optarg; 79 | break; 80 | case 'o': 81 | output_file = optarg; 82 | break; 83 | case 'h': 84 | print_help(std::cout); 85 | return 0; 86 | case '?': 87 | print_help(std::cerr); 88 | return 1; 89 | } 90 | } 91 | 92 | if (optind < argc && input_file.empty()) { 93 | input_file = argv[optind++]; 94 | } 95 | 96 | if (output_file == "") { 97 | std::cerr << "You must specify the output file." << std::endl; 98 | return 1; 99 | } 100 | 101 | Sold sold(input_file, exclude_sos, exclude_finis, custome_library_path, emit_section_header); 102 | sold.Link(output_file); 103 | 104 | if (check_output) { 105 | std::string dummy = output_file + ".dummy-for-check-output"; 106 | Sold check(output_file, exclude_sos, exclude_finis, custome_library_path, emit_section_header); 107 | check.Link(dummy); 108 | std::remove(dummy.c_str()); 109 | } 110 | return 0; 111 | } 112 | -------------------------------------------------------------------------------- /shdr_builder.cc: -------------------------------------------------------------------------------- 1 | // Copyright (C) 2021 The sold authors 2 | // 3 | // This program is free software: you can redistribute it and/or modify 4 | // it under the terms of the GNU General Public License as published by 5 | // the Free Software Foundation, either version 3 of the License, or 6 | // (at your option) any later version. 7 | // 8 | // This program is distributed in the hope that it will be useful, 9 | // but WITHOUT ANY WARRANTY; without even the implied warranty of 10 | // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 11 | // GNU General Public License for more details. 12 | // 13 | // You should have received a copy of the GNU General Public License 14 | // along with this program. If not, see . 15 | 16 | #include "shdr_builder.h" 17 | 18 | #include 19 | #include "utils.h" 20 | 21 | void ShdrBuilder::EmitShstrtab(FILE* fp) { 22 | std::string str = ""; 23 | str += '\0'; 24 | for (const auto& i : type_to_str) { 25 | str += i.second; 26 | str += '\0'; 27 | } 28 | 29 | CHECK(fwrite(str.c_str(), str.size(), 1, fp) == 1); 30 | } 31 | 32 | uintptr_t ShdrBuilder::ShstrtabSize() const { 33 | std::string str = ""; 34 | str += '\0'; 35 | for (const auto& i : type_to_str) { 36 | str += i.second; 37 | str += '\0'; 38 | } 39 | return str.size(); 40 | } 41 | 42 | uint32_t ShdrBuilder::GetShName(ShdrType type) const { 43 | // The head of shstrtab is '\0' so we must skip it. 44 | uint32_t r = 1; 45 | for (const auto& i : type_to_str) { 46 | if (i.first == type) { 47 | break; 48 | } else { 49 | r += i.second.size() + 1; 50 | } 51 | } 52 | return r; 53 | } 54 | 55 | void ShdrBuilder::EmitShdrs(FILE* fp) { 56 | Elf_Shdr shstrtab; 57 | bool found_shstrtab = false; 58 | int num_not_shstrtab = 0; 59 | 60 | // Emit other than shstrtab 61 | for (const auto& s : shdrs) { 62 | if (s.sh_name == GetShName(Shstrtab)) { 63 | shstrtab = s; 64 | found_shstrtab = true; 65 | } else { 66 | num_not_shstrtab++; 67 | CHECK(fwrite(&s, sizeof(s), 1, fp) == 1); 68 | } 69 | } 70 | 71 | // num_not_shstrtab must not be 0 because ehdr_.e_shstrndx is ignored when it is 0 72 | CHECK(found_shstrtab); 73 | CHECK(num_not_shstrtab != 0); 74 | 75 | CHECK(fwrite(&shstrtab, sizeof(shstrtab), 1, fp) == 1); 76 | } 77 | 78 | uint32_t ShdrBuilder::GetIndex(ShdrType type) const { 79 | uint32_t r = 0; 80 | for (const auto& s : shdrs) { 81 | if (s.sh_name == GetShName(type)) { 82 | return r; 83 | } 84 | r++; 85 | } 86 | 87 | LOG(FATAL) << "It is not in shdrs."; 88 | exit(1); 89 | } 90 | 91 | void ShdrBuilder::Freeze() { 92 | for (auto& s : shdrs) { 93 | if (s.sh_name == GetShName(GnuHash) || s.sh_name == GetShName(RelaDyn) || s.sh_name == GetShName(GnuVersion)) { 94 | s.sh_link = GetIndex(Dynsym); 95 | } else if (s.sh_name == GetShName(Dynsym) || s.sh_name == GetShName(GnuVersionR) || s.sh_name == GetShName(Dynamic)) { 96 | s.sh_link = GetIndex(Dynstr); 97 | } 98 | } 99 | } 100 | 101 | void ShdrBuilder::RegisterShdr(Elf_Off offset, uint64_t size, ShdrType type, uint64_t entsize, Elf_Word info) { 102 | Elf_Shdr shdr = {0}; 103 | shdr.sh_name = GetShName(type); 104 | shdr.sh_offset = offset; 105 | shdr.sh_addr = offset; 106 | shdr.sh_size = size; 107 | shdr.sh_entsize = entsize; 108 | shdr.sh_info = info; 109 | switch (type) { 110 | case GnuHash: 111 | shdr.sh_type = SHT_GNU_HASH; 112 | shdr.sh_flags = SHF_ALLOC; 113 | break; 114 | case Dynsym: 115 | shdr.sh_type = SHT_DYNSYM; 116 | shdr.sh_flags = SHF_ALLOC; 117 | 118 | // TODO(akawashiro) Now, I assume the last local symbol is located at index 0. 119 | // ref: https://www.sco.com/developers/gabi/1998-04-29/ch4.sheader.html#sh_link 120 | // "One greater than the symbol table index of the last local symbol (binding STB_LOCAL)." 121 | shdr.sh_info = 1; 122 | 123 | break; 124 | case GnuVersion: 125 | shdr.sh_type = SHT_GNU_versym; 126 | shdr.sh_flags = SHF_ALLOC; 127 | break; 128 | case GnuVersionR: 129 | shdr.sh_type = SHT_GNU_verneed; 130 | shdr.sh_flags = SHF_ALLOC; 131 | break; 132 | case Dynstr: 133 | shdr.sh_type = SHT_STRTAB; 134 | shdr.sh_flags = SHF_ALLOC; 135 | break; 136 | case RelaDyn: 137 | shdr.sh_type = SHT_RELA; 138 | shdr.sh_flags = SHF_ALLOC; 139 | break; 140 | case InitArray: 141 | shdr.sh_type = SHT_INIT_ARRAY; 142 | shdr.sh_flags = SHF_ALLOC | SHF_EXECINSTR; 143 | break; 144 | case FiniArray: 145 | shdr.sh_type = SHT_FINI_ARRAY; 146 | shdr.sh_flags = SHF_ALLOC | SHF_EXECINSTR; 147 | break; 148 | case Strtab: 149 | shdr.sh_type = SHT_STRTAB; 150 | shdr.sh_flags = 0; 151 | shdr.sh_addr = 0; 152 | break; 153 | case Shstrtab: 154 | shdr.sh_type = SHT_STRTAB; 155 | shdr.sh_flags = 0; 156 | shdr.sh_addr = 0; 157 | break; 158 | case Dynamic: 159 | shdr.sh_type = SHT_DYNAMIC; 160 | shdr.sh_flags = SHF_ALLOC | SHF_WRITE; 161 | break; 162 | default: 163 | LOG(FATAL) << "Not implemented"; 164 | exit(1); 165 | } 166 | shdrs.push_back(shdr); 167 | } 168 | -------------------------------------------------------------------------------- /elf_binary.h: -------------------------------------------------------------------------------- 1 | // Copyright (C) 2021 The sold authors 2 | // 3 | // This program is free software: you can redistribute it and/or modify 4 | // it under the terms of the GNU General Public License as published by 5 | // the Free Software Foundation, either version 3 of the License, or 6 | // (at your option) any later version. 7 | // 8 | // This program is distributed in the hope that it will be useful, 9 | // but WITHOUT ANY WARRANTY; without even the implied warranty of 10 | // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 11 | // GNU General Public License for more details. 12 | // 13 | // You should have received a copy of the GNU General Public License 14 | // along with this program. If not, see . 15 | 16 | #pragma once 17 | 18 | #include "hash.h" 19 | #include "utils.h" 20 | 21 | #include 22 | #include 23 | #include 24 | #include 25 | #include 26 | 27 | class ELFBinary { 28 | public: 29 | ELFBinary(const std::string& filename, int fd, char* head, size_t mapped_size, size_t filesize); 30 | 31 | ~ELFBinary(); 32 | 33 | static bool IsELF(const char* p); 34 | 35 | const std::string& filename() const { return filename_; } 36 | 37 | const Elf_Ehdr* ehdr() const { return ehdr_; } 38 | const std::vector phdrs() const { return phdrs_; } 39 | std::vector phdrs_mut() const { return phdrs_; } 40 | const std::vector loads() const { return loads_; } 41 | const Elf_Phdr* tls() const { return tls_; } 42 | const Elf_Phdr* gnu_stack() const { return gnu_stack_; } 43 | const Elf_Phdr* gnu_relro() const { return gnu_relro_; } 44 | 45 | const std::vector& neededs() const { return neededs_; } 46 | const std::string& soname() const { return soname_; } 47 | const std::string& runpath() const { return runpath_; } 48 | const std::string& rpath() const { return rpath_; } 49 | 50 | const Elf_Sym* symtab() const { return symtab_; } 51 | Elf_Sym* symtab_mut() const { return symtab_; } 52 | const Elf_Verneed* verneed() const { return verneed_; } 53 | Elf_Verneed* verneed_mut() const { return verneed_; } 54 | const Elf_Versym* versym() const { return versym_; } 55 | const Elf_Xword verneednum() const { return verneednum_; } 56 | const Elf_Rel* rel() const { return rel_; } 57 | size_t num_rels() const { return num_rels_; } 58 | const Elf_Rel* plt_rel() const { return plt_rel_; } 59 | size_t num_plt_rels() const { return num_plt_rels_; } 60 | const EHFrameHeader* eh_frame_header() const { return &eh_frame_header_; } 61 | const char* strtab() const { return strtab_; } 62 | 63 | const char* head() const { return head_; } 64 | char* head_mut() const { return head_; } 65 | size_t filesize() const { return filesize_; } 66 | size_t mapped_size() const { return mapped_size_; } 67 | 68 | const std::string& name() const { return name_; } 69 | 70 | uintptr_t init() const { return init_; } 71 | uintptr_t fini() const { return fini_; } 72 | const uintptr_t init_array_addr() const { return init_array_addr_; }; 73 | const uintptr_t fini_array_addr() const { return fini_array_addr_; }; 74 | const std::vector& init_array() const { return init_array_; } 75 | const std::vector& fini_array() const { return fini_array_; } 76 | 77 | const std::vector& GetSymbolMap() const { return syms_; } 78 | 79 | Range GetRange() const; 80 | 81 | bool IsAddrInInitarray(uintptr_t addr) const; 82 | bool IsAddrInFiniarray(uintptr_t addr) const; 83 | 84 | bool IsVaddrInTLSData(uintptr_t vaddr) const; 85 | bool IsOffsetInTLSData(uintptr_t offset) const; 86 | bool IsOffsetInTLSBSS(uintptr_t offset) const; 87 | 88 | std::set CollectSymbolsFromDynamic(); 89 | void ReadDynSymtab(const std::map& filename_to_soname); 90 | 91 | const char* Str(uintptr_t name) { return strtab_ + name; } 92 | 93 | char* GetPtr(uintptr_t offset) { return head_ + OffsetFromAddr(offset); } 94 | 95 | Elf_Phdr* FindPhdr(uint64_t type); 96 | 97 | const Elf_Phdr& GetPhdr(uint64_t type); 98 | 99 | void PrintVerneeds(); 100 | 101 | void PrintVersyms(); 102 | 103 | std::string ShowDynSymtab(); 104 | std::string ShowDtRela(); 105 | std::string ShowVersion(); 106 | std::string ShowTLS(); 107 | std::string ShowEHFrame(); 108 | 109 | std::pair GetVersion(int index, const std::map& filename_to_soname); 110 | 111 | Elf_Addr OffsetFromAddr(const Elf_Addr addr) const; 112 | Elf_Addr AddrFromOffset(const Elf_Addr offset) const; 113 | 114 | private: 115 | void ParsePhdrs(); 116 | void ParseEHFrameHeader(size_t off, size_t size); 117 | void ParseDynamic(size_t off, size_t size); 118 | void ParseFuncArray(uintptr_t* array, uintptr_t size, std::vector* out); 119 | 120 | const std::string filename_; 121 | int fd_; 122 | char* head_; 123 | size_t filesize_; 124 | size_t mapped_size_; 125 | 126 | Elf_Ehdr* ehdr_{nullptr}; 127 | std::vector phdrs_; 128 | std::vector loads_; 129 | Elf_Phdr* tls_{nullptr}; 130 | Elf_Phdr* gnu_stack_{nullptr}; 131 | Elf_Phdr* gnu_relro_{nullptr}; 132 | const char* strtab_{nullptr}; 133 | Elf_Sym* symtab_{nullptr}; 134 | 135 | EHFrameHeader eh_frame_header_; 136 | 137 | std::vector neededs_; 138 | // This is the name specified in the DT_SONAME field. 139 | std::string soname_; 140 | std::string runpath_; 141 | std::string rpath_; 142 | 143 | Elf_Rel* rel_{nullptr}; 144 | size_t num_rels_{0}; 145 | Elf_Rel* plt_rel_{nullptr}; 146 | size_t num_plt_rels_{0}; 147 | 148 | Elf_GnuHash* gnu_hash_{nullptr}; 149 | Elf_Hash* hash_{nullptr}; 150 | 151 | uintptr_t* init_array_offset_{0}; 152 | uintptr_t init_arraysz_{0}; 153 | uintptr_t init_array_addr_{0}; 154 | uintptr_t* fini_array_offset_{0}; 155 | uintptr_t fini_array_addr_{0}; 156 | uintptr_t fini_arraysz_{0}; 157 | 158 | uintptr_t init_{0}; 159 | uintptr_t fini_{0}; 160 | std::vector init_array_; 161 | std::vector fini_array_; 162 | 163 | // This is the name on the filsysytem 164 | std::string name_; 165 | std::vector syms_; 166 | 167 | int nsyms_{0}; 168 | 169 | Elf_Versym* versym_{nullptr}; 170 | Elf_Verneed* verneed_{nullptr}; 171 | Elf_Verdef* verdef_{nullptr}; 172 | Elf_Xword verneednum_{0}; 173 | Elf_Xword verdefnum_{0}; 174 | }; 175 | 176 | std::unique_ptr ReadELF(const std::string& filename); 177 | -------------------------------------------------------------------------------- /tools/raw_write.h: -------------------------------------------------------------------------------- 1 | // Copyright (C) 2010 by Shinichiro Hamaji 2 | // 3 | // Permission is hereby granted, free of charge, to any person obtaining a copy 4 | // of this software and associated documentation files (the "Software"), to deal 5 | // in the Software without restriction, including without limitation the rights 6 | // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 7 | // copies of the Software, and to permit persons to whom the Software is 8 | // furnished to do so, subject to the following conditions: 9 | // 10 | // The above copyright notice and this permission notice shall be included in 11 | // all copies or substantial portions of the Software. 12 | // 13 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 14 | // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 15 | // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 16 | // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 17 | // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 18 | // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 19 | // THE SOFTWARE. 20 | 21 | #include 22 | 23 | #if defined(__x86_64__) 24 | #define RAW_WRITE(fd, buf, count) \ 25 | do { \ 26 | register unsigned long RAW_rsi##__LINE__ __asm__("rsi") = (unsigned long)buf; \ 27 | __asm__ volatile("syscall;\n" \ 28 | : "+r"(RAW_rsi##__LINE__) \ 29 | : "a"(SYS_write), "D"(fd), "d"(count) \ 30 | : "r8", "r10", "rcx", "r11", "memory", "cc"); \ 31 | /* The input registers may be broken by syscall */ \ 32 | __asm__ volatile("" ::: "rax", "rdi", "rdx"); \ 33 | } while (0) 34 | #elif defined(__i386__) 35 | #define RAW_WRITE(fd, buf, count) \ 36 | do { \ 37 | __asm__ volatile("int $0x80;\n" ::"a"(SYS_write), "b"(fd), "c"(buf), "d"(count) : "memory", "cc"); \ 38 | /* The input registers may be broken by syscall */ \ 39 | __asm__ volatile("" ::: "eax", "ebx", "ecx", "edx"); \ 40 | } while (0) 41 | #elif defined(__arm__) 42 | #define RAW_WRITE(fd, buf, count) \ 43 | do { \ 44 | __asm__ volatile( \ 45 | "mov %%r0, %1;\n" \ 46 | "mov %%r1, %2;\n" \ 47 | "mov %%r2, %3;\n" \ 48 | "push {%%r7};\n" \ 49 | "mov %%r7, %0;\n" \ 50 | "swi 0x0;\n" \ 51 | "pop {%%r7};\n" ::"I"(SYS_write), \ 52 | "r"(fd), "r"(buf), "r"(count) \ 53 | : "memory", "cc", "r0", "r1", "r2"); \ 54 | } while (0) 55 | #else 56 | #error "RAW_WRITE isn't defined for this architecture" 57 | #endif 58 | 59 | #define RAW_PRINT_STR(buf) \ 60 | do { \ 61 | const char* RAW_p##__LINE__ = buf; \ 62 | int i; \ 63 | for (i = 0; RAW_p##__LINE__[i]; i++) { \ 64 | } \ 65 | RAW_WRITE(2, RAW_p##__LINE__, i); \ 66 | } while (0) 67 | 68 | #define RAW_PRINT_BASE_N(num, base) \ 69 | do { \ 70 | /* unsigned long long isn't supported */ \ 71 | long long RAW_n##__LINE__ = (long long)num; \ 72 | int RAW_b##__LINE__ = base; \ 73 | int was_minus = 0; \ 74 | char buf[21]; \ 75 | char* p = buf + 20; \ 76 | int l = 0; \ 77 | if (RAW_n##__LINE__ < 0) { \ 78 | was_minus = 1; \ 79 | RAW_n##__LINE__ = -RAW_n##__LINE__; \ 80 | } \ 81 | do { \ 82 | int v = RAW_n##__LINE__ % RAW_b##__LINE__; \ 83 | if (v > 9) \ 84 | *p = 'a' + v - 10; \ 85 | else \ 86 | *p = '0' + v; \ 87 | l++; \ 88 | RAW_n##__LINE__ /= RAW_b##__LINE__; \ 89 | p--; \ 90 | } while (RAW_n##__LINE__ != 0); \ 91 | if (was_minus) { \ 92 | *p = '-'; \ 93 | l++; \ 94 | } else { \ 95 | p++; \ 96 | } \ 97 | RAW_WRITE(2, p, l); \ 98 | } while (0) 99 | 100 | #define RAW_PRINT_HEX(num) RAW_PRINT_BASE_N(num, 16) 101 | #define RAW_PRINT_INT(num) RAW_PRINT_BASE_N(num, 10) 102 | #define RAW_PRINT_PTR(num) \ 103 | do { \ 104 | char buf[3] = "0x"; \ 105 | RAW_WRITE(2, buf, 2); \ 106 | RAW_PRINT_BASE_N((unsigned long)num, 16); \ 107 | } while (0) 108 | 109 | #define RAW_PRINT_NL_AFTER_SOMETHING(print) \ 110 | do { \ 111 | print; \ 112 | char buf[2] = "\n"; \ 113 | RAW_WRITE(2, buf, 1); \ 114 | } while (0) 115 | #define RAW_PUTS_STR(buf) RAW_PRINT_NL_AFTER_SOMETHING(RAW_PRINT_STR(buf)) 116 | #define RAW_PUTS_HEX(buf) RAW_PRINT_NL_AFTER_SOMETHING(RAW_PRINT_HEX(buf)) 117 | #define RAW_PUTS_INT(buf) RAW_PRINT_NL_AFTER_SOMETHING(RAW_PRINT_INT(buf)) 118 | #define RAW_PUTS_PTR(buf) RAW_PRINT_NL_AFTER_SOMETHING(RAW_PRINT_PTR(buf)) 119 | 120 | /* some more utilities for "printf" debug... */ 121 | #if defined(__arm__) 122 | #define RAW_BREAK() __asm__ volatile("bkpt;\n") 123 | #else 124 | #define RAW_BREAK() __asm__ volatile("int3;\n") 125 | #endif 126 | #define RAW_NOP() __asm__ volatile("nop;\n") 127 | /* you can easily find this code by grepping 4242 */ 128 | #if defined(__x86_64__) 129 | #define RAW_UNIQ_NOP() __asm__ volatile("nop 0x42424242(%rax);\n") 130 | #elif defined(__i386__) 131 | #define RAW_UNIQ_NOP() __asm__ volatile("nop 0x42424242(%eax);\n") 132 | #elif defined(__arm__) 133 | #define RAW_UNIQ_NOP() __asm__ volatile("nop;\n") 134 | #else 135 | #error "RAW_UNIQ_NOP isn't defined for this architecture" 136 | #endif 137 | --------------------------------------------------------------------------------