diff --git a/CMakeLists.txt b/CMakeLists.txt index 01a2ac0..4716306 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -28,7 +28,7 @@ if(NOT CMAKE_BUILD_TYPE AND NOT CMAKE_CONFIGURATION_TYPES) endif() add_compile_options(-fdata-sections -ffunction-sections -Wswitch-enum - -Werror=switch-enum -fPIC) + -Werror=switch-enum -fvisibility=hidden -fPIC) set(full_relro_flags "-pie;LINKER:-z,relro,-z,now,-z,noexecstack") cmake_push_check_state() @@ -60,7 +60,8 @@ set(CMAKE_CXX_IMPLICIT_LINK_LIBRARIES "") add_subdirectory(third_party) -add_executable(versioned_map_main VersionedMap.cpp RootSet.cpp) +add_executable(versioned_map_main VersionedMap.cpp RootSet.cpp + $) target_include_directories(versioned_map_main PRIVATE ${CMAKE_SOURCE_DIR}/include) target_link_libraries(versioned_map_main PRIVATE nanobench xxhash) @@ -71,11 +72,48 @@ if(CMAKE_BUILD_TYPE STREQUAL "Debug") target_link_options(versioned_map_main PRIVATE -fsanitize=address,undefined) endif() -add_library(versioned_map VersionedMap.cpp RootSet.cpp) -target_link_libraries(versioned_map PRIVATE xxhash) -target_compile_options(versioned_map PRIVATE -fno-exceptions) -target_include_directories(versioned_map PUBLIC ${CMAKE_SOURCE_DIR}/include) -set_target_properties(versioned_map PROPERTIES LINKER_LANGUAGE C) +add_library(${PROJECT_NAME}-object OBJECT VersionedMap.cpp RootSet.cpp) + +target_compile_options(${PROJECT_NAME}-object PRIVATE -fno-exceptions -fno-rtti) +target_include_directories(${PROJECT_NAME}-object + PRIVATE ${CMAKE_SOURCE_DIR}/include) +target_link_libraries(${PROJECT_NAME}-object PRIVATE xxhash) + +add_custom_command( + OUTPUT ${CMAKE_BINARY_DIR}/${PROJECT_NAME}.o + COMMAND ld -r $ + $ -o ${CMAKE_BINARY_DIR}/${PROJECT_NAME}.o + DEPENDS $ $ + COMMAND_EXPAND_LISTS) + +add_library(${PROJECT_NAME} SHARED ${CMAKE_BINARY_DIR}/${PROJECT_NAME}.o) +set_target_properties( + ${PROJECT_NAME} PROPERTIES LIBRARY_OUTPUT_DIRECTORY + "${CMAKE_BINARY_DIR}/versioned-map") +if(NOT CMAKE_BUILD_TYPE STREQUAL Debug) + set_target_properties(${PROJECT_NAME} PROPERTIES LINKER_LANGUAGE C) +endif() + +if(HAS_VERSION_SCRIPT) + target_link_options(${PROJECT_NAME} PRIVATE + LINKER:--version-script=${CMAKE_SOURCE_DIR}/linker.map) +endif() + +add_library(${PROJECT_NAME}-static STATIC ${CMAKE_BINARY_DIR}/${PROJECT_NAME}.o) +if(NOT CMAKE_BUILD_TYPE STREQUAL Debug) + set_target_properties(${PROJECT_NAME}-static PROPERTIES LINKER_LANGUAGE C) +endif() + +if(NOT APPLE) + add_custom_command( + TARGET ${PROJECT_NAME}-static + POST_BUILD + COMMAND + ${CMAKE_OBJCOPY} + --keep-global-symbols=${CMAKE_SOURCE_DIR}/symbol-exports.txt + $ || echo + "Proceeding with all symbols global in static library") +endif() include(CTest) @@ -101,4 +139,30 @@ if(BUILD_TESTING) target_compile_options(rootset_test_tsan PRIVATE -fsanitize=thread -UNDEBUG) target_link_options(rootset_test_tsan PRIVATE -fsanitize=thread) add_test(NAME rootset_test_tsan COMMAND rootset_test) + + # symbol visibility tests + if(NOT CMAKE_BUILD_TYPE STREQUAL Debug) + if(APPLE) + set(symbol_exports ${CMAKE_SOURCE_DIR}/apple-symbol-exports.txt) + set(symbol_imports ${CMAKE_SOURCE_DIR}/apple-symbol-imports.txt) + else() + set(symbol_exports ${CMAKE_SOURCE_DIR}/symbol-exports.txt) + if(CMAKE_SYSTEM_PROCESSOR STREQUAL aarch64) + set(symbol_imports ${CMAKE_SOURCE_DIR}/aarch64-symbol-imports.txt) + else() + set(symbol_imports ${CMAKE_SOURCE_DIR}/symbol-imports.txt) + endif() + endif() + add_test( + NAME shared_symbols + COMMAND + ${CMAKE_SOURCE_DIR}/test_symbols.sh $ + ${symbol_exports} ${symbol_imports}) + add_test( + NAME static_symbols + COMMAND + ${CMAKE_SOURCE_DIR}/test_symbols.sh + $ ${symbol_exports} + ${symbol_imports}) + endif() endif() diff --git a/VersionedMap.cpp b/VersionedMap.cpp index 25b7307..bba8dc6 100644 --- a/VersionedMap.cpp +++ b/VersionedMap.cpp @@ -460,7 +460,7 @@ private: int searchPathSize_; }; -struct VersionedMap::Impl { +struct __attribute__((__visibility__("hidden"))) VersionedMap::Impl { // The last node is allowed to be 0, in which case this is the search path of // where an entry would exist @@ -1174,13 +1174,13 @@ int64_t VersionedMap::getBytes() const { return impl->getBytes(); } // GCOVR_EXCL_START -void VersionedMap::Impl::printInOrder(int64_t version) { +inline void VersionedMap::Impl::printInOrder(int64_t version) { printInOrderHelper(version, roots.getThreadSafeHandle().rootForVersion(version), 0); } -void VersionedMap::Impl::printInOrderHelper(int64_t version, uint32_t node, - int depth) { +inline void VersionedMap::Impl::printInOrderHelper(int64_t version, + uint32_t node, int depth) { if (node == 0) { return; } diff --git a/aarch64-symbol-imports.txt b/aarch64-symbol-imports.txt new file mode 100644 index 0000000..99ab86c --- /dev/null +++ b/aarch64-symbol-imports.txt @@ -0,0 +1,8 @@ +__stack_chk_fail@GLIBC_2.17 +__stack_chk_guard@GLIBC_2.17 +abort@GLIBC_2.17 +free@GLIBC_2.17 +malloc@GLIBC_2.17 +memcpy@GLIBC_2.17 +memmove@GLIBC_2.17 +memset@GLIBC_2.17 \ No newline at end of file diff --git a/apple-symbol-exports.txt b/apple-symbol-exports.txt new file mode 100644 index 0000000..df81aad --- /dev/null +++ b/apple-symbol-exports.txt @@ -0,0 +1,31 @@ +__ZN8weaselab12VersionedMap12addMutationsEPKNS0_8MutationEix +__ZN8weaselab12VersionedMap16setOldestVersionEx +__ZN8weaselab12VersionedMap8IteratorC1EOS1_ +__ZN8weaselab12VersionedMap8IteratorC1ERKS1_ +__ZN8weaselab12VersionedMap8IteratorC2EOS1_ +__ZN8weaselab12VersionedMap8IteratorC2ERKS1_ +__ZN8weaselab12VersionedMap8IteratorD1Ev +__ZN8weaselab12VersionedMap8IteratorD2Ev +__ZN8weaselab12VersionedMap8IteratoraSEOS1_ +__ZN8weaselab12VersionedMap8IteratoraSERKS1_ +__ZN8weaselab12VersionedMap8IteratormmEi +__ZN8weaselab12VersionedMap8IteratormmEv +__ZN8weaselab12VersionedMap8IteratorppEi +__ZN8weaselab12VersionedMap8IteratorppEv +__ZN8weaselab12VersionedMapC1EOS0_ +__ZN8weaselab12VersionedMapC1Ex +__ZN8weaselab12VersionedMapC2EOS0_ +__ZN8weaselab12VersionedMapC2Ex +__ZN8weaselab12VersionedMapD1Ev +__ZN8weaselab12VersionedMapD2Ev +__ZN8weaselab12VersionedMapaSEOS0_ +__ZNK8weaselab12VersionedMap10getVersionEv +__ZNK8weaselab12VersionedMap16getOldestVersionEv +__ZNK8weaselab12VersionedMap3endEx +__ZNK8weaselab12VersionedMap5beginEx +__ZNK8weaselab12VersionedMap8Iterator3cmpEv +__ZNK8weaselab12VersionedMap8IteratordeEv +__ZNK8weaselab12VersionedMap8IteratoreqERKS1_ +__ZNK8weaselab12VersionedMap8IteratorneERKS1_ +__ZNK8weaselab12VersionedMap8firstGeqEPKNS0_3KeyEPKxPNS0_8IteratorEi +__ZNK8weaselab12VersionedMap8getBytesEv \ No newline at end of file diff --git a/apple-symbol-imports.txt b/apple-symbol-imports.txt new file mode 100644 index 0000000..e804ffd --- /dev/null +++ b/apple-symbol-imports.txt @@ -0,0 +1,21 @@ +___error +___memcpy_chk +___stack_chk_fail +___stack_chk_guard +___stderrp +__tlv_bootstrap +_abort +_bzero +_calloc +_fflush +_fprintf +_free +_fwrite +_malloc +_memcmp +_memcpy +_mmap +_mprotect +_munmap +_strerror +_sysconf \ No newline at end of file diff --git a/include/VersionedMap.h b/include/VersionedMap.h index a5930f3..5a92508 100644 --- a/include/VersionedMap.h +++ b/include/VersionedMap.h @@ -37,7 +37,7 @@ namespace weaselab { * - Methods that make stronger guarantees about the safety of calling * concurrently with non-const methods are documented as such. */ -struct VersionedMap { +struct __attribute__((__visibility__("default"))) VersionedMap { /** Indicates how `Mutation::param1` and `Mutation::param2` are to be * interpreted. */ diff --git a/linker.map b/linker.map new file mode 100644 index 0000000..3691443 --- /dev/null +++ b/linker.map @@ -0,0 +1,6 @@ +{ + global: + *ConflictSet*; + local: + *; +}; \ No newline at end of file diff --git a/symbol-exports.txt b/symbol-exports.txt new file mode 100644 index 0000000..42c0562 --- /dev/null +++ b/symbol-exports.txt @@ -0,0 +1,17 @@ +ConflictSet_addWrites +ConflictSet_check +ConflictSet_create +ConflictSet_destroy +ConflictSet_getBytes +ConflictSet_setOldestVersion +_ZN8weaselab11ConflictSet16setOldestVersionEl +_ZN8weaselab11ConflictSet9addWritesEPKNS0_10WriteRangeEil +_ZN8weaselab11ConflictSetaSEOS0_ +_ZN8weaselab11ConflictSetC1El +_ZN8weaselab11ConflictSetC1EOS0_ +_ZN8weaselab11ConflictSetC2El +_ZN8weaselab11ConflictSetC2EOS0_ +_ZN8weaselab11ConflictSetD1Ev +_ZN8weaselab11ConflictSetD2Ev +_ZNK8weaselab11ConflictSet5checkEPKNS0_9ReadRangeEPNS0_6ResultEi +_ZNK8weaselab11ConflictSet8getBytesEv diff --git a/symbol-imports.txt b/symbol-imports.txt new file mode 100644 index 0000000..bbed523 --- /dev/null +++ b/symbol-imports.txt @@ -0,0 +1,9 @@ +_GLOBAL_OFFSET_TABLE_ +__stack_chk_fail@GLIBC_2.4 +__tls_get_addr@GLIBC_2.3 +abort@GLIBC_2.2.5 +free@GLIBC_2.2.5 +malloc@GLIBC_2.2.5 +memcpy@GLIBC_2.14 +memmove@GLIBC_2.2.5 +memset@GLIBC_2.2.5 diff --git a/test_symbols.sh b/test_symbols.sh new file mode 100755 index 0000000..f6c41e3 --- /dev/null +++ b/test_symbols.sh @@ -0,0 +1,16 @@ +#!/bin/bash + +set -euo pipefail + +# ./test_symbols.sh + +diff -u <(sort < "$2") <(nm "$1" | grep " T " | cut -f3 -d " " | sort) +ec=0 +for symbol in $(nm "$1" | grep " U " | sed 's/ U //') ; do + if ! grep --fixed-strings "$symbol" "$3" > /dev/null ; then + echo "Imported symbol $symbol not present in $3" + ec=1 + fi +done + +exit $ec \ No newline at end of file diff --git a/third_party/CMakeLists.txt b/third_party/CMakeLists.txt index 18db6e2..0e62fe7 100644 --- a/third_party/CMakeLists.txt +++ b/third_party/CMakeLists.txt @@ -2,6 +2,6 @@ add_library(nanobench ${CMAKE_CURRENT_SOURCE_DIR}/nanobench.cpp) target_include_directories(nanobench SYSTEM PUBLIC ${CMAKE_CURRENT_SOURCE_DIR}/include/nanobench) -add_library(xxhash ${CMAKE_CURRENT_SOURCE_DIR}/xxhash.c) +add_library(xxhash OBJECT ${CMAKE_CURRENT_SOURCE_DIR}/xxhash.c) target_include_directories(xxhash SYSTEM PUBLIC ${CMAKE_CURRENT_SOURCE_DIR}/include/xxhash)