diff --git a/debuginfo-tests/nrvo-string.cpp b/debuginfo-tests/nrvo-string.cpp index ba8d9d42f6f404..de89056fc84649 100644 --- a/debuginfo-tests/nrvo-string.cpp +++ b/debuginfo-tests/nrvo-string.cpp @@ -7,8 +7,7 @@ // RUN: %test_debuginfo %s %t.out // // PR34513 -volatile int sideeffect = 0; -void __attribute__((noinline)) stop() { sideeffect++; } +void __attribute__((noinline)) stop() {} struct string { string() {} @@ -19,7 +18,7 @@ struct string { string get_string() { string unused; string result = 3; - // DEBUGGER: break 23 + // DEBUGGER: break 22 stop(); return result; } @@ -35,7 +34,7 @@ string2 get_string2() { some_function(result.i); // Test that the debugger can get the value of result after another // function is called. - // DEBUGGER: break 39 + // DEBUGGER: break 38 stop(); return result; } diff --git a/libcxxabi/CMakeLists.txt b/libcxxabi/CMakeLists.txt index 8ca169065f48e9..e1977278fc8be9 100644 --- a/libcxxabi/CMakeLists.txt +++ b/libcxxabi/CMakeLists.txt @@ -43,9 +43,7 @@ include(CMakeDependentOption) include(HandleCompilerRT) # Define options. -option(LIBCXXABI_ENABLE_EXCEPTIONS - "Provide support for exceptions in the runtime. - When disabled, libc++abi does not support stack unwinding and other exceptions-related features." ON) +option(LIBCXXABI_ENABLE_EXCEPTIONS "Use exceptions." ON) option(LIBCXXABI_ENABLE_ASSERTIONS "Enable assertions independent of build mode." ON) option(LIBCXXABI_ENABLE_PEDANTIC "Compile with pedantic enabled." ON) option(LIBCXXABI_ENABLE_PIC "Build Position-Independent Code, even in static library" ON) diff --git a/libcxxabi/cmake/Modules/HandleOutOfTreeLLVM.cmake b/libcxxabi/cmake/Modules/HandleOutOfTreeLLVM.cmake index c43308ee8aa4f2..4420aca2a14a13 100644 --- a/libcxxabi/cmake/Modules/HandleOutOfTreeLLVM.cmake +++ b/libcxxabi/cmake/Modules/HandleOutOfTreeLLVM.cmake @@ -9,9 +9,6 @@ macro(find_llvm_parts) set(LLVM_PATH ${LLVM_PATH} CACHE PATH "Path to LLVM source tree") set(LLVM_MAIN_SRC_DIR ${LLVM_PATH}) set(LLVM_CMAKE_PATH "${LLVM_PATH}/cmake/modules") - if (NOT IS_DIRECTORY "${LLVM_PATH}") - message(FATAL_ERROR "The provided LLVM_PATH (${LLVM_PATH}) is not a valid directory") - endif() elseif(LLVM_CONFIG_PATH) message(STATUS "Found LLVM_CONFIG_PATH as ${LLVM_CONFIG_PATH}") set(LIBCXXABI_USING_INSTALLED_LLVM 1) diff --git a/libcxxabi/include/__cxxabi_config.h b/libcxxabi/include/__cxxabi_config.h index cbbb1c10c1a29d..1e0edcab88e25b 100644 --- a/libcxxabi/include/__cxxabi_config.h +++ b/libcxxabi/include/__cxxabi_config.h @@ -71,8 +71,7 @@ #define _LIBCXXABI_NO_CFI #endif -// wasm32 follows the arm32 ABI convention of using 32-bit guard. -#if defined(__arm__) || defined(__wasm32__) +#if defined(__arm__) # define _LIBCXXABI_GUARD_ABI_ARM #endif diff --git a/libcxxabi/lib/itanium-base.exp b/libcxxabi/lib/itanium-base.exp deleted file mode 100644 index ff0f8128a95c42..00000000000000 --- a/libcxxabi/lib/itanium-base.exp +++ /dev/null @@ -1,373 +0,0 @@ -# Typeinfos for fundamental types -__ZTIa -__ZTIb -__ZTIc -__ZTId -__ZTIDh -__ZTIDi -__ZTIDn -__ZTIDs -__ZTIDu -__ZTIe -__ZTIf -__ZTIg -__ZTIh -__ZTIi -__ZTIj -__ZTIl -__ZTIm -__ZTIn -__ZTIo -__ZTIPa -__ZTIPb -__ZTIPc -__ZTIPd -__ZTIPDh -__ZTIPDi -__ZTIPDn -__ZTIPDs -__ZTIPDu -__ZTIPe -__ZTIPf -__ZTIPg -__ZTIPh -__ZTIPi -__ZTIPj -__ZTIPKa -__ZTIPKb -__ZTIPKc -__ZTIPKd -__ZTIPKDh -__ZTIPKDi -__ZTIPKDn -__ZTIPKDs -__ZTIPKDu -__ZTIPKe -__ZTIPKf -__ZTIPKg -__ZTIPKh -__ZTIPKi -__ZTIPKj -__ZTIPKl -__ZTIPKm -__ZTIPKn -__ZTIPKo -__ZTIPKs -__ZTIPKt -__ZTIPKv -__ZTIPKw -__ZTIPKx -__ZTIPKy -__ZTIPl -__ZTIPm -__ZTIPn -__ZTIPo -__ZTIPs -__ZTIPt -__ZTIPv -__ZTIPw -__ZTIPx -__ZTIPy -__ZTIs -__ZTIt -__ZTIv -__ZTIw -__ZTIx -__ZTIy - -# Typeinfo names for fundamental types -__ZTSa -__ZTSb -__ZTSc -__ZTSd -__ZTSDh -__ZTSDi -__ZTSDn -__ZTSDs -__ZTSDu -__ZTSe -__ZTSf -__ZTSg -__ZTSh -__ZTSi -__ZTSj -__ZTSl -__ZTSm -__ZTSn -__ZTSo -__ZTSPa -__ZTSPb -__ZTSPc -__ZTSPd -__ZTSPDh -__ZTSPDi -__ZTSPDn -__ZTSPDs -__ZTSPDu -__ZTSPe -__ZTSPf -__ZTSPg -__ZTSPh -__ZTSPi -__ZTSPj -__ZTSPKa -__ZTSPKb -__ZTSPKc -__ZTSPKd -__ZTSPKDh -__ZTSPKDi -__ZTSPKDn -__ZTSPKDs -__ZTSPKDu -__ZTSPKe -__ZTSPKf -__ZTSPKg -__ZTSPKh -__ZTSPKi -__ZTSPKj -__ZTSPKl -__ZTSPKm -__ZTSPKn -__ZTSPKo -__ZTSPKs -__ZTSPKt -__ZTSPKv -__ZTSPKw -__ZTSPKx -__ZTSPKy -__ZTSPl -__ZTSPm -__ZTSPn -__ZTSPo -__ZTSPs -__ZTSPt -__ZTSPv -__ZTSPw -__ZTSPx -__ZTSPy -__ZTSs -__ZTSt -__ZTSv -__ZTSw -__ZTSx -__ZTSy - -# Typeinfos for types from libc++abi -__ZTIN10__cxxabiv116__enum_type_infoE -__ZTIN10__cxxabiv116__shim_type_infoE -__ZTIN10__cxxabiv117__array_type_infoE -__ZTIN10__cxxabiv117__class_type_infoE -__ZTIN10__cxxabiv117__pbase_type_infoE -__ZTIN10__cxxabiv119__pointer_type_infoE -__ZTIN10__cxxabiv120__function_type_infoE -__ZTIN10__cxxabiv120__si_class_type_infoE -__ZTIN10__cxxabiv121__vmi_class_type_infoE -__ZTIN10__cxxabiv123__fundamental_type_infoE -__ZTIN10__cxxabiv129__pointer_to_member_type_infoE - -# Typeinfo names for types from libc++abi -__ZTSN10__cxxabiv116__enum_type_infoE -__ZTSN10__cxxabiv116__shim_type_infoE -__ZTSN10__cxxabiv117__array_type_infoE -__ZTSN10__cxxabiv117__class_type_infoE -__ZTSN10__cxxabiv117__pbase_type_infoE -__ZTSN10__cxxabiv119__pointer_type_infoE -__ZTSN10__cxxabiv120__function_type_infoE -__ZTSN10__cxxabiv120__si_class_type_infoE -__ZTSN10__cxxabiv121__vmi_class_type_infoE -__ZTSN10__cxxabiv123__fundamental_type_infoE -__ZTSN10__cxxabiv129__pointer_to_member_type_infoE - -# Typeinfos for std:: exception types -__ZTISt10bad_typeid -__ZTISt11logic_error -__ZTISt11range_error -__ZTISt12domain_error -__ZTISt12length_error -__ZTISt12out_of_range -__ZTISt13bad_exception -__ZTISt13runtime_error -__ZTISt14overflow_error -__ZTISt15underflow_error -__ZTISt16invalid_argument -__ZTISt20bad_array_new_length -__ZTISt8bad_cast -__ZTISt9bad_alloc -__ZTISt9exception -__ZTISt9type_info - -# Typeinfo names for std:: exception types -__ZTSSt10bad_typeid -__ZTSSt11logic_error -__ZTSSt11range_error -__ZTSSt12domain_error -__ZTSSt12length_error -__ZTSSt12out_of_range -__ZTSSt13bad_exception -__ZTSSt13runtime_error -__ZTSSt14overflow_error -__ZTSSt15underflow_error -__ZTSSt16invalid_argument -__ZTSSt20bad_array_new_length -__ZTSSt8bad_cast -__ZTSSt9bad_alloc -__ZTSSt9exception -__ZTSSt9type_info - -# Vtables for libc++abi types -__ZTVN10__cxxabiv116__enum_type_infoE -__ZTVN10__cxxabiv116__shim_type_infoE -__ZTVN10__cxxabiv117__array_type_infoE -__ZTVN10__cxxabiv117__class_type_infoE -__ZTVN10__cxxabiv117__pbase_type_infoE -__ZTVN10__cxxabiv119__pointer_type_infoE -__ZTVN10__cxxabiv120__function_type_infoE -__ZTVN10__cxxabiv120__si_class_type_infoE -__ZTVN10__cxxabiv121__vmi_class_type_infoE -__ZTVN10__cxxabiv123__fundamental_type_infoE -__ZTVN10__cxxabiv129__pointer_to_member_type_infoE - -# Vtables for std:: exception types -__ZTVSt10bad_typeid -__ZTVSt11logic_error -__ZTVSt11range_error -__ZTVSt12domain_error -__ZTVSt12length_error -__ZTVSt12out_of_range -__ZTVSt13bad_exception -__ZTVSt13runtime_error -__ZTVSt14overflow_error -__ZTVSt15underflow_error -__ZTVSt16invalid_argument -__ZTVSt20bad_array_new_length -__ZTVSt8bad_cast -__ZTVSt9bad_alloc -__ZTVSt9exception -__ZTVSt9type_info - -# Itanium C++ ABI requirements -___cxa_allocate_dependent_exception -___cxa_allocate_exception -___cxa_bad_cast -___cxa_bad_typeid -___cxa_begin_catch -___cxa_call_unexpected -___cxa_current_exception_type -___cxa_current_primary_exception -___cxa_decrement_exception_refcount -___cxa_deleted_virtual -___cxa_demangle -___cxa_end_catch -___cxa_free_dependent_exception -___cxa_free_exception -___cxa_get_exception_ptr -___cxa_get_globals -___cxa_get_globals_fast -___cxa_guard_abort -___cxa_guard_acquire -___cxa_guard_release -___cxa_increment_exception_refcount -___cxa_pure_virtual -___cxa_rethrow -___cxa_rethrow_primary_exception -___cxa_throw -___cxa_throw_bad_array_new_length -___cxa_uncaught_exception -___cxa_uncaught_exceptions -___cxa_vec_cctor -___cxa_vec_cleanup -___cxa_vec_ctor -___cxa_vec_delete -___cxa_vec_delete2 -___cxa_vec_delete3 -___cxa_vec_dtor -___cxa_vec_new -___cxa_vec_new2 -___cxa_vec_new3 -___dynamic_cast -___cxa_terminate_handler -___cxa_unexpected_handler -___cxa_new_handler - -# ::what() functions for std:: exception types -__ZNKSt10bad_typeid4whatEv -__ZNKSt11logic_error4whatEv -__ZNKSt13bad_exception4whatEv -__ZNKSt13runtime_error4whatEv -__ZNKSt20bad_array_new_length4whatEv -__ZNKSt8bad_cast4whatEv -__ZNKSt9bad_alloc4whatEv -__ZNKSt9exception4whatEv - -# Default constructors and destructors for std:: exception types -__ZNSt10bad_typeidC1Ev -__ZNSt10bad_typeidC2Ev -__ZNSt10bad_typeidD0Ev -__ZNSt10bad_typeidD1Ev -__ZNSt10bad_typeidD2Ev -__ZNSt11logic_errorD0Ev -__ZNSt11logic_errorD1Ev -__ZNSt11logic_errorD2Ev -__ZNSt11range_errorD0Ev -__ZNSt11range_errorD1Ev -__ZNSt11range_errorD2Ev -__ZNSt12domain_errorD0Ev -__ZNSt12domain_errorD1Ev -__ZNSt12domain_errorD2Ev -__ZNSt12length_errorD0Ev -__ZNSt12length_errorD1Ev -__ZNSt12length_errorD2Ev -__ZNSt12out_of_rangeD0Ev -__ZNSt12out_of_rangeD1Ev -__ZNSt12out_of_rangeD2Ev -__ZNSt13bad_exceptionD0Ev -__ZNSt13bad_exceptionD1Ev -__ZNSt13bad_exceptionD2Ev -__ZNSt13runtime_errorD0Ev -__ZNSt13runtime_errorD1Ev -__ZNSt13runtime_errorD2Ev -__ZNSt14overflow_errorD0Ev -__ZNSt14overflow_errorD1Ev -__ZNSt14overflow_errorD2Ev -__ZNSt15underflow_errorD0Ev -__ZNSt15underflow_errorD1Ev -__ZNSt15underflow_errorD2Ev -__ZNSt16invalid_argumentD0Ev -__ZNSt16invalid_argumentD1Ev -__ZNSt16invalid_argumentD2Ev -__ZNSt20bad_array_new_lengthC1Ev -__ZNSt20bad_array_new_lengthC2Ev -__ZNSt20bad_array_new_lengthD0Ev -__ZNSt20bad_array_new_lengthD1Ev -__ZNSt20bad_array_new_lengthD2Ev -__ZNSt8bad_castC1Ev -__ZNSt8bad_castC2Ev -__ZNSt8bad_castD0Ev -__ZNSt8bad_castD1Ev -__ZNSt8bad_castD2Ev -__ZNSt9bad_allocC1Ev -__ZNSt9bad_allocC2Ev -__ZNSt9bad_allocD0Ev -__ZNSt9bad_allocD1Ev -__ZNSt9bad_allocD2Ev -__ZNSt9exceptionD0Ev -__ZNSt9exceptionD1Ev -__ZNSt9exceptionD2Ev -__ZNSt9type_infoD0Ev -__ZNSt9type_infoD1Ev -__ZNSt9type_infoD2Ev - -# Other std:: functions implemented in libc++abi -__ZSt10unexpectedv -__ZSt13get_terminatev -__ZSt13set_terminatePFvvE -__ZSt14get_unexpectedv -__ZSt14set_unexpectedPFvvE -__ZSt15get_new_handlerv -__ZSt15set_new_handlerPFvvE -__ZSt9terminatev - -# Misc -__ZN10__cxxabiv119__getExceptionClassEPK17_Unwind_Exception -__ZN10__cxxabiv119__setExceptionClassEP17_Unwind_Exceptiony -__ZN10__cxxabiv121__isOurExceptionClassEPK17_Unwind_Exception diff --git a/libcxxabi/lib/new-delete.exp b/libcxxabi/lib/new-delete.exp deleted file mode 100644 index 086d2fec24ea74..00000000000000 --- a/libcxxabi/lib/new-delete.exp +++ /dev/null @@ -1,20 +0,0 @@ -__Znwm -__ZnwmRKSt9nothrow_t -__ZnwmSt11align_val_t -__ZnwmSt11align_val_tRKSt9nothrow_t -__ZdaPv -__ZdaPvm -__ZdaPvmSt11align_val_t -__ZdaPvRKSt9nothrow_t -__ZdaPvSt11align_val_t -__ZdaPvSt11align_val_tRKSt9nothrow_t -__ZdlPv -__ZdlPvm -__ZdlPvmSt11align_val_t -__ZdlPvRKSt9nothrow_t -__ZdlPvSt11align_val_t -__ZdlPvSt11align_val_tRKSt9nothrow_t -__Znam -__ZnamRKSt9nothrow_t -__ZnamSt11align_val_t -__ZnamSt11align_val_tRKSt9nothrow_t diff --git a/libcxxabi/lib/personality-sjlj.exp b/libcxxabi/lib/personality-sjlj.exp deleted file mode 100644 index be0bfac668e29e..00000000000000 --- a/libcxxabi/lib/personality-sjlj.exp +++ /dev/null @@ -1 +0,0 @@ -___gxx_personality_sj0 diff --git a/libcxxabi/lib/personality-v0.exp b/libcxxabi/lib/personality-v0.exp deleted file mode 100644 index 610e4e3568dc1d..00000000000000 --- a/libcxxabi/lib/personality-v0.exp +++ /dev/null @@ -1 +0,0 @@ -___gxx_personality_v0 diff --git a/libcxxabi/src/CMakeLists.txt b/libcxxabi/src/CMakeLists.txt index 6b8f76b1a39f07..77f00987097f87 100644 --- a/libcxxabi/src/CMakeLists.txt +++ b/libcxxabi/src/CMakeLists.txt @@ -147,16 +147,6 @@ if (LLVM_ENABLE_MODULES) string(REPLACE "-Wl,-z,defs" "" CMAKE_SHARED_LINKER_FLAGS "${CMAKE_SHARED_LINKER_FLAGS}") endif() -if (NOT TARGET pstl::ParallelSTL) - message(STATUS "Could not find ParallelSTL, libc++abi will not attempt to use it but the build may fail if the libc++ in use needs it to be available.") -endif() - -if ("${CMAKE_OSX_ARCHITECTURES}" MATCHES "^(armv6|armv7|armv7s)$") - set(LIBCXXABI_USE_SJLJ_EXCEPTIONS ON) -else() - set(LIBCXXABI_USE_SJLJ_EXCEPTIONS OFF) -endif() - # Build the shared library. if (LIBCXXABI_ENABLE_SHARED) add_library(cxxabi_shared SHARED ${LIBCXXABI_SOURCES} ${LIBCXXABI_HEADERS}) @@ -164,9 +154,6 @@ if (LIBCXXABI_ENABLE_SHARED) llvm_setup_rpath(cxxabi_shared) endif() target_link_libraries(cxxabi_shared PRIVATE ${LIBCXXABI_SHARED_LIBRARIES} ${LIBCXXABI_LIBRARIES}) - if (TARGET pstl::ParallelSTL) - target_link_libraries(cxxabi_shared PUBLIC pstl::ParallelSTL) - endif() set_target_properties(cxxabi_shared PROPERTIES CXX_EXTENSIONS @@ -194,30 +181,12 @@ if (LIBCXXABI_ENABLE_SHARED) if (LIBCXXABI_INSTALL_SHARED_LIBRARY) list(APPEND LIBCXXABI_INSTALL_TARGETS "cxxabi_shared") endif() - - # -exported_symbols_list is only available on Apple platforms - if (APPLE) - target_link_libraries(cxxabi_shared PRIVATE "-Wl,-exported_symbols_list,${CMAKE_CURRENT_SOURCE_DIR}/../lib/itanium-base.exp") - - if (LIBCXXABI_ENABLE_NEW_DELETE_DEFINITIONS) - target_link_libraries(cxxabi_shared PRIVATE "-Wl,-exported_symbols_list,${CMAKE_CURRENT_SOURCE_DIR}/../lib/new-delete.exp") - endif() - - if (LIBCXXABI_USE_SJLJ_EXCEPTIONS) - target_link_libraries(cxxabi_shared PRIVATE "-Wl,-exported_symbols_list,${CMAKE_CURRENT_SOURCE_DIR}/../lib/personality-sjlj.exp") - else() - target_link_libraries(cxxabi_shared PRIVATE "-Wl,-exported_symbols_list,${CMAKE_CURRENT_SOURCE_DIR}/../lib/personality-v0.exp") - endif() - endif() endif() # Build the static library. if (LIBCXXABI_ENABLE_STATIC) add_library(cxxabi_static STATIC ${LIBCXXABI_SOURCES} ${LIBCXXABI_HEADERS}) target_link_libraries(cxxabi_static PRIVATE ${LIBCXXABI_STATIC_LIBRARIES} ${LIBCXXABI_LIBRARIES}) - if (TARGET pstl::ParallelSTL) - target_link_libraries(cxxabi_static PUBLIC pstl::ParallelSTL) - endif() set_target_properties(cxxabi_static PROPERTIES CXX_EXTENSIONS diff --git a/libcxxabi/src/cxa_default_handlers.cpp b/libcxxabi/src/cxa_default_handlers.cpp index 91a63f537662e6..8110f6c1403f74 100644 --- a/libcxxabi/src/cxa_default_handlers.cpp +++ b/libcxxabi/src/cxa_default_handlers.cpp @@ -14,8 +14,8 @@ #include #include "abort_message.h" #include "cxxabi.h" -#include "cxa_handlers.h" -#include "cxa_exception.h" +#include "cxa_handlers.hpp" +#include "cxa_exception.hpp" #include "private_typeinfo.h" #include "include/atomic_support.h" @@ -25,7 +25,6 @@ static const char* cause = "uncaught"; __attribute__((noreturn)) static void demangling_terminate_handler() { -#ifndef _LIBCXXABI_NO_EXCEPTIONS // If there might be an uncaught exception using namespace __cxxabiv1; __cxa_eh_globals* globals = __cxa_get_globals_fast(); @@ -72,7 +71,6 @@ static void demangling_terminate_handler() abort_message("terminating with %s foreign exception", cause); } } -#endif // Else just note that we're terminating abort_message("terminating"); } diff --git a/libcxxabi/src/cxa_exception.cpp b/libcxxabi/src/cxa_exception.cpp index 688ba1ef74d578..27f040380fd83f 100644 --- a/libcxxabi/src/cxa_exception.cpp +++ b/libcxxabi/src/cxa_exception.cpp @@ -14,8 +14,8 @@ #include // for std::terminate #include // for memset -#include "cxa_exception.h" -#include "cxa_handlers.h" +#include "cxa_exception.hpp" +#include "cxa_handlers.hpp" #include "fallback_malloc.h" #include "include/atomic_support.h" diff --git a/libcxxabi/src/cxa_exception.h b/libcxxabi/src/cxa_exception.hpp similarity index 98% rename from libcxxabi/src/cxa_exception.h rename to libcxxabi/src/cxa_exception.hpp index d24b80a38c44aa..95b859ea4f285d 100644 --- a/libcxxabi/src/cxa_exception.h +++ b/libcxxabi/src/cxa_exception.hpp @@ -1,4 +1,4 @@ -//===------------------------- cxa_exception.h ----------------------------===// +//===------------------------- cxa_exception.hpp --------------------------===// // // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. // See https://llvm.org/LICENSE.txt for license information. diff --git a/libcxxabi/src/cxa_exception_storage.cpp b/libcxxabi/src/cxa_exception_storage.cpp index dea670203c1dfa..81ba5f0207ad1c 100644 --- a/libcxxabi/src/cxa_exception_storage.cpp +++ b/libcxxabi/src/cxa_exception_storage.cpp @@ -10,7 +10,7 @@ // //===----------------------------------------------------------------------===// -#include "cxa_exception.h" +#include "cxa_exception.hpp" #include <__threading_support> @@ -46,7 +46,7 @@ extern "C" { #include "abort_message.h" #include "fallback_malloc.h" -#if defined(__unix__) && !defined(__ANDROID__) && defined(__ELF__) && defined(_LIBCXXABI_HAS_COMMENT_LIB_PRAGMA) +#if defined(__unix__) && defined(__ELF__) && defined(_LIBCXXABI_HAS_COMMENT_LIB_PRAGMA) #pragma comment(lib, "pthread") #endif diff --git a/libcxxabi/src/cxa_guard_impl.h b/libcxxabi/src/cxa_guard_impl.h index 98e42ba2fb0b03..935ba80d85c7df 100644 --- a/libcxxabi/src/cxa_guard_impl.h +++ b/libcxxabi/src/cxa_guard_impl.h @@ -50,7 +50,7 @@ #include #include <__threading_support> #ifndef _LIBCXXABI_HAS_NO_THREADS -#if defined(__unix__) && !defined(__ANDROID__) && defined(__ELF__) && defined(_LIBCXXABI_HAS_COMMENT_LIB_PRAGMA) +#if defined(__unix__) && defined(__ELF__) && defined(_LIBCXXABI_HAS_COMMENT_LIB_PRAGMA) #pragma comment(lib, "pthread") #endif #endif @@ -175,7 +175,7 @@ struct GuardObject { /// Implements __cxa_guard_acquire AcquireResult cxa_guard_acquire() { AtomicInt guard_byte(guard_byte_address); - if (guard_byte.load(std::_AO_Acquire) != UNSET) + if (guard_byte.load(std::_AO_Acquire) == COMPLETE_BIT) return INIT_IS_DONE; return derived()->acquire_init_byte(); } diff --git a/libcxxabi/src/cxa_handlers.cpp b/libcxxabi/src/cxa_handlers.cpp index f520a4db6edacd..390bc6564cbdbc 100644 --- a/libcxxabi/src/cxa_handlers.cpp +++ b/libcxxabi/src/cxa_handlers.cpp @@ -14,8 +14,8 @@ #include #include "abort_message.h" #include "cxxabi.h" -#include "cxa_handlers.h" -#include "cxa_exception.h" +#include "cxa_handlers.hpp" +#include "cxa_exception.hpp" #include "private_typeinfo.h" #include "include/atomic_support.h" @@ -73,7 +73,6 @@ __attribute__((noreturn)) void terminate() _NOEXCEPT { -#ifndef _LIBCXXABI_NO_EXCEPTIONS // If there might be an uncaught exception using namespace __cxxabiv1; __cxa_eh_globals* globals = __cxa_get_globals_fast(); @@ -88,7 +87,6 @@ terminate() _NOEXCEPT __terminate(exception_header->terminateHandler); } } -#endif __terminate(get_terminate()); } diff --git a/libcxxabi/src/cxa_handlers.h b/libcxxabi/src/cxa_handlers.hpp similarity index 95% rename from libcxxabi/src/cxa_handlers.h rename to libcxxabi/src/cxa_handlers.hpp index c8e2e44aee1f05..f87f49dce22e4c 100644 --- a/libcxxabi/src/cxa_handlers.h +++ b/libcxxabi/src/cxa_handlers.hpp @@ -1,4 +1,4 @@ -//===------------------------- cxa_handlers.h -----------------------------===// +//===------------------------- cxa_handlers.cpp ---------------------------===// // // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. // See https://llvm.org/LICENSE.txt for license information. diff --git a/libcxxabi/src/cxa_noexception.cpp b/libcxxabi/src/cxa_noexception.cpp index 2182c70d0bcd68..c32ebb0d1e6154 100644 --- a/libcxxabi/src/cxa_noexception.cpp +++ b/libcxxabi/src/cxa_noexception.cpp @@ -15,8 +15,8 @@ #include "cxxabi.h" #include // for std::terminate -#include "cxa_exception.h" -#include "cxa_handlers.h" +#include "cxa_exception.hpp" +#include "cxa_handlers.hpp" namespace __cxxabiv1 { diff --git a/libcxxabi/src/cxa_personality.cpp b/libcxxabi/src/cxa_personality.cpp index f140b7443fb83a..9dded404269e9f 100644 --- a/libcxxabi/src/cxa_personality.cpp +++ b/libcxxabi/src/cxa_personality.cpp @@ -17,8 +17,8 @@ #include #include "__cxxabi_config.h" -#include "cxa_exception.h" -#include "cxa_handlers.h" +#include "cxa_exception.hpp" +#include "cxa_handlers.hpp" #include "private_typeinfo.h" #include "unwind.h" diff --git a/libcxxabi/src/cxa_thread_atexit.cpp b/libcxxabi/src/cxa_thread_atexit.cpp index 392403bd047cef..3b60c2919f445d 100644 --- a/libcxxabi/src/cxa_thread_atexit.cpp +++ b/libcxxabi/src/cxa_thread_atexit.cpp @@ -10,7 +10,7 @@ #include "cxxabi.h" #include <__threading_support> #ifndef _LIBCXXABI_HAS_NO_THREADS -#if defined(__unix__) && !defined(__ANDROID__) && defined(__ELF__) && defined(_LIBCXXABI_HAS_COMMENT_LIB_PRAGMA) +#if defined(__unix__) && defined(__ELF__) && defined(_LIBCXXABI_HAS_COMMENT_LIB_PRAGMA) #pragma comment(lib, "pthread") #endif #endif diff --git a/libcxxabi/src/cxa_unexpected.cpp b/libcxxabi/src/cxa_unexpected.cpp index bbfa6684efa749..ee0845ba2b2720 100644 --- a/libcxxabi/src/cxa_unexpected.cpp +++ b/libcxxabi/src/cxa_unexpected.cpp @@ -8,7 +8,7 @@ #include #include "cxxabi.h" -#include "cxa_exception.h" +#include "cxa_exception.hpp" namespace __cxxabiv1 { diff --git a/libcxxabi/src/demangle/ItaniumDemangle.h b/libcxxabi/src/demangle/ItaniumDemangle.h index aaccb27e17a3ea..ad1034f0fba3f3 100644 --- a/libcxxabi/src/demangle/ItaniumDemangle.h +++ b/libcxxabi/src/demangle/ItaniumDemangle.h @@ -3624,10 +3624,6 @@ Node *AbstractManglingParser::parseType() { case 's': First += 2; return make("char16_t"); - // ::= Du # char8_t (C++2a, not yet in the Itanium spec) - case 'u': - First += 2; - return make("char8_t"); // ::= Da # auto (in dependent new-expressions) case 'a': First += 2; diff --git a/libcxxabi/src/fallback_malloc.cpp b/libcxxabi/src/fallback_malloc.cpp index 9d6240752a1ab1..73ea28ed82449d 100644 --- a/libcxxabi/src/fallback_malloc.cpp +++ b/libcxxabi/src/fallback_malloc.cpp @@ -13,7 +13,7 @@ #include <__threading_support> #ifndef _LIBCXXABI_HAS_NO_THREADS -#if defined(__unix__) && !defined(__ANDROID__) && defined(__ELF__) && defined(_LIBCXXABI_HAS_COMMENT_LIB_PRAGMA) +#if defined(__unix__) && defined(__ELF__) && defined(_LIBCXXABI_HAS_COMMENT_LIB_PRAGMA) #pragma comment(lib, "pthread") #endif #endif diff --git a/libcxxabi/src/private_typeinfo.cpp b/libcxxabi/src/private_typeinfo.cpp index 43c91d123c9bda..c0a239476240cc 100644 --- a/libcxxabi/src/private_typeinfo.cpp +++ b/libcxxabi/src/private_typeinfo.cpp @@ -618,6 +618,7 @@ __dynamic_cast(const void *static_ptr, const __class_type_info *static_type, const __class_type_info *dst_type, std::ptrdiff_t src2dst_offset) { // Possible future optimization: Take advantage of src2dst_offset + // Currently clang always sets src2dst_offset to -1 (no hint). // Get (dynamic_ptr, dynamic_type) from static_ptr void **vtable = *static_cast(static_ptr); diff --git a/libcxxabi/test/CMakeLists.txt b/libcxxabi/test/CMakeLists.txt index 60e052d20710ca..01fae1357db3a3 100644 --- a/libcxxabi/test/CMakeLists.txt +++ b/libcxxabi/test/CMakeLists.txt @@ -19,7 +19,6 @@ pythonize_bool(LIBCXXABI_ENABLE_EXCEPTIONS) pythonize_bool(LIBCXXABI_USE_LLVM_UNWINDER) pythonize_bool(LIBCXXABI_USE_COMPILER_RT) pythonize_bool(LIBCXXABI_BUILD_EXTERNAL_THREAD_LIBRARY) -pythonize_bool(LIBCXX_ENABLE_PARALLEL_ALGORITHMS) set(LIBCXXABI_TARGET_INFO "libcxx.test.target_info.LocalTI" CACHE STRING "TargetInfo to use when setting up test environment.") set(LIBCXXABI_EXECUTOR "None" CACHE STRING diff --git a/libcxxabi/test/dynamic_cast14.pass.cpp b/libcxxabi/test/dynamic_cast14.pass.cpp index 57a4f26ed3b3c0..d72fa7f15ddb88 100644 --- a/libcxxabi/test/dynamic_cast14.pass.cpp +++ b/libcxxabi/test/dynamic_cast14.pass.cpp @@ -7,7 +7,7 @@ //===----------------------------------------------------------------------===// #include -#include "support/timer.h" +#include "support/timer.hpp" namespace t1 { diff --git a/libcxxabi/test/dynamic_cast3.pass.cpp b/libcxxabi/test/dynamic_cast3.pass.cpp index d569d5a540241d..b2187d369a8f2c 100644 --- a/libcxxabi/test/dynamic_cast3.pass.cpp +++ b/libcxxabi/test/dynamic_cast3.pass.cpp @@ -7,7 +7,7 @@ //===----------------------------------------------------------------------===// #include -#include "support/timer.h" +#include "support/timer.hpp" // This test explicitly tests dynamic cast with types that have inaccessible // bases. diff --git a/libcxxabi/test/dynamic_cast5.pass.cpp b/libcxxabi/test/dynamic_cast5.pass.cpp index a8e6d968bbcc64..b6a4c409ab2736 100644 --- a/libcxxabi/test/dynamic_cast5.pass.cpp +++ b/libcxxabi/test/dynamic_cast5.pass.cpp @@ -7,7 +7,7 @@ //===----------------------------------------------------------------------===// #include -#include "support/timer.h" +#include "support/timer.hpp" // This test explicitly tests dynamic cast with types that have inaccessible // bases. diff --git a/libcxxabi/test/dynamic_cast_stress.pass.cpp b/libcxxabi/test/dynamic_cast_stress.pass.cpp index 73b398f4730a9f..9f56a785317aad 100644 --- a/libcxxabi/test/dynamic_cast_stress.pass.cpp +++ b/libcxxabi/test/dynamic_cast_stress.pass.cpp @@ -10,7 +10,7 @@ #include #include -#include "support/timer.h" +#include "support/timer.hpp" template struct C diff --git a/libcxxabi/test/lit.site.cfg.in b/libcxxabi/test/lit.site.cfg.in index 8ac2fa45cab0bd..4abb8edeea073b 100644 --- a/libcxxabi/test/lit.site.cfg.in +++ b/libcxxabi/test/lit.site.cfg.in @@ -26,8 +26,5 @@ config.sysroot = "@LIBCXXABI_SYSROOT@" config.gcc_toolchain = "@LIBCXXABI_GCC_TOOLCHAIN@" config.cxx_ext_threads = @LIBCXXABI_BUILD_EXTERNAL_THREAD_LIBRARY@ -config.pstl_src_root = "@ParallelSTL_SOURCE_DIR@" if @LIBCXX_ENABLE_PARALLEL_ALGORITHMS@ else None -config.pstl_obj_root = "@ParallelSTL_BINARY_DIR@" if @LIBCXX_ENABLE_PARALLEL_ALGORITHMS@ else None - # Let the main config do the real work. lit_config.load_config(config, "@LIBCXXABI_SOURCE_DIR@/test/lit.cfg") diff --git a/libcxxabi/test/support/timer.h b/libcxxabi/test/support/timer.hpp similarity index 95% rename from libcxxabi/test/support/timer.h rename to libcxxabi/test/support/timer.hpp index 98a5dc0b68c172..f8cd3b8e5d4665 100644 --- a/libcxxabi/test/support/timer.h +++ b/libcxxabi/test/support/timer.hpp @@ -6,8 +6,8 @@ // //===----------------------------------------------------------------------===//// -#ifndef TIMER_H -#define TIMER_H +#ifndef TIMER_HPP +#define TIMER_HPP // Define LIBCXXABI_NO_TIMER to disable testing with a timer. #ifndef LIBCXXABI_NO_TIMER @@ -51,4 +51,4 @@ class timer #endif /* LIBCXXABI_NO_TIMER */ -#endif /* TIMER_H */ +#endif /* TIMER_HPP */ diff --git a/libcxxabi/test/test_demangle.pass.cpp b/libcxxabi/test/test_demangle.pass.cpp index 220c2fee9e27c0..761226b16b258a 100644 --- a/libcxxabi/test/test_demangle.pass.cpp +++ b/libcxxabi/test/test_demangle.pass.cpp @@ -6,7 +6,7 @@ // //===----------------------------------------------------------------------===// -#include "support/timer.h" +#include "support/timer.hpp" #include #include #include @@ -29772,9 +29772,6 @@ const char* cases[][2] = {"_ZN3FooIXu8__uuidofzdeL_Z3sucEEEC1Ev", "Foo<__uuidof(*(suc))>::Foo()"}, {"_ZN3FooIXu8__uuidoft13SomeUUIDClassEEC1Ev", "Foo<__uuidof(SomeUUIDClass)>::Foo()"}, - - // C++2a char8_t: - {"_ZTSPDu", "typeinfo name for char8_t*"}, }; const unsigned N = sizeof(cases) / sizeof(cases[0]); diff --git a/libcxxabi/test/test_exception_storage.pass.cpp b/libcxxabi/test/test_exception_storage.pass.cpp index 305a97024dfced..1fee6800477100 100644 --- a/libcxxabi/test/test_exception_storage.pass.cpp +++ b/libcxxabi/test/test_exception_storage.pass.cpp @@ -12,7 +12,7 @@ #include <__threading_support> #include -#include "../src/cxa_exception.h" +#include "../src/cxa_exception.hpp" typedef __cxxabiv1::__cxa_eh_globals globals_t ; diff --git a/libunwind/CMakeLists.txt b/libunwind/CMakeLists.txt index 440141c9b27b8c..b51922a48fe288 100644 --- a/libunwind/CMakeLists.txt +++ b/libunwind/CMakeLists.txt @@ -83,7 +83,7 @@ if (CMAKE_SOURCE_DIR STREQUAL CMAKE_CURRENT_SOURCE_DIR OR LIBUNWIND_STANDALONE_B endif() set(PACKAGE_NAME libunwind) - set(PACKAGE_VERSION 10.0.0svn) + set(PACKAGE_VERSION 9.0.0svn) set(PACKAGE_STRING "${PACKAGE_NAME} ${PACKAGE_VERSION}") set(PACKAGE_BUGREPORT "llvm-bugs@lists.llvm.org") diff --git a/libunwind/docs/conf.py b/libunwind/docs/conf.py index 44935b6ff25002..704a1d0a12da46 100644 --- a/libunwind/docs/conf.py +++ b/libunwind/docs/conf.py @@ -48,9 +48,9 @@ # built documents. # # The short X.Y version. -version = '10.0' +version = '9.0' # The full version, including alpha/beta/rc tags. -release = '10.0' +release = '9.0' # The language for content autogenerated by Sphinx. Refer to documentation # for a list of supported languages. diff --git a/libunwind/src/AddressSpace.hpp b/libunwind/src/AddressSpace.hpp index 2c9a083be2acee..fb07c807db9e9a 100644 --- a/libunwind/src/AddressSpace.hpp +++ b/libunwind/src/AddressSpace.hpp @@ -27,7 +27,7 @@ #if _LIBUNWIND_USE_DLADDR #include -#if defined(__unix__) && defined(__ELF__) && defined(_LIBUNWIND_HAS_COMMENT_LIB_PRAGMA) +#if defined(__unix__) && defined(__ELF__) && defined(_LIBUNWIND_HAS_COMMENT_LIB_PRAGMA) #pragma comment(lib, "dl") #endif #endif diff --git a/libunwind/src/RWMutex.hpp b/libunwind/src/RWMutex.hpp index 954e94c322d45a..a37ac77144f389 100644 --- a/libunwind/src/RWMutex.hpp +++ b/libunwind/src/RWMutex.hpp @@ -17,7 +17,7 @@ #include #elif !defined(_LIBUNWIND_HAS_NO_THREADS) #include -#if defined(__unix__) && !defined(__ANDROID__) && defined(__ELF__) && defined(_LIBUNWIND_HAS_COMMENT_LIB_PRAGMA) +#if defined(__unix__) && defined(__ELF__) && defined(_LIBUNWIND_HAS_COMMENT_LIB_PRAGMA) #pragma comment(lib, "pthread") #endif #endif diff --git a/libunwind/src/Unwind-EHABI.cpp b/libunwind/src/Unwind-EHABI.cpp index a23ba2cc7e0e60..f4558231a0e7eb 100644 --- a/libunwind/src/Unwind-EHABI.cpp +++ b/libunwind/src/Unwind-EHABI.cpp @@ -31,11 +31,7 @@ namespace { // signinficant byte. uint8_t getByte(const uint32_t* data, size_t offset) { const uint8_t* byteData = reinterpret_cast(data); -#ifdef __LITTLE_ENDIAN__ return byteData[(offset & ~(size_t)0x03) + (3 - (offset & (size_t)0x03))]; -#else - return byteData[offset]; -#endif } const char* getNextWord(const char* data, uint32_t* out) { @@ -941,13 +937,8 @@ _Unwind_VRS_Pop(_Unwind_Context *context, _Unwind_VRS_RegClass regclass, // format 1", which is equivalent to FSTMD + a padding word. for (uint32_t i = first; i < end; ++i) { // SP is only 32-bit aligned so don't copy 64-bit at a time. - uint64_t w0 = *sp++; - uint64_t w1 = *sp++; -#ifdef __LITTLE_ENDIAN__ - uint64_t value = (w1 << 32) | w0; -#else - uint64_t value = (w0 << 32) | w1; -#endif + uint64_t value = *sp++; + value |= ((uint64_t)(*sp++)) << 32; if (_Unwind_VRS_Set(context, regclass, i, representation, &value) != _UVRSR_OK) return _UVRSR_FAILED; diff --git a/lld/CMakeLists.txt b/lld/CMakeLists.txt index 641f71c114aeea..e2fbdbfbbb47f7 100644 --- a/lld/CMakeLists.txt +++ b/lld/CMakeLists.txt @@ -56,6 +56,7 @@ if(CMAKE_SOURCE_DIR STREQUAL CMAKE_CURRENT_SOURCE_DIR) include(HandleLLVMOptions) if(LLVM_INCLUDE_TESTS) + set(Python_ADDITIONAL_VERSIONS 2.7) include(FindPythonInterp) if(NOT PYTHONINTERP_FOUND) message(FATAL_ERROR diff --git a/lld/COFF/Chunks.cpp b/lld/COFF/Chunks.cpp index 0e43d2b478b405..fbae6f9a2725fc 100644 --- a/lld/COFF/Chunks.cpp +++ b/lld/COFF/Chunks.cpp @@ -29,27 +29,27 @@ using llvm::support::ulittle32_t; namespace lld { namespace coff { -SectionChunk::SectionChunk(ObjFile *f, const coff_section *h) - : Chunk(SectionKind), file(f), header(h), repl(this) { - // Initialize relocs. - setRelocs(file->getCOFFObj()->getRelocations(header)); +SectionChunk::SectionChunk(ObjFile *F, const coff_section *H) + : Chunk(SectionKind), File(F), Header(H), Repl(this) { + // Initialize Relocs. + setRelocs(File->getCOFFObj()->getRelocations(Header)); - // Initialize sectionName. - StringRef sectionName; - if (Expected e = file->getCOFFObj()->getSectionName(header)) - sectionName = *e; - sectionNameData = sectionName.data(); - sectionNameSize = sectionName.size(); + // Initialize SectionName. + StringRef SectionName; + if (Expected E = File->getCOFFObj()->getSectionName(Header)) + SectionName = *E; + SectionNameData = SectionName.data(); + SectionNameSize = SectionName.size(); - setAlignment(header->getAlignment()); + setAlignment(Header->getAlignment()); - hasData = !(header->Characteristics & IMAGE_SCN_CNT_UNINITIALIZED_DATA); + HasData = !(Header->Characteristics & IMAGE_SCN_CNT_UNINITIALIZED_DATA); // If linker GC is disabled, every chunk starts out alive. If linker GC is // enabled, treat non-comdat sections as roots. Generally optimized object // files will be built with -ffunction-sections or /Gy, so most things worth // stripping will be in a comdat. - live = !config->doGC || !isCOMDAT(); + Live = !Config->DoGC || !isCOMDAT(); } // SectionChunk is one of the most frequently allocated classes, so it is @@ -57,173 +57,173 @@ SectionChunk::SectionChunk(ObjFile *f, const coff_section *h) // below is the size of this class on x64 platforms. static_assert(sizeof(SectionChunk) <= 88, "SectionChunk grew unexpectedly"); -static void add16(uint8_t *p, int16_t v) { write16le(p, read16le(p) + v); } -static void add32(uint8_t *p, int32_t v) { write32le(p, read32le(p) + v); } -static void add64(uint8_t *p, int64_t v) { write64le(p, read64le(p) + v); } -static void or16(uint8_t *p, uint16_t v) { write16le(p, read16le(p) | v); } -static void or32(uint8_t *p, uint32_t v) { write32le(p, read32le(p) | v); } +static void add16(uint8_t *P, int16_t V) { write16le(P, read16le(P) + V); } +static void add32(uint8_t *P, int32_t V) { write32le(P, read32le(P) + V); } +static void add64(uint8_t *P, int64_t V) { write64le(P, read64le(P) + V); } +static void or16(uint8_t *P, uint16_t V) { write16le(P, read16le(P) | V); } +static void or32(uint8_t *P, uint32_t V) { write32le(P, read32le(P) | V); } // Verify that given sections are appropriate targets for SECREL // relocations. This check is relaxed because unfortunately debug // sections have section-relative relocations against absolute symbols. -static bool checkSecRel(const SectionChunk *sec, OutputSection *os) { - if (os) +static bool checkSecRel(const SectionChunk *Sec, OutputSection *OS) { + if (OS) return true; - if (sec->isCodeView()) + if (Sec->isCodeView()) return false; error("SECREL relocation cannot be applied to absolute symbols"); return false; } -static void applySecRel(const SectionChunk *sec, uint8_t *off, - OutputSection *os, uint64_t s) { - if (!checkSecRel(sec, os)) +static void applySecRel(const SectionChunk *Sec, uint8_t *Off, + OutputSection *OS, uint64_t S) { + if (!checkSecRel(Sec, OS)) return; - uint64_t secRel = s - os->getRVA(); - if (secRel > UINT32_MAX) { - error("overflow in SECREL relocation in section: " + sec->getSectionName()); + uint64_t SecRel = S - OS->getRVA(); + if (SecRel > UINT32_MAX) { + error("overflow in SECREL relocation in section: " + Sec->getSectionName()); return; } - add32(off, secRel); + add32(Off, SecRel); } -static void applySecIdx(uint8_t *off, OutputSection *os) { +static void applySecIdx(uint8_t *Off, OutputSection *OS) { // Absolute symbol doesn't have section index, but section index relocation // against absolute symbol should be resolved to one plus the last output // section index. This is required for compatibility with MSVC. - if (os) - add16(off, os->sectionIndex); + if (OS) + add16(Off, OS->SectionIndex); else - add16(off, DefinedAbsolute::numOutputSections + 1); -} - -void SectionChunk::applyRelX64(uint8_t *off, uint16_t type, OutputSection *os, - uint64_t s, uint64_t p) const { - switch (type) { - case IMAGE_REL_AMD64_ADDR32: add32(off, s + config->imageBase); break; - case IMAGE_REL_AMD64_ADDR64: add64(off, s + config->imageBase); break; - case IMAGE_REL_AMD64_ADDR32NB: add32(off, s); break; - case IMAGE_REL_AMD64_REL32: add32(off, s - p - 4); break; - case IMAGE_REL_AMD64_REL32_1: add32(off, s - p - 5); break; - case IMAGE_REL_AMD64_REL32_2: add32(off, s - p - 6); break; - case IMAGE_REL_AMD64_REL32_3: add32(off, s - p - 7); break; - case IMAGE_REL_AMD64_REL32_4: add32(off, s - p - 8); break; - case IMAGE_REL_AMD64_REL32_5: add32(off, s - p - 9); break; - case IMAGE_REL_AMD64_SECTION: applySecIdx(off, os); break; - case IMAGE_REL_AMD64_SECREL: applySecRel(this, off, os, s); break; + add16(Off, DefinedAbsolute::NumOutputSections + 1); +} + +void SectionChunk::applyRelX64(uint8_t *Off, uint16_t Type, OutputSection *OS, + uint64_t S, uint64_t P) const { + switch (Type) { + case IMAGE_REL_AMD64_ADDR32: add32(Off, S + Config->ImageBase); break; + case IMAGE_REL_AMD64_ADDR64: add64(Off, S + Config->ImageBase); break; + case IMAGE_REL_AMD64_ADDR32NB: add32(Off, S); break; + case IMAGE_REL_AMD64_REL32: add32(Off, S - P - 4); break; + case IMAGE_REL_AMD64_REL32_1: add32(Off, S - P - 5); break; + case IMAGE_REL_AMD64_REL32_2: add32(Off, S - P - 6); break; + case IMAGE_REL_AMD64_REL32_3: add32(Off, S - P - 7); break; + case IMAGE_REL_AMD64_REL32_4: add32(Off, S - P - 8); break; + case IMAGE_REL_AMD64_REL32_5: add32(Off, S - P - 9); break; + case IMAGE_REL_AMD64_SECTION: applySecIdx(Off, OS); break; + case IMAGE_REL_AMD64_SECREL: applySecRel(this, Off, OS, S); break; default: - error("unsupported relocation type 0x" + Twine::utohexstr(type) + " in " + - toString(file)); + error("unsupported relocation type 0x" + Twine::utohexstr(Type) + " in " + + toString(File)); } } -void SectionChunk::applyRelX86(uint8_t *off, uint16_t type, OutputSection *os, - uint64_t s, uint64_t p) const { - switch (type) { +void SectionChunk::applyRelX86(uint8_t *Off, uint16_t Type, OutputSection *OS, + uint64_t S, uint64_t P) const { + switch (Type) { case IMAGE_REL_I386_ABSOLUTE: break; - case IMAGE_REL_I386_DIR32: add32(off, s + config->imageBase); break; - case IMAGE_REL_I386_DIR32NB: add32(off, s); break; - case IMAGE_REL_I386_REL32: add32(off, s - p - 4); break; - case IMAGE_REL_I386_SECTION: applySecIdx(off, os); break; - case IMAGE_REL_I386_SECREL: applySecRel(this, off, os, s); break; + case IMAGE_REL_I386_DIR32: add32(Off, S + Config->ImageBase); break; + case IMAGE_REL_I386_DIR32NB: add32(Off, S); break; + case IMAGE_REL_I386_REL32: add32(Off, S - P - 4); break; + case IMAGE_REL_I386_SECTION: applySecIdx(Off, OS); break; + case IMAGE_REL_I386_SECREL: applySecRel(this, Off, OS, S); break; default: - error("unsupported relocation type 0x" + Twine::utohexstr(type) + " in " + - toString(file)); + error("unsupported relocation type 0x" + Twine::utohexstr(Type) + " in " + + toString(File)); } } -static void applyMOV(uint8_t *off, uint16_t v) { - write16le(off, (read16le(off) & 0xfbf0) | ((v & 0x800) >> 1) | ((v >> 12) & 0xf)); - write16le(off + 2, (read16le(off + 2) & 0x8f00) | ((v & 0x700) << 4) | (v & 0xff)); +static void applyMOV(uint8_t *Off, uint16_t V) { + write16le(Off, (read16le(Off) & 0xfbf0) | ((V & 0x800) >> 1) | ((V >> 12) & 0xf)); + write16le(Off + 2, (read16le(Off + 2) & 0x8f00) | ((V & 0x700) << 4) | (V & 0xff)); } -static uint16_t readMOV(uint8_t *off, bool movt) { - uint16_t op1 = read16le(off); - if ((op1 & 0xfbf0) != (movt ? 0xf2c0 : 0xf240)) - error("unexpected instruction in " + Twine(movt ? "MOVT" : "MOVW") + +static uint16_t readMOV(uint8_t *Off, bool MOVT) { + uint16_t Op1 = read16le(Off); + if ((Op1 & 0xfbf0) != (MOVT ? 0xf2c0 : 0xf240)) + error("unexpected instruction in " + Twine(MOVT ? "MOVT" : "MOVW") + " instruction in MOV32T relocation"); - uint16_t op2 = read16le(off + 2); - if ((op2 & 0x8000) != 0) - error("unexpected instruction in " + Twine(movt ? "MOVT" : "MOVW") + + uint16_t Op2 = read16le(Off + 2); + if ((Op2 & 0x8000) != 0) + error("unexpected instruction in " + Twine(MOVT ? "MOVT" : "MOVW") + " instruction in MOV32T relocation"); - return (op2 & 0x00ff) | ((op2 >> 4) & 0x0700) | ((op1 << 1) & 0x0800) | - ((op1 & 0x000f) << 12); + return (Op2 & 0x00ff) | ((Op2 >> 4) & 0x0700) | ((Op1 << 1) & 0x0800) | + ((Op1 & 0x000f) << 12); } -void applyMOV32T(uint8_t *off, uint32_t v) { - uint16_t immW = readMOV(off, false); // read MOVW operand - uint16_t immT = readMOV(off + 4, true); // read MOVT operand - uint32_t imm = immW | (immT << 16); - v += imm; // add the immediate offset - applyMOV(off, v); // set MOVW operand - applyMOV(off + 4, v >> 16); // set MOVT operand +void applyMOV32T(uint8_t *Off, uint32_t V) { + uint16_t ImmW = readMOV(Off, false); // read MOVW operand + uint16_t ImmT = readMOV(Off + 4, true); // read MOVT operand + uint32_t Imm = ImmW | (ImmT << 16); + V += Imm; // add the immediate offset + applyMOV(Off, V); // set MOVW operand + applyMOV(Off + 4, V >> 16); // set MOVT operand } -static void applyBranch20T(uint8_t *off, int32_t v) { - if (!isInt<21>(v)) +static void applyBranch20T(uint8_t *Off, int32_t V) { + if (!isInt<21>(V)) error("relocation out of range"); - uint32_t s = v < 0 ? 1 : 0; - uint32_t j1 = (v >> 19) & 1; - uint32_t j2 = (v >> 18) & 1; - or16(off, (s << 10) | ((v >> 12) & 0x3f)); - or16(off + 2, (j1 << 13) | (j2 << 11) | ((v >> 1) & 0x7ff)); + uint32_t S = V < 0 ? 1 : 0; + uint32_t J1 = (V >> 19) & 1; + uint32_t J2 = (V >> 18) & 1; + or16(Off, (S << 10) | ((V >> 12) & 0x3f)); + or16(Off + 2, (J1 << 13) | (J2 << 11) | ((V >> 1) & 0x7ff)); } -void applyBranch24T(uint8_t *off, int32_t v) { - if (!isInt<25>(v)) +void applyBranch24T(uint8_t *Off, int32_t V) { + if (!isInt<25>(V)) error("relocation out of range"); - uint32_t s = v < 0 ? 1 : 0; - uint32_t j1 = ((~v >> 23) & 1) ^ s; - uint32_t j2 = ((~v >> 22) & 1) ^ s; - or16(off, (s << 10) | ((v >> 12) & 0x3ff)); + uint32_t S = V < 0 ? 1 : 0; + uint32_t J1 = ((~V >> 23) & 1) ^ S; + uint32_t J2 = ((~V >> 22) & 1) ^ S; + or16(Off, (S << 10) | ((V >> 12) & 0x3ff)); // Clear out the J1 and J2 bits which may be set. - write16le(off + 2, (read16le(off + 2) & 0xd000) | (j1 << 13) | (j2 << 11) | ((v >> 1) & 0x7ff)); + write16le(Off + 2, (read16le(Off + 2) & 0xd000) | (J1 << 13) | (J2 << 11) | ((V >> 1) & 0x7ff)); } -void SectionChunk::applyRelARM(uint8_t *off, uint16_t type, OutputSection *os, - uint64_t s, uint64_t p) const { +void SectionChunk::applyRelARM(uint8_t *Off, uint16_t Type, OutputSection *OS, + uint64_t S, uint64_t P) const { // Pointer to thumb code must have the LSB set. - uint64_t sx = s; - if (os && (os->header.Characteristics & IMAGE_SCN_MEM_EXECUTE)) - sx |= 1; - switch (type) { - case IMAGE_REL_ARM_ADDR32: add32(off, sx + config->imageBase); break; - case IMAGE_REL_ARM_ADDR32NB: add32(off, sx); break; - case IMAGE_REL_ARM_MOV32T: applyMOV32T(off, sx + config->imageBase); break; - case IMAGE_REL_ARM_BRANCH20T: applyBranch20T(off, sx - p - 4); break; - case IMAGE_REL_ARM_BRANCH24T: applyBranch24T(off, sx - p - 4); break; - case IMAGE_REL_ARM_BLX23T: applyBranch24T(off, sx - p - 4); break; - case IMAGE_REL_ARM_SECTION: applySecIdx(off, os); break; - case IMAGE_REL_ARM_SECREL: applySecRel(this, off, os, s); break; - case IMAGE_REL_ARM_REL32: add32(off, sx - p - 4); break; + uint64_t SX = S; + if (OS && (OS->Header.Characteristics & IMAGE_SCN_MEM_EXECUTE)) + SX |= 1; + switch (Type) { + case IMAGE_REL_ARM_ADDR32: add32(Off, SX + Config->ImageBase); break; + case IMAGE_REL_ARM_ADDR32NB: add32(Off, SX); break; + case IMAGE_REL_ARM_MOV32T: applyMOV32T(Off, SX + Config->ImageBase); break; + case IMAGE_REL_ARM_BRANCH20T: applyBranch20T(Off, SX - P - 4); break; + case IMAGE_REL_ARM_BRANCH24T: applyBranch24T(Off, SX - P - 4); break; + case IMAGE_REL_ARM_BLX23T: applyBranch24T(Off, SX - P - 4); break; + case IMAGE_REL_ARM_SECTION: applySecIdx(Off, OS); break; + case IMAGE_REL_ARM_SECREL: applySecRel(this, Off, OS, S); break; + case IMAGE_REL_ARM_REL32: add32(Off, SX - P - 4); break; default: - error("unsupported relocation type 0x" + Twine::utohexstr(type) + " in " + - toString(file)); + error("unsupported relocation type 0x" + Twine::utohexstr(Type) + " in " + + toString(File)); } } // Interpret the existing immediate value as a byte offset to the // target symbol, then update the instruction with the immediate as // the page offset from the current instruction to the target. -void applyArm64Addr(uint8_t *off, uint64_t s, uint64_t p, int shift) { - uint32_t orig = read32le(off); - uint64_t imm = ((orig >> 29) & 0x3) | ((orig >> 3) & 0x1FFFFC); - s += imm; - imm = (s >> shift) - (p >> shift); - uint32_t immLo = (imm & 0x3) << 29; - uint32_t immHi = (imm & 0x1FFFFC) << 3; - uint64_t mask = (0x3 << 29) | (0x1FFFFC << 3); - write32le(off, (orig & ~mask) | immLo | immHi); +void applyArm64Addr(uint8_t *Off, uint64_t S, uint64_t P, int Shift) { + uint32_t Orig = read32le(Off); + uint64_t Imm = ((Orig >> 29) & 0x3) | ((Orig >> 3) & 0x1FFFFC); + S += Imm; + Imm = (S >> Shift) - (P >> Shift); + uint32_t ImmLo = (Imm & 0x3) << 29; + uint32_t ImmHi = (Imm & 0x1FFFFC) << 3; + uint64_t Mask = (0x3 << 29) | (0x1FFFFC << 3); + write32le(Off, (Orig & ~Mask) | ImmLo | ImmHi); } // Update the immediate field in a AARCH64 ldr, str, and add instruction. // Optionally limit the range of the written immediate by one or more bits -// (rangeLimit). -void applyArm64Imm(uint8_t *off, uint64_t imm, uint32_t rangeLimit) { - uint32_t orig = read32le(off); - imm += (orig >> 10) & 0xFFF; - orig &= ~(0xFFF << 10); - write32le(off, orig | ((imm & (0xFFF >> rangeLimit)) << 10)); +// (RangeLimit). +void applyArm64Imm(uint8_t *Off, uint64_t Imm, uint32_t RangeLimit) { + uint32_t Orig = read32le(Off); + Imm += (Orig >> 10) & 0xFFF; + Orig &= ~(0xFFF << 10); + write32le(Off, Orig | ((Imm & (0xFFF >> RangeLimit)) << 10)); } // Add the 12 bit page offset to the existing immediate. @@ -234,178 +234,178 @@ void applyArm64Imm(uint8_t *off, uint64_t imm, uint32_t rangeLimit) { // Even if larger loads/stores have a larger range, limit the // effective offset to 12 bit, since it is intended to be a // page offset. -static void applyArm64Ldr(uint8_t *off, uint64_t imm) { - uint32_t orig = read32le(off); - uint32_t size = orig >> 30; +static void applyArm64Ldr(uint8_t *Off, uint64_t Imm) { + uint32_t Orig = read32le(Off); + uint32_t Size = Orig >> 30; // 0x04000000 indicates SIMD/FP registers // 0x00800000 indicates 128 bit - if ((orig & 0x4800000) == 0x4800000) - size += 4; - if ((imm & ((1 << size) - 1)) != 0) + if ((Orig & 0x4800000) == 0x4800000) + Size += 4; + if ((Imm & ((1 << Size) - 1)) != 0) error("misaligned ldr/str offset"); - applyArm64Imm(off, imm >> size, size); + applyArm64Imm(Off, Imm >> Size, Size); } -static void applySecRelLow12A(const SectionChunk *sec, uint8_t *off, - OutputSection *os, uint64_t s) { - if (checkSecRel(sec, os)) - applyArm64Imm(off, (s - os->getRVA()) & 0xfff, 0); +static void applySecRelLow12A(const SectionChunk *Sec, uint8_t *Off, + OutputSection *OS, uint64_t S) { + if (checkSecRel(Sec, OS)) + applyArm64Imm(Off, (S - OS->getRVA()) & 0xfff, 0); } -static void applySecRelHigh12A(const SectionChunk *sec, uint8_t *off, - OutputSection *os, uint64_t s) { - if (!checkSecRel(sec, os)) +static void applySecRelHigh12A(const SectionChunk *Sec, uint8_t *Off, + OutputSection *OS, uint64_t S) { + if (!checkSecRel(Sec, OS)) return; - uint64_t secRel = (s - os->getRVA()) >> 12; - if (0xfff < secRel) { + uint64_t SecRel = (S - OS->getRVA()) >> 12; + if (0xfff < SecRel) { error("overflow in SECREL_HIGH12A relocation in section: " + - sec->getSectionName()); + Sec->getSectionName()); return; } - applyArm64Imm(off, secRel & 0xfff, 0); + applyArm64Imm(Off, SecRel & 0xfff, 0); } -static void applySecRelLdr(const SectionChunk *sec, uint8_t *off, - OutputSection *os, uint64_t s) { - if (checkSecRel(sec, os)) - applyArm64Ldr(off, (s - os->getRVA()) & 0xfff); +static void applySecRelLdr(const SectionChunk *Sec, uint8_t *Off, + OutputSection *OS, uint64_t S) { + if (checkSecRel(Sec, OS)) + applyArm64Ldr(Off, (S - OS->getRVA()) & 0xfff); } -void applyArm64Branch26(uint8_t *off, int64_t v) { - if (!isInt<28>(v)) +void applyArm64Branch26(uint8_t *Off, int64_t V) { + if (!isInt<28>(V)) error("relocation out of range"); - or32(off, (v & 0x0FFFFFFC) >> 2); + or32(Off, (V & 0x0FFFFFFC) >> 2); } -static void applyArm64Branch19(uint8_t *off, int64_t v) { - if (!isInt<21>(v)) +static void applyArm64Branch19(uint8_t *Off, int64_t V) { + if (!isInt<21>(V)) error("relocation out of range"); - or32(off, (v & 0x001FFFFC) << 3); + or32(Off, (V & 0x001FFFFC) << 3); } -static void applyArm64Branch14(uint8_t *off, int64_t v) { - if (!isInt<16>(v)) +static void applyArm64Branch14(uint8_t *Off, int64_t V) { + if (!isInt<16>(V)) error("relocation out of range"); - or32(off, (v & 0x0000FFFC) << 3); -} - -void SectionChunk::applyRelARM64(uint8_t *off, uint16_t type, OutputSection *os, - uint64_t s, uint64_t p) const { - switch (type) { - case IMAGE_REL_ARM64_PAGEBASE_REL21: applyArm64Addr(off, s, p, 12); break; - case IMAGE_REL_ARM64_REL21: applyArm64Addr(off, s, p, 0); break; - case IMAGE_REL_ARM64_PAGEOFFSET_12A: applyArm64Imm(off, s & 0xfff, 0); break; - case IMAGE_REL_ARM64_PAGEOFFSET_12L: applyArm64Ldr(off, s & 0xfff); break; - case IMAGE_REL_ARM64_BRANCH26: applyArm64Branch26(off, s - p); break; - case IMAGE_REL_ARM64_BRANCH19: applyArm64Branch19(off, s - p); break; - case IMAGE_REL_ARM64_BRANCH14: applyArm64Branch14(off, s - p); break; - case IMAGE_REL_ARM64_ADDR32: add32(off, s + config->imageBase); break; - case IMAGE_REL_ARM64_ADDR32NB: add32(off, s); break; - case IMAGE_REL_ARM64_ADDR64: add64(off, s + config->imageBase); break; - case IMAGE_REL_ARM64_SECREL: applySecRel(this, off, os, s); break; - case IMAGE_REL_ARM64_SECREL_LOW12A: applySecRelLow12A(this, off, os, s); break; - case IMAGE_REL_ARM64_SECREL_HIGH12A: applySecRelHigh12A(this, off, os, s); break; - case IMAGE_REL_ARM64_SECREL_LOW12L: applySecRelLdr(this, off, os, s); break; - case IMAGE_REL_ARM64_SECTION: applySecIdx(off, os); break; - case IMAGE_REL_ARM64_REL32: add32(off, s - p - 4); break; + or32(Off, (V & 0x0000FFFC) << 3); +} + +void SectionChunk::applyRelARM64(uint8_t *Off, uint16_t Type, OutputSection *OS, + uint64_t S, uint64_t P) const { + switch (Type) { + case IMAGE_REL_ARM64_PAGEBASE_REL21: applyArm64Addr(Off, S, P, 12); break; + case IMAGE_REL_ARM64_REL21: applyArm64Addr(Off, S, P, 0); break; + case IMAGE_REL_ARM64_PAGEOFFSET_12A: applyArm64Imm(Off, S & 0xfff, 0); break; + case IMAGE_REL_ARM64_PAGEOFFSET_12L: applyArm64Ldr(Off, S & 0xfff); break; + case IMAGE_REL_ARM64_BRANCH26: applyArm64Branch26(Off, S - P); break; + case IMAGE_REL_ARM64_BRANCH19: applyArm64Branch19(Off, S - P); break; + case IMAGE_REL_ARM64_BRANCH14: applyArm64Branch14(Off, S - P); break; + case IMAGE_REL_ARM64_ADDR32: add32(Off, S + Config->ImageBase); break; + case IMAGE_REL_ARM64_ADDR32NB: add32(Off, S); break; + case IMAGE_REL_ARM64_ADDR64: add64(Off, S + Config->ImageBase); break; + case IMAGE_REL_ARM64_SECREL: applySecRel(this, Off, OS, S); break; + case IMAGE_REL_ARM64_SECREL_LOW12A: applySecRelLow12A(this, Off, OS, S); break; + case IMAGE_REL_ARM64_SECREL_HIGH12A: applySecRelHigh12A(this, Off, OS, S); break; + case IMAGE_REL_ARM64_SECREL_LOW12L: applySecRelLdr(this, Off, OS, S); break; + case IMAGE_REL_ARM64_SECTION: applySecIdx(Off, OS); break; + case IMAGE_REL_ARM64_REL32: add32(Off, S - P - 4); break; default: - error("unsupported relocation type 0x" + Twine::utohexstr(type) + " in " + - toString(file)); + error("unsupported relocation type 0x" + Twine::utohexstr(Type) + " in " + + toString(File)); } } -static void maybeReportRelocationToDiscarded(const SectionChunk *fromChunk, - Defined *sym, - const coff_relocation &rel) { +static void maybeReportRelocationToDiscarded(const SectionChunk *FromChunk, + Defined *Sym, + const coff_relocation &Rel) { // Don't report these errors when the relocation comes from a debug info // section or in mingw mode. MinGW mode object files (built by GCC) can // have leftover sections with relocations against discarded comdat // sections. Such sections are left as is, with relocations untouched. - if (fromChunk->isCodeView() || fromChunk->isDWARF() || config->mingw) + if (FromChunk->isCodeView() || FromChunk->isDWARF() || Config->MinGW) return; // Get the name of the symbol. If it's null, it was discarded early, so we // have to go back to the object file. - ObjFile *file = fromChunk->file; - StringRef name; - if (sym) { - name = sym->getName(); + ObjFile *File = FromChunk->File; + StringRef Name; + if (Sym) { + Name = Sym->getName(); } else { - COFFSymbolRef coffSym = - check(file->getCOFFObj()->getSymbol(rel.SymbolTableIndex)); - file->getCOFFObj()->getSymbolName(coffSym, name); + COFFSymbolRef COFFSym = + check(File->getCOFFObj()->getSymbol(Rel.SymbolTableIndex)); + File->getCOFFObj()->getSymbolName(COFFSym, Name); } - std::vector symbolLocations = - getSymbolLocations(file, rel.SymbolTableIndex); + std::vector SymbolLocations = + getSymbolLocations(File, Rel.SymbolTableIndex); - std::string out; - llvm::raw_string_ostream os(out); - os << "relocation against symbol in discarded section: " + name; - for (const std::string &s : symbolLocations) - os << s; - error(os.str()); + std::string Out; + llvm::raw_string_ostream OS(Out); + OS << "relocation against symbol in discarded section: " + Name; + for (const std::string &S : SymbolLocations) + OS << S; + error(OS.str()); } -void SectionChunk::writeTo(uint8_t *buf) const { - if (!hasData) +void SectionChunk::writeTo(uint8_t *Buf) const { + if (!hasData()) return; // Copy section contents from source object file to output file. - ArrayRef a = getContents(); - if (!a.empty()) - memcpy(buf, a.data(), a.size()); + ArrayRef A = getContents(); + if (!A.empty()) + memcpy(Buf, A.data(), A.size()); // Apply relocations. - size_t inputSize = getSize(); - for (size_t i = 0, e = relocsSize; i < e; i++) { - const coff_relocation &rel = relocsData[i]; + size_t InputSize = getSize(); + for (size_t I = 0, E = RelocsSize; I < E; I++) { + const coff_relocation &Rel = RelocsData[I]; // Check for an invalid relocation offset. This check isn't perfect, because // we don't have the relocation size, which is only known after checking the // machine and relocation type. As a result, a relocation may overwrite the // beginning of the following input section. - if (rel.VirtualAddress >= inputSize) { + if (Rel.VirtualAddress >= InputSize) { error("relocation points beyond the end of its parent section"); continue; } - uint8_t *off = buf + rel.VirtualAddress; + uint8_t *Off = Buf + Rel.VirtualAddress; - auto *sym = - dyn_cast_or_null(file->getSymbol(rel.SymbolTableIndex)); + auto *Sym = + dyn_cast_or_null(File->getSymbol(Rel.SymbolTableIndex)); // Get the output section of the symbol for this relocation. The output // section is needed to compute SECREL and SECTION relocations used in debug // info. - Chunk *c = sym ? sym->getChunk() : nullptr; - OutputSection *os = c ? c->getOutputSection() : nullptr; + Chunk *C = Sym ? Sym->getChunk() : nullptr; + OutputSection *OS = C ? C->getOutputSection() : nullptr; // Skip the relocation if it refers to a discarded section, and diagnose it // as an error if appropriate. If a symbol was discarded early, it may be // null. If it was discarded late, the output section will be null, unless // it was an absolute or synthetic symbol. - if (!sym || - (!os && !isa(sym) && !isa(sym))) { - maybeReportRelocationToDiscarded(this, sym, rel); + if (!Sym || + (!OS && !isa(Sym) && !isa(Sym))) { + maybeReportRelocationToDiscarded(this, Sym, Rel); continue; } - uint64_t s = sym->getRVA(); + uint64_t S = Sym->getRVA(); // Compute the RVA of the relocation for relative relocations. - uint64_t p = rva + rel.VirtualAddress; - switch (config->machine) { + uint64_t P = RVA + Rel.VirtualAddress; + switch (Config->Machine) { case AMD64: - applyRelX64(off, rel.Type, os, s, p); + applyRelX64(Off, Rel.Type, OS, S, P); break; case I386: - applyRelX86(off, rel.Type, os, s, p); + applyRelX86(Off, Rel.Type, OS, S, P); break; case ARMNT: - applyRelARM(off, rel.Type, os, s, p); + applyRelARM(Off, Rel.Type, OS, S, P); break; case ARM64: - applyRelARM64(off, rel.Type, os, s, p); + applyRelARM64(Off, Rel.Type, OS, S, P); break; default: llvm_unreachable("unknown machine type"); @@ -413,32 +413,32 @@ void SectionChunk::writeTo(uint8_t *buf) const { } } -void SectionChunk::addAssociative(SectionChunk *child) { +void SectionChunk::addAssociative(SectionChunk *Child) { // Insert this child at the head of the list. - assert(child->assocChildren == nullptr && + assert(Child->AssocChildren == nullptr && "associated sections cannot have their own associated children"); - child->assocChildren = assocChildren; - assocChildren = child; + Child->AssocChildren = AssocChildren; + AssocChildren = Child; } -static uint8_t getBaserelType(const coff_relocation &rel) { - switch (config->machine) { +static uint8_t getBaserelType(const coff_relocation &Rel) { + switch (Config->Machine) { case AMD64: - if (rel.Type == IMAGE_REL_AMD64_ADDR64) + if (Rel.Type == IMAGE_REL_AMD64_ADDR64) return IMAGE_REL_BASED_DIR64; return IMAGE_REL_BASED_ABSOLUTE; case I386: - if (rel.Type == IMAGE_REL_I386_DIR32) + if (Rel.Type == IMAGE_REL_I386_DIR32) return IMAGE_REL_BASED_HIGHLOW; return IMAGE_REL_BASED_ABSOLUTE; case ARMNT: - if (rel.Type == IMAGE_REL_ARM_ADDR32) + if (Rel.Type == IMAGE_REL_ARM_ADDR32) return IMAGE_REL_BASED_HIGHLOW; - if (rel.Type == IMAGE_REL_ARM_MOV32T) + if (Rel.Type == IMAGE_REL_ARM_MOV32T) return IMAGE_REL_BASED_ARM_MOV32T; return IMAGE_REL_BASED_ABSOLUTE; case ARM64: - if (rel.Type == IMAGE_REL_ARM64_ADDR64) + if (Rel.Type == IMAGE_REL_ARM64_ADDR64) return IMAGE_REL_BASED_DIR64; return IMAGE_REL_BASED_ABSOLUTE; default: @@ -450,16 +450,16 @@ static uint8_t getBaserelType(const coff_relocation &rel) { // Collect all locations that contain absolute addresses, which need to be // fixed by the loader if load-time relocation is needed. // Only called when base relocation is enabled. -void SectionChunk::getBaserels(std::vector *res) { - for (size_t i = 0, e = relocsSize; i < e; i++) { - const coff_relocation &rel = relocsData[i]; - uint8_t ty = getBaserelType(rel); - if (ty == IMAGE_REL_BASED_ABSOLUTE) +void SectionChunk::getBaserels(std::vector *Res) { + for (size_t I = 0, E = RelocsSize; I < E; I++) { + const coff_relocation &Rel = RelocsData[I]; + uint8_t Ty = getBaserelType(Rel); + if (Ty == IMAGE_REL_BASED_ABSOLUTE) continue; - Symbol *target = file->getSymbol(rel.SymbolTableIndex); - if (!target || isa(target)) + Symbol *Target = File->getSymbol(Rel.SymbolTableIndex); + if (!Target || isa(Target)) continue; - res->emplace_back(rva + rel.VirtualAddress, ty); + Res->emplace_back(RVA + Rel.VirtualAddress, Ty); } } @@ -470,7 +470,7 @@ void SectionChunk::getBaserels(std::vector *res) { // another DLL) This returns the size the relocation is supposed to update, // in bits, or 0 if the relocation cannot be handled as a runtime pseudo // relocation. -static int getRuntimePseudoRelocSize(uint16_t type) { +static int getRuntimePseudoRelocSize(uint16_t Type) { // Relocations that either contain an absolute address, or a plain // relative offset, since the runtime pseudo reloc implementation // adds 8/16/32/64 bit values to a memory address. @@ -496,9 +496,9 @@ static int getRuntimePseudoRelocSize(uint16_t type) { // the image, or temporarily changed at runtime with VirtualProtect. // Since this only operates on direct address values, it doesn't work for // ARM/ARM64 relocations, other than the plain ADDR32/ADDR64 relocations. - switch (config->machine) { + switch (Config->Machine) { case AMD64: - switch (type) { + switch (Type) { case IMAGE_REL_AMD64_ADDR64: return 64; case IMAGE_REL_AMD64_ADDR32: @@ -513,7 +513,7 @@ static int getRuntimePseudoRelocSize(uint16_t type) { return 0; } case I386: - switch (type) { + switch (Type) { case IMAGE_REL_I386_DIR32: case IMAGE_REL_I386_REL32: return 32; @@ -521,14 +521,14 @@ static int getRuntimePseudoRelocSize(uint16_t type) { return 0; } case ARMNT: - switch (type) { + switch (Type) { case IMAGE_REL_ARM_ADDR32: return 32; default: return 0; } case ARM64: - switch (type) { + switch (Type) { case IMAGE_REL_ARM64_ADDR64: return 64; case IMAGE_REL_ARM64_ADDR32: @@ -547,48 +547,48 @@ static int getRuntimePseudoRelocSize(uint16_t type) { // to a module local variable, which turned out to actually need to be // imported from another DLL). void SectionChunk::getRuntimePseudoRelocs( - std::vector &res) { - for (const coff_relocation &rel : getRelocs()) { - auto *target = - dyn_cast_or_null(file->getSymbol(rel.SymbolTableIndex)); - if (!target || !target->isRuntimePseudoReloc) + std::vector &Res) { + for (const coff_relocation &Rel : getRelocs()) { + auto *Target = + dyn_cast_or_null(File->getSymbol(Rel.SymbolTableIndex)); + if (!Target || !Target->IsRuntimePseudoReloc) continue; - int sizeInBits = getRuntimePseudoRelocSize(rel.Type); - if (sizeInBits == 0) { - error("unable to automatically import from " + target->getName() + + int SizeInBits = getRuntimePseudoRelocSize(Rel.Type); + if (SizeInBits == 0) { + error("unable to automatically import from " + Target->getName() + " with relocation type " + - file->getCOFFObj()->getRelocationTypeName(rel.Type) + " in " + - toString(file)); + File->getCOFFObj()->getRelocationTypeName(Rel.Type) + " in " + + toString(File)); continue; } - // sizeInBits is used to initialize the Flags field; currently no + // SizeInBits is used to initialize the Flags field; currently no // other flags are defined. - res.emplace_back( - RuntimePseudoReloc(target, this, rel.VirtualAddress, sizeInBits)); + Res.emplace_back( + RuntimePseudoReloc(Target, this, Rel.VirtualAddress, SizeInBits)); } } bool SectionChunk::isCOMDAT() const { - return header->Characteristics & IMAGE_SCN_LNK_COMDAT; + return Header->Characteristics & IMAGE_SCN_LNK_COMDAT; } void SectionChunk::printDiscardedMessage() const { // Removed by dead-stripping. If it's removed by ICF, ICF already // printed out the name, so don't repeat that here. - if (sym && this == repl) - message("Discarded " + sym->getName()); + if (Sym && this == Repl) + message("Discarded " + Sym->getName()); } StringRef SectionChunk::getDebugName() const { - if (sym) - return sym->getName(); + if (Sym) + return Sym->getName(); return ""; } ArrayRef SectionChunk::getContents() const { - ArrayRef a; - cantFail(file->getCOFFObj()->getSectionContents(header, a)); - return a; + ArrayRef A; + cantFail(File->getCOFFObj()->getSectionContents(Header, A)); + return A; } ArrayRef SectionChunk::consumeDebugMagic() { @@ -596,57 +596,57 @@ ArrayRef SectionChunk::consumeDebugMagic() { return consumeDebugMagic(getContents(), getSectionName()); } -ArrayRef SectionChunk::consumeDebugMagic(ArrayRef data, - StringRef sectionName) { - if (data.empty()) +ArrayRef SectionChunk::consumeDebugMagic(ArrayRef Data, + StringRef SectionName) { + if (Data.empty()) return {}; // First 4 bytes are section magic. - if (data.size() < 4) - fatal("the section is too short: " + sectionName); + if (Data.size() < 4) + fatal("the section is too short: " + SectionName); - if (!sectionName.startswith(".debug$")) - fatal("invalid section: " + sectionName); + if (!SectionName.startswith(".debug$")) + fatal("invalid section: " + SectionName); - uint32_t magic = support::endian::read32le(data.data()); - uint32_t expectedMagic = sectionName == ".debug$H" + uint32_t Magic = support::endian::read32le(Data.data()); + uint32_t ExpectedMagic = SectionName == ".debug$H" ? DEBUG_HASHES_SECTION_MAGIC : DEBUG_SECTION_MAGIC; - if (magic != expectedMagic) { - warn("ignoring section " + sectionName + " with unrecognized magic 0x" + - utohexstr(magic)); + if (Magic != ExpectedMagic) { + warn("ignoring section " + SectionName + " with unrecognized magic 0x" + + utohexstr(Magic)); return {}; } - return data.slice(4); + return Data.slice(4); } -SectionChunk *SectionChunk::findByName(ArrayRef sections, - StringRef name) { - for (SectionChunk *c : sections) - if (c->getSectionName() == name) - return c; +SectionChunk *SectionChunk::findByName(ArrayRef Sections, + StringRef Name) { + for (SectionChunk *C : Sections) + if (C->getSectionName() == Name) + return C; return nullptr; } -void SectionChunk::replace(SectionChunk *other) { - p2Align = std::max(p2Align, other->p2Align); - other->repl = repl; - other->live = false; +void SectionChunk::replace(SectionChunk *Other) { + P2Align = std::max(P2Align, Other->P2Align); + Other->Repl = Repl; + Other->Live = false; } uint32_t SectionChunk::getSectionNumber() const { - DataRefImpl r; - r.p = reinterpret_cast(header); - SectionRef s(r, file->getCOFFObj()); - return s.getIndex() + 1; + DataRefImpl R; + R.p = reinterpret_cast(Header); + SectionRef S(R, File->getCOFFObj()); + return S.getIndex() + 1; } -CommonChunk::CommonChunk(const COFFSymbolRef s) : sym(s) { +CommonChunk::CommonChunk(const COFFSymbolRef S) : Sym(S) { // The value of a common symbol is its size. Align all common symbols smaller // than 32 bytes naturally, i.e. round the size up to the next power of two. // This is what MSVC link.exe does. - setAlignment(std::min(32U, uint32_t(PowerOf2Ceil(sym.getValue())))); - hasData = false; + setAlignment(std::min(32U, uint32_t(PowerOf2Ceil(Sym.getValue())))); + HasData = false; } uint32_t CommonChunk::getOutputCharacteristics() const { @@ -654,139 +654,139 @@ uint32_t CommonChunk::getOutputCharacteristics() const { IMAGE_SCN_MEM_WRITE; } -void StringChunk::writeTo(uint8_t *buf) const { - memcpy(buf, str.data(), str.size()); - buf[str.size()] = '\0'; +void StringChunk::writeTo(uint8_t *Buf) const { + memcpy(Buf, Str.data(), Str.size()); + Buf[Str.size()] = '\0'; } -ImportThunkChunkX64::ImportThunkChunkX64(Defined *s) : ImportThunkChunk(s) { +ImportThunkChunkX64::ImportThunkChunkX64(Defined *S) : ImportThunkChunk(S) { // Intel Optimization Manual says that all branch targets // should be 16-byte aligned. MSVC linker does this too. setAlignment(16); } -void ImportThunkChunkX64::writeTo(uint8_t *buf) const { - memcpy(buf, importThunkX86, sizeof(importThunkX86)); +void ImportThunkChunkX64::writeTo(uint8_t *Buf) const { + memcpy(Buf, ImportThunkX86, sizeof(ImportThunkX86)); // The first two bytes is a JMP instruction. Fill its operand. - write32le(buf + 2, impSymbol->getRVA() - rva - getSize()); + write32le(Buf + 2, ImpSymbol->getRVA() - RVA - getSize()); } -void ImportThunkChunkX86::getBaserels(std::vector *res) { - res->emplace_back(getRVA() + 2); +void ImportThunkChunkX86::getBaserels(std::vector *Res) { + Res->emplace_back(getRVA() + 2); } -void ImportThunkChunkX86::writeTo(uint8_t *buf) const { - memcpy(buf, importThunkX86, sizeof(importThunkX86)); +void ImportThunkChunkX86::writeTo(uint8_t *Buf) const { + memcpy(Buf, ImportThunkX86, sizeof(ImportThunkX86)); // The first two bytes is a JMP instruction. Fill its operand. - write32le(buf + 2, - impSymbol->getRVA() + config->imageBase); + write32le(Buf + 2, + ImpSymbol->getRVA() + Config->ImageBase); } -void ImportThunkChunkARM::getBaserels(std::vector *res) { - res->emplace_back(getRVA(), IMAGE_REL_BASED_ARM_MOV32T); +void ImportThunkChunkARM::getBaserels(std::vector *Res) { + Res->emplace_back(getRVA(), IMAGE_REL_BASED_ARM_MOV32T); } -void ImportThunkChunkARM::writeTo(uint8_t *buf) const { - memcpy(buf, importThunkARM, sizeof(importThunkARM)); +void ImportThunkChunkARM::writeTo(uint8_t *Buf) const { + memcpy(Buf, ImportThunkARM, sizeof(ImportThunkARM)); // Fix mov.w and mov.t operands. - applyMOV32T(buf, impSymbol->getRVA() + config->imageBase); + applyMOV32T(Buf, ImpSymbol->getRVA() + Config->ImageBase); } -void ImportThunkChunkARM64::writeTo(uint8_t *buf) const { - int64_t off = impSymbol->getRVA() & 0xfff; - memcpy(buf, importThunkARM64, sizeof(importThunkARM64)); - applyArm64Addr(buf, impSymbol->getRVA(), rva, 12); - applyArm64Ldr(buf + 4, off); +void ImportThunkChunkARM64::writeTo(uint8_t *Buf) const { + int64_t Off = ImpSymbol->getRVA() & 0xfff; + memcpy(Buf, ImportThunkARM64, sizeof(ImportThunkARM64)); + applyArm64Addr(Buf, ImpSymbol->getRVA(), RVA, 12); + applyArm64Ldr(Buf + 4, Off); } // A Thumb2, PIC, non-interworking range extension thunk. -const uint8_t armThunk[] = { +const uint8_t ArmThunk[] = { 0x40, 0xf2, 0x00, 0x0c, // P: movw ip,:lower16:S - (P + (L1-P) + 4) 0xc0, 0xf2, 0x00, 0x0c, // movt ip,:upper16:S - (P + (L1-P) + 4) 0xe7, 0x44, // L1: add pc, ip }; size_t RangeExtensionThunkARM::getSize() const { - assert(config->machine == ARMNT); - return sizeof(armThunk); + assert(Config->Machine == ARMNT); + return sizeof(ArmThunk); } -void RangeExtensionThunkARM::writeTo(uint8_t *buf) const { - assert(config->machine == ARMNT); - uint64_t offset = target->getRVA() - rva - 12; - memcpy(buf, armThunk, sizeof(armThunk)); - applyMOV32T(buf, uint32_t(offset)); +void RangeExtensionThunkARM::writeTo(uint8_t *Buf) const { + assert(Config->Machine == ARMNT); + uint64_t Offset = Target->getRVA() - RVA - 12; + memcpy(Buf, ArmThunk, sizeof(ArmThunk)); + applyMOV32T(Buf, uint32_t(Offset)); } // A position independent ARM64 adrp+add thunk, with a maximum range of // +/- 4 GB, which is enough for any PE-COFF. -const uint8_t arm64Thunk[] = { +const uint8_t Arm64Thunk[] = { 0x10, 0x00, 0x00, 0x90, // adrp x16, Dest 0x10, 0x02, 0x00, 0x91, // add x16, x16, :lo12:Dest 0x00, 0x02, 0x1f, 0xd6, // br x16 }; size_t RangeExtensionThunkARM64::getSize() const { - assert(config->machine == ARM64); - return sizeof(arm64Thunk); + assert(Config->Machine == ARM64); + return sizeof(Arm64Thunk); } -void RangeExtensionThunkARM64::writeTo(uint8_t *buf) const { - assert(config->machine == ARM64); - memcpy(buf, arm64Thunk, sizeof(arm64Thunk)); - applyArm64Addr(buf + 0, target->getRVA(), rva, 12); - applyArm64Imm(buf + 4, target->getRVA() & 0xfff, 0); +void RangeExtensionThunkARM64::writeTo(uint8_t *Buf) const { + assert(Config->Machine == ARM64); + memcpy(Buf, Arm64Thunk, sizeof(Arm64Thunk)); + applyArm64Addr(Buf + 0, Target->getRVA(), RVA, 12); + applyArm64Imm(Buf + 4, Target->getRVA() & 0xfff, 0); } -void LocalImportChunk::getBaserels(std::vector *res) { - res->emplace_back(getRVA()); +void LocalImportChunk::getBaserels(std::vector *Res) { + Res->emplace_back(getRVA()); } -size_t LocalImportChunk::getSize() const { return config->wordsize; } +size_t LocalImportChunk::getSize() const { return Config->Wordsize; } -void LocalImportChunk::writeTo(uint8_t *buf) const { - if (config->is64()) { - write64le(buf, sym->getRVA() + config->imageBase); +void LocalImportChunk::writeTo(uint8_t *Buf) const { + if (Config->is64()) { + write64le(Buf, Sym->getRVA() + Config->ImageBase); } else { - write32le(buf, sym->getRVA() + config->imageBase); + write32le(Buf, Sym->getRVA() + Config->ImageBase); } } -void RVATableChunk::writeTo(uint8_t *buf) const { - ulittle32_t *begin = reinterpret_cast(buf); - size_t cnt = 0; - for (const ChunkAndOffset &co : syms) - begin[cnt++] = co.inputChunk->getRVA() + co.offset; - std::sort(begin, begin + cnt); - assert(std::unique(begin, begin + cnt) == begin + cnt && +void RVATableChunk::writeTo(uint8_t *Buf) const { + ulittle32_t *Begin = reinterpret_cast(Buf); + size_t Cnt = 0; + for (const ChunkAndOffset &CO : Syms) + Begin[Cnt++] = CO.InputChunk->getRVA() + CO.Offset; + std::sort(Begin, Begin + Cnt); + assert(std::unique(Begin, Begin + Cnt) == Begin + Cnt && "RVA tables should be de-duplicated"); } // MinGW specific, for the "automatic import of variables from DLLs" feature. size_t PseudoRelocTableChunk::getSize() const { - if (relocs.empty()) + if (Relocs.empty()) return 0; - return 12 + 12 * relocs.size(); + return 12 + 12 * Relocs.size(); } // MinGW specific. -void PseudoRelocTableChunk::writeTo(uint8_t *buf) const { - if (relocs.empty()) +void PseudoRelocTableChunk::writeTo(uint8_t *Buf) const { + if (Relocs.empty()) return; - ulittle32_t *table = reinterpret_cast(buf); + ulittle32_t *Table = reinterpret_cast(Buf); // This is the list header, to signal the runtime pseudo relocation v2 // format. - table[0] = 0; - table[1] = 0; - table[2] = 1; - - size_t idx = 3; - for (const RuntimePseudoReloc &rpr : relocs) { - table[idx + 0] = rpr.sym->getRVA(); - table[idx + 1] = rpr.target->getRVA() + rpr.targetOffset; - table[idx + 2] = rpr.flags; - idx += 3; + Table[0] = 0; + Table[1] = 0; + Table[2] = 1; + + size_t Idx = 3; + for (const RuntimePseudoReloc &RPR : Relocs) { + Table[Idx + 0] = RPR.Sym->getRVA(); + Table[Idx + 1] = RPR.Target->getRVA() + RPR.TargetOffset; + Table[Idx + 2] = RPR.Flags; + Idx += 3; } } @@ -829,26 +829,26 @@ void PseudoRelocTableChunk::writeTo(uint8_t *buf) const { // // Usually we have a lot of relocations for each page, so the number of // bytes for one .reloc entry is close to 2 bytes on average. -BaserelChunk::BaserelChunk(uint32_t page, Baserel *begin, Baserel *end) { +BaserelChunk::BaserelChunk(uint32_t Page, Baserel *Begin, Baserel *End) { // Block header consists of 4 byte page RVA and 4 byte block size. // Each entry is 2 byte. Last entry may be padding. - data.resize(alignTo((end - begin) * 2 + 8, 4)); - uint8_t *p = data.data(); - write32le(p, page); - write32le(p + 4, data.size()); - p += 8; - for (Baserel *i = begin; i != end; ++i) { - write16le(p, (i->type << 12) | (i->rva - page)); - p += 2; + Data.resize(alignTo((End - Begin) * 2 + 8, 4)); + uint8_t *P = Data.data(); + write32le(P, Page); + write32le(P + 4, Data.size()); + P += 8; + for (Baserel *I = Begin; I != End; ++I) { + write16le(P, (I->Type << 12) | (I->RVA - Page)); + P += 2; } } -void BaserelChunk::writeTo(uint8_t *buf) const { - memcpy(buf, data.data(), data.size()); +void BaserelChunk::writeTo(uint8_t *Buf) const { + memcpy(Buf, Data.data(), Data.size()); } uint8_t Baserel::getDefaultType() { - switch (config->machine) { + switch (Config->Machine) { case AMD64: case ARM64: return IMAGE_REL_BASED_DIR64; @@ -860,38 +860,38 @@ uint8_t Baserel::getDefaultType() { } } -MergeChunk *MergeChunk::instances[Log2MaxSectionAlignment + 1] = {}; +MergeChunk *MergeChunk::Instances[Log2MaxSectionAlignment + 1] = {}; -MergeChunk::MergeChunk(uint32_t alignment) - : builder(StringTableBuilder::RAW, alignment) { - setAlignment(alignment); +MergeChunk::MergeChunk(uint32_t Alignment) + : Builder(StringTableBuilder::RAW, Alignment) { + setAlignment(Alignment); } -void MergeChunk::addSection(SectionChunk *c) { - assert(isPowerOf2_32(c->getAlignment())); - uint8_t p2Align = llvm::Log2_32(c->getAlignment()); - assert(p2Align < array_lengthof(instances)); - auto *&mc = instances[p2Align]; - if (!mc) - mc = make(c->getAlignment()); - mc->sections.push_back(c); +void MergeChunk::addSection(SectionChunk *C) { + assert(isPowerOf2_32(C->getAlignment())); + uint8_t P2Align = llvm::Log2_32(C->getAlignment()); + assert(P2Align < array_lengthof(Instances)); + auto *&MC = Instances[P2Align]; + if (!MC) + MC = make(C->getAlignment()); + MC->Sections.push_back(C); } void MergeChunk::finalizeContents() { - assert(!finalized && "should only finalize once"); - for (SectionChunk *c : sections) - if (c->live) - builder.add(toStringRef(c->getContents())); - builder.finalize(); - finalized = true; + assert(!Finalized && "should only finalize once"); + for (SectionChunk *C : Sections) + if (C->Live) + Builder.add(toStringRef(C->getContents())); + Builder.finalize(); + Finalized = true; } void MergeChunk::assignSubsectionRVAs() { - for (SectionChunk *c : sections) { - if (!c->live) + for (SectionChunk *C : Sections) { + if (!C->Live) continue; - size_t off = builder.getOffset(toStringRef(c->getContents())); - c->setRVA(rva + off); + size_t Off = Builder.getOffset(toStringRef(C->getContents())); + C->setRVA(RVA + Off); } } @@ -900,21 +900,21 @@ uint32_t MergeChunk::getOutputCharacteristics() const { } size_t MergeChunk::getSize() const { - return builder.getSize(); + return Builder.getSize(); } -void MergeChunk::writeTo(uint8_t *buf) const { - builder.write(buf); +void MergeChunk::writeTo(uint8_t *Buf) const { + Builder.write(Buf); } // MinGW specific. -size_t AbsolutePointerChunk::getSize() const { return config->wordsize; } +size_t AbsolutePointerChunk::getSize() const { return Config->Wordsize; } -void AbsolutePointerChunk::writeTo(uint8_t *buf) const { - if (config->is64()) { - write64le(buf, value); +void AbsolutePointerChunk::writeTo(uint8_t *Buf) const { + if (Config->is64()) { + write64le(Buf, Value); } else { - write32le(buf, value); + write32le(Buf, Value); } } diff --git a/lld/COFF/Chunks.h b/lld/COFF/Chunks.h index 6bb629fe998b36..0df168be771271 100644 --- a/lld/COFF/Chunks.h +++ b/lld/COFF/Chunks.h @@ -40,10 +40,10 @@ class RuntimePseudoReloc; class Symbol; // Mask for permissions (discardable, writable, readable, executable, etc). -const uint32_t permMask = 0xFE000000; +const uint32_t PermMask = 0xFE000000; // Mask for section types (code, data, bss). -const uint32_t typeMask = 0x000000E0; +const uint32_t TypeMask = 0x000000E0; // The log base 2 of the largest section alignment, which is log2(8192), or 13. enum : unsigned { Log2MaxSectionAlignment = 13 }; @@ -55,23 +55,23 @@ enum : unsigned { Log2MaxSectionAlignment = 13 }; class Chunk { public: enum Kind : uint8_t { SectionKind, OtherKind, ImportThunkKind }; - Kind kind() const { return chunkKind; } + Kind kind() const { return ChunkKind; } // Returns the size of this chunk (even if this is a common or BSS.) size_t getSize() const; // Returns chunk alignment in power of two form. Value values are powers of // two from 1 to 8192. - uint32_t getAlignment() const { return 1U << p2Align; } + uint32_t getAlignment() const { return 1U << P2Align; } // Update the chunk section alignment measured in bytes. Internally alignment // is stored in log2. - void setAlignment(uint32_t align) { + void setAlignment(uint32_t Align) { // Treat zero byte alignment as 1 byte alignment. - align = align ? align : 1; - assert(llvm::isPowerOf2_32(align) && "alignment is not a power of 2"); - p2Align = llvm::Log2_32(align); - assert(p2Align <= Log2MaxSectionAlignment && + Align = Align ? Align : 1; + assert(llvm::isPowerOf2_32(Align) && "alignment is not a power of 2"); + P2Align = llvm::Log2_32(Align); + assert(P2Align <= Log2MaxSectionAlignment && "impossible requested alignment"); } @@ -79,17 +79,22 @@ class Chunk { // beginning of the file. Because this function may use RVA values // of other chunks for relocations, you need to set them properly // before calling this function. - void writeTo(uint8_t *buf) const; + void writeTo(uint8_t *Buf) const; // The writer sets and uses the addresses. In practice, PE images cannot be // larger than 2GB. Chunks are always laid as part of the image, so Chunk RVAs // can be stored with 32 bits. - uint32_t getRVA() const { return rva; } - void setRVA(uint64_t v) { - rva = (uint32_t)v; - assert(rva == v && "RVA truncated"); + uint32_t getRVA() const { return RVA; } + void setRVA(uint64_t V) { + RVA = (uint32_t)V; + assert(RVA == V && "RVA truncated"); } + // Returns true if this has non-zero data. BSS chunks return + // false. If false is returned, the space occupied by this chunk + // will be filled with zeros. + bool hasData() const { return HasData; } + // Returns readable/writable/executable bits. uint32_t getOutputCharacteristics() const; @@ -99,13 +104,13 @@ class Chunk { // An output section has pointers to chunks in the section, and each // chunk has a back pointer to an output section. - void setOutputSectionIdx(uint16_t o) { osidx = o; } - uint16_t getOutputSectionIdx() const { return osidx; } + void setOutputSectionIdx(uint16_t O) { OSIdx = O; } + uint16_t getOutputSectionIdx() const { return OSIdx; } OutputSection *getOutputSection() const; // Windows-specific. // Collect all locations that contain absolute addresses for base relocations. - void getBaserels(std::vector *res); + void getBaserels(std::vector *Res); // Returns a human-readable name of this chunk. Chunks are unnamed chunks of // bytes, so this is used only for logging or debugging. @@ -117,28 +122,24 @@ class Chunk { bool isHotPatchable() const; protected: - Chunk(Kind k = OtherKind) : chunkKind(k), hasData(true), p2Align(0) {} + Chunk(Kind K = OtherKind) : ChunkKind(K), HasData(true), P2Align(0) {} - const Kind chunkKind; + const Kind ChunkKind; -public: - // Returns true if this has non-zero data. BSS chunks return - // false. If false is returned, the space occupied by this chunk - // will be filled with zeros. Corresponds to the + // True if the section has data. Corresponds to the // IMAGE_SCN_CNT_UNINITIALIZED_DATA section characteristic bit. - uint8_t hasData : 1; + uint8_t HasData : 1; -public: // The alignment of this chunk, stored in log2 form. The writer uses the // value. - uint8_t p2Align : 7; + uint8_t P2Align : 7; // The output section index for this chunk. The first valid section number is // one. - uint16_t osidx = 0; + uint16_t OSIdx = 0; // The RVA of this chunk in the output. The writer sets a value. - uint32_t rva = 0; + uint32_t RVA = 0; }; class NonSectionChunk : public Chunk { @@ -154,7 +155,7 @@ class NonSectionChunk : public Chunk { // beginning of the file. Because this function may use RVA values // of other chunks for relocations, you need to set them properly // before calling this function. - virtual void writeTo(uint8_t *buf) const {} + virtual void writeTo(uint8_t *Buf) const {} // Returns the section name if this is a section chunk. // It is illegal to call this function on non-section chunks. @@ -164,16 +165,16 @@ class NonSectionChunk : public Chunk { // Windows-specific. // Collect all locations that contain absolute addresses for base relocations. - virtual void getBaserels(std::vector *res) {} + virtual void getBaserels(std::vector *Res) {} // Returns a human-readable name of this chunk. Chunks are unnamed chunks of // bytes, so this is used only for logging or debugging. virtual StringRef getDebugName() const { return ""; } - static bool classof(const Chunk *c) { return c->kind() != SectionKind; } + static bool classof(const Chunk *C) { return C->kind() != SectionKind; } protected: - NonSectionChunk(Kind k = OtherKind) : Chunk(k) {} + NonSectionChunk(Kind K = OtherKind) : Chunk(K) {} }; // A chunk corresponding a section of an input file. @@ -187,41 +188,41 @@ class SectionChunk final : public Chunk { std::random_access_iterator_tag, Symbol *> { friend SectionChunk; - ObjFile *file; + ObjFile *File; - symbol_iterator(ObjFile *file, const coff_relocation *i) - : symbol_iterator::iterator_adaptor_base(i), file(file) {} + symbol_iterator(ObjFile *File, const coff_relocation *I) + : symbol_iterator::iterator_adaptor_base(I), File(File) {} public: symbol_iterator() = default; - Symbol *operator*() const { return file->getSymbol(I->SymbolTableIndex); } + Symbol *operator*() const { return File->getSymbol(I->SymbolTableIndex); } }; - SectionChunk(ObjFile *file, const coff_section *header); - static bool classof(const Chunk *c) { return c->kind() == SectionKind; } - size_t getSize() const { return header->SizeOfRawData; } + SectionChunk(ObjFile *File, const coff_section *Header); + static bool classof(const Chunk *C) { return C->kind() == SectionKind; } + size_t getSize() const { return Header->SizeOfRawData; } ArrayRef getContents() const; - void writeTo(uint8_t *buf) const; + void writeTo(uint8_t *Buf) const; uint32_t getOutputCharacteristics() const { - return header->Characteristics & (permMask | typeMask); + return Header->Characteristics & (PermMask | TypeMask); } StringRef getSectionName() const { - return StringRef(sectionNameData, sectionNameSize); + return StringRef(SectionNameData, SectionNameSize); } - void getBaserels(std::vector *res); + void getBaserels(std::vector *Res); bool isCOMDAT() const; - void applyRelX64(uint8_t *off, uint16_t type, OutputSection *os, uint64_t s, - uint64_t p) const; - void applyRelX86(uint8_t *off, uint16_t type, OutputSection *os, uint64_t s, - uint64_t p) const; - void applyRelARM(uint8_t *off, uint16_t type, OutputSection *os, uint64_t s, - uint64_t p) const; - void applyRelARM64(uint8_t *off, uint16_t type, OutputSection *os, uint64_t s, - uint64_t p) const; + void applyRelX64(uint8_t *Off, uint16_t Type, OutputSection *OS, uint64_t S, + uint64_t P) const; + void applyRelX86(uint8_t *Off, uint16_t Type, OutputSection *OS, uint64_t S, + uint64_t P) const; + void applyRelARM(uint8_t *Off, uint16_t Type, OutputSection *OS, uint64_t S, + uint64_t P) const; + void applyRelARM64(uint8_t *Off, uint16_t Type, OutputSection *OS, uint64_t S, + uint64_t P) const; - void getRuntimePseudoRelocs(std::vector &res); + void getRuntimePseudoRelocs(std::vector &Res); // Called if the garbage collector decides to not include this chunk // in a final output. It's supposed to print out a log message to stdout. @@ -229,7 +230,7 @@ class SectionChunk final : public Chunk { // Adds COMDAT associative sections to this COMDAT section. A chunk // and its children are treated as a group by the garbage collector. - void addAssociative(SectionChunk *child); + void addAssociative(SectionChunk *Child); StringRef getDebugName() const; @@ -246,19 +247,19 @@ class SectionChunk final : public Chunk { // Allow iteration over the bodies of this chunk's relocated symbols. llvm::iterator_range symbols() const { - return llvm::make_range(symbol_iterator(file, relocsData), - symbol_iterator(file, relocsData + relocsSize)); + return llvm::make_range(symbol_iterator(File, RelocsData), + symbol_iterator(File, RelocsData + RelocsSize)); } ArrayRef getRelocs() const { - return llvm::makeArrayRef(relocsData, relocsSize); + return llvm::makeArrayRef(RelocsData, RelocsSize); } // Reloc setter used by ARM range extension thunk insertion. - void setRelocs(ArrayRef newRelocs) { - relocsData = newRelocs.data(); - relocsSize = newRelocs.size(); - assert(relocsSize == newRelocs.size() && "reloc size truncation"); + void setRelocs(ArrayRef NewRelocs) { + RelocsData = NewRelocs.data(); + RelocsSize = NewRelocs.size(); + assert(RelocsSize == NewRelocs.size() && "reloc size truncation"); } // Single linked list iterator for associated comdat children. @@ -267,26 +268,26 @@ class SectionChunk final : public Chunk { AssociatedIterator, std::forward_iterator_tag, SectionChunk> { public: AssociatedIterator() = default; - AssociatedIterator(SectionChunk *head) : cur(head) {} - AssociatedIterator &operator=(const AssociatedIterator &r) { - cur = r.cur; + AssociatedIterator(SectionChunk *Head) : Cur(Head) {} + AssociatedIterator &operator=(const AssociatedIterator &R) { + Cur = R.Cur; return *this; } - bool operator==(const AssociatedIterator &r) const { return cur == r.cur; } - const SectionChunk &operator*() const { return *cur; } - SectionChunk &operator*() { return *cur; } + bool operator==(const AssociatedIterator &R) const { return Cur == R.Cur; } + const SectionChunk &operator*() const { return *Cur; } + SectionChunk &operator*() { return *Cur; } AssociatedIterator &operator++() { - cur = cur->assocChildren; + Cur = Cur->AssocChildren; return *this; } private: - SectionChunk *cur = nullptr; + SectionChunk *Cur = nullptr; }; // Allow iteration over the associated child chunks for this section. llvm::iterator_range children() const { - return llvm::make_range(AssociatedIterator(assocChildren), + return llvm::make_range(AssociatedIterator(AssocChildren), AssociatedIterator(nullptr)); } @@ -295,56 +296,56 @@ class SectionChunk final : public Chunk { ArrayRef consumeDebugMagic(); - static ArrayRef consumeDebugMagic(ArrayRef data, - StringRef sectionName); + static ArrayRef consumeDebugMagic(ArrayRef Data, + StringRef SectionName); - static SectionChunk *findByName(ArrayRef sections, - StringRef name); + static SectionChunk *findByName(ArrayRef Sections, + StringRef Name); // The file that this chunk was created from. - ObjFile *file; + ObjFile *File; // Pointer to the COFF section header in the input file. - const coff_section *header; + const coff_section *Header; // The COMDAT leader symbol if this is a COMDAT chunk. - DefinedRegular *sym = nullptr; + DefinedRegular *Sym = nullptr; // The CRC of the contents as described in the COFF spec 4.5.5. // Auxiliary Format 5: Section Definitions. Used for ICF. - uint32_t checksum = 0; + uint32_t Checksum = 0; // Used by the garbage collector. - bool live; + bool Live; // Whether this section needs to be kept distinct from other sections during // ICF. This is set by the driver using address-significance tables. - bool keepUnique = false; + bool KeepUnique = false; // The COMDAT selection if this is a COMDAT chunk. - llvm::COFF::COMDATType selection = (llvm::COFF::COMDATType)0; + llvm::COFF::COMDATType Selection = (llvm::COFF::COMDATType)0; // A pointer pointing to a replacement for this chunk. // Initially it points to "this" object. If this chunk is merged // with other chunk by ICF, it points to another chunk, // and this chunk is considered as dead. - SectionChunk *repl; + SectionChunk *Repl; private: - SectionChunk *assocChildren = nullptr; + SectionChunk *AssocChildren = nullptr; // Used for ICF (Identical COMDAT Folding) - void replace(SectionChunk *other); - uint32_t eqClass[2] = {0, 0}; + void replace(SectionChunk *Other); + uint32_t Class[2] = {0, 0}; // Relocations for this section. Size is stored below. - const coff_relocation *relocsData; + const coff_relocation *RelocsData; // Section name string. Size is stored below. - const char *sectionNameData; + const char *SectionNameData; - uint32_t relocsSize = 0; - uint32_t sectionNameSize = 0; + uint32_t RelocsSize = 0; + uint32_t SectionNameSize = 0; }; // Inline methods to implement faux-virtual dispatch for SectionChunk. @@ -364,11 +365,11 @@ inline uint32_t Chunk::getOutputCharacteristics() const { ->getOutputCharacteristics(); } -inline void Chunk::writeTo(uint8_t *buf) const { +inline void Chunk::writeTo(uint8_t *Buf) const { if (isa(this)) - static_cast(this)->writeTo(buf); + static_cast(this)->writeTo(Buf); else - static_cast(this)->writeTo(buf); + static_cast(this)->writeTo(Buf); } inline StringRef Chunk::getSectionName() const { @@ -378,11 +379,11 @@ inline StringRef Chunk::getSectionName() const { return static_cast(this)->getSectionName(); } -inline void Chunk::getBaserels(std::vector *res) { +inline void Chunk::getBaserels(std::vector *Res) { if (isa(this)) - static_cast(this)->getBaserels(res); + static_cast(this)->getBaserels(Res); else - static_cast(this)->getBaserels(res); + static_cast(this)->getBaserels(Res); } inline StringRef Chunk::getDebugName() const { @@ -403,58 +404,58 @@ inline StringRef Chunk::getDebugName() const { // on the offsets assigned by the StringTableBuilder. class MergeChunk : public NonSectionChunk { public: - MergeChunk(uint32_t alignment); - static void addSection(SectionChunk *c); + MergeChunk(uint32_t Alignment); + static void addSection(SectionChunk *C); void finalizeContents(); void assignSubsectionRVAs(); uint32_t getOutputCharacteristics() const override; StringRef getSectionName() const override { return ".rdata"; } size_t getSize() const override; - void writeTo(uint8_t *buf) const override; + void writeTo(uint8_t *Buf) const override; - static MergeChunk *instances[Log2MaxSectionAlignment + 1]; - std::vector sections; + static MergeChunk *Instances[Log2MaxSectionAlignment + 1]; + std::vector Sections; private: - llvm::StringTableBuilder builder; - bool finalized = false; + llvm::StringTableBuilder Builder; + bool Finalized = false; }; // A chunk for common symbols. Common chunks don't have actual data. class CommonChunk : public NonSectionChunk { public: - CommonChunk(const COFFSymbolRef sym); - size_t getSize() const override { return sym.getValue(); } + CommonChunk(const COFFSymbolRef Sym); + size_t getSize() const override { return Sym.getValue(); } uint32_t getOutputCharacteristics() const override; StringRef getSectionName() const override { return ".bss"; } private: - const COFFSymbolRef sym; + const COFFSymbolRef Sym; }; // A chunk for linker-created strings. class StringChunk : public NonSectionChunk { public: - explicit StringChunk(StringRef s) : str(s) {} - size_t getSize() const override { return str.size() + 1; } - void writeTo(uint8_t *buf) const override; + explicit StringChunk(StringRef S) : Str(S) {} + size_t getSize() const override { return Str.size() + 1; } + void writeTo(uint8_t *Buf) const override; private: - StringRef str; + StringRef Str; }; -static const uint8_t importThunkX86[] = { +static const uint8_t ImportThunkX86[] = { 0xff, 0x25, 0x00, 0x00, 0x00, 0x00, // JMP *0x0 }; -static const uint8_t importThunkARM[] = { +static const uint8_t ImportThunkARM[] = { 0x40, 0xf2, 0x00, 0x0c, // mov.w ip, #0 0xc0, 0xf2, 0x00, 0x0c, // mov.t ip, #0 0xdc, 0xf8, 0x00, 0xf0, // ldr.w pc, [ip] }; -static const uint8_t importThunkARM64[] = { +static const uint8_t ImportThunkARM64[] = { 0x10, 0x00, 0x00, 0x90, // adrp x16, #0 0x10, 0x02, 0x40, 0xf9, // ldr x16, [x16] 0x00, 0x02, 0x1f, 0xd6, // br x16 @@ -465,83 +466,83 @@ static const uint8_t importThunkARM64[] = { // contents will be a JMP instruction to some __imp_ symbol. class ImportThunkChunk : public NonSectionChunk { public: - ImportThunkChunk(Defined *s) - : NonSectionChunk(ImportThunkKind), impSymbol(s) {} - static bool classof(const Chunk *c) { return c->kind() == ImportThunkKind; } + ImportThunkChunk(Defined *S) + : NonSectionChunk(ImportThunkKind), ImpSymbol(S) {} + static bool classof(const Chunk *C) { return C->kind() == ImportThunkKind; } protected: - Defined *impSymbol; + Defined *ImpSymbol; }; class ImportThunkChunkX64 : public ImportThunkChunk { public: - explicit ImportThunkChunkX64(Defined *s); - size_t getSize() const override { return sizeof(importThunkX86); } - void writeTo(uint8_t *buf) const override; + explicit ImportThunkChunkX64(Defined *S); + size_t getSize() const override { return sizeof(ImportThunkX86); } + void writeTo(uint8_t *Buf) const override; }; class ImportThunkChunkX86 : public ImportThunkChunk { public: - explicit ImportThunkChunkX86(Defined *s) : ImportThunkChunk(s) {} - size_t getSize() const override { return sizeof(importThunkX86); } - void getBaserels(std::vector *res) override; - void writeTo(uint8_t *buf) const override; + explicit ImportThunkChunkX86(Defined *S) : ImportThunkChunk(S) {} + size_t getSize() const override { return sizeof(ImportThunkX86); } + void getBaserels(std::vector *Res) override; + void writeTo(uint8_t *Buf) const override; }; class ImportThunkChunkARM : public ImportThunkChunk { public: - explicit ImportThunkChunkARM(Defined *s) : ImportThunkChunk(s) {} - size_t getSize() const override { return sizeof(importThunkARM); } - void getBaserels(std::vector *res) override; - void writeTo(uint8_t *buf) const override; + explicit ImportThunkChunkARM(Defined *S) : ImportThunkChunk(S) {} + size_t getSize() const override { return sizeof(ImportThunkARM); } + void getBaserels(std::vector *Res) override; + void writeTo(uint8_t *Buf) const override; }; class ImportThunkChunkARM64 : public ImportThunkChunk { public: - explicit ImportThunkChunkARM64(Defined *s) : ImportThunkChunk(s) {} - size_t getSize() const override { return sizeof(importThunkARM64); } - void writeTo(uint8_t *buf) const override; + explicit ImportThunkChunkARM64(Defined *S) : ImportThunkChunk(S) {} + size_t getSize() const override { return sizeof(ImportThunkARM64); } + void writeTo(uint8_t *Buf) const override; }; class RangeExtensionThunkARM : public NonSectionChunk { public: - explicit RangeExtensionThunkARM(Defined *t) : target(t) {} + explicit RangeExtensionThunkARM(Defined *T) : Target(T) {} size_t getSize() const override; - void writeTo(uint8_t *buf) const override; + void writeTo(uint8_t *Buf) const override; - Defined *target; + Defined *Target; }; class RangeExtensionThunkARM64 : public NonSectionChunk { public: - explicit RangeExtensionThunkARM64(Defined *t) : target(t) {} + explicit RangeExtensionThunkARM64(Defined *T) : Target(T) {} size_t getSize() const override; - void writeTo(uint8_t *buf) const override; + void writeTo(uint8_t *Buf) const override; - Defined *target; + Defined *Target; }; // Windows-specific. // See comments for DefinedLocalImport class. class LocalImportChunk : public NonSectionChunk { public: - explicit LocalImportChunk(Defined *s) : sym(s) { - setAlignment(config->wordsize); + explicit LocalImportChunk(Defined *S) : Sym(S) { + setAlignment(Config->Wordsize); } size_t getSize() const override; - void getBaserels(std::vector *res) override; - void writeTo(uint8_t *buf) const override; + void getBaserels(std::vector *Res) override; + void writeTo(uint8_t *Buf) const override; private: - Defined *sym; + Defined *Sym; }; // Duplicate RVAs are not allowed in RVA tables, so unique symbols by chunk and // offset into the chunk. Order does not matter as the RVA table will be sorted // later. struct ChunkAndOffset { - Chunk *inputChunk; - uint32_t offset; + Chunk *InputChunk; + uint32_t Offset; struct DenseMapInfo { static ChunkAndOffset getEmptyKey() { @@ -550,12 +551,12 @@ struct ChunkAndOffset { static ChunkAndOffset getTombstoneKey() { return {llvm::DenseMapInfo::getTombstoneKey(), 0}; } - static unsigned getHashValue(const ChunkAndOffset &co) { + static unsigned getHashValue(const ChunkAndOffset &CO) { return llvm::DenseMapInfo>::getHashValue( - {co.inputChunk, co.offset}); + {CO.InputChunk, CO.Offset}); } - static bool isEqual(const ChunkAndOffset &lhs, const ChunkAndOffset &rhs) { - return lhs.inputChunk == rhs.inputChunk && lhs.offset == rhs.offset; + static bool isEqual(const ChunkAndOffset &LHS, const ChunkAndOffset &RHS) { + return LHS.InputChunk == RHS.InputChunk && LHS.Offset == RHS.Offset; } }; }; @@ -565,12 +566,12 @@ using SymbolRVASet = llvm::DenseSet; // Table which contains symbol RVAs. Used for /safeseh and /guard:cf. class RVATableChunk : public NonSectionChunk { public: - explicit RVATableChunk(SymbolRVASet s) : syms(std::move(s)) {} - size_t getSize() const override { return syms.size() * 4; } - void writeTo(uint8_t *buf) const override; + explicit RVATableChunk(SymbolRVASet S) : Syms(std::move(S)) {} + size_t getSize() const override { return Syms.size() * 4; } + void writeTo(uint8_t *Buf) const override; private: - SymbolRVASet syms; + SymbolRVASet Syms; }; // Windows-specific. @@ -578,22 +579,22 @@ class RVATableChunk : public NonSectionChunk { // See the PE/COFF spec 5.6 for details. class BaserelChunk : public NonSectionChunk { public: - BaserelChunk(uint32_t page, Baserel *begin, Baserel *end); - size_t getSize() const override { return data.size(); } - void writeTo(uint8_t *buf) const override; + BaserelChunk(uint32_t Page, Baserel *Begin, Baserel *End); + size_t getSize() const override { return Data.size(); } + void writeTo(uint8_t *Buf) const override; private: - std::vector data; + std::vector Data; }; class Baserel { public: - Baserel(uint32_t v, uint8_t ty) : rva(v), type(ty) {} - explicit Baserel(uint32_t v) : Baserel(v, getDefaultType()) {} + Baserel(uint32_t V, uint8_t Ty) : RVA(V), Type(Ty) {} + explicit Baserel(uint32_t V) : Baserel(V, getDefaultType()) {} uint8_t getDefaultType(); - uint32_t rva; - uint8_t type; + uint32_t RVA; + uint8_t Type; }; // This is a placeholder Chunk, to allow attaching a DefinedSynthetic to a @@ -604,7 +605,7 @@ class EmptyChunk : public NonSectionChunk { public: EmptyChunk() {} size_t getSize() const override { return 0; } - void writeTo(uint8_t *buf) const override {} + void writeTo(uint8_t *Buf) const override {} }; // MinGW specific, for the "automatic import of variables from DLLs" feature. @@ -615,15 +616,15 @@ class EmptyChunk : public NonSectionChunk { // code. class PseudoRelocTableChunk : public NonSectionChunk { public: - PseudoRelocTableChunk(std::vector &relocs) - : relocs(std::move(relocs)) { + PseudoRelocTableChunk(std::vector &Relocs) + : Relocs(std::move(Relocs)) { setAlignment(4); } size_t getSize() const override; - void writeTo(uint8_t *buf) const override; + void writeTo(uint8_t *Buf) const override; private: - std::vector relocs; + std::vector Relocs; }; // MinGW specific; information about one individual location in the image @@ -631,48 +632,48 @@ class PseudoRelocTableChunk : public NonSectionChunk { // one individual element in the PseudoRelocTableChunk table. class RuntimePseudoReloc { public: - RuntimePseudoReloc(Defined *sym, SectionChunk *target, uint32_t targetOffset, - int flags) - : sym(sym), target(target), targetOffset(targetOffset), flags(flags) {} + RuntimePseudoReloc(Defined *Sym, SectionChunk *Target, uint32_t TargetOffset, + int Flags) + : Sym(Sym), Target(Target), TargetOffset(TargetOffset), Flags(Flags) {} - Defined *sym; - SectionChunk *target; - uint32_t targetOffset; + Defined *Sym; + SectionChunk *Target; + uint32_t TargetOffset; // The Flags field contains the size of the relocation, in bits. No other // flags are currently defined. - int flags; + int Flags; }; // MinGW specific. A Chunk that contains one pointer-sized absolute value. class AbsolutePointerChunk : public NonSectionChunk { public: - AbsolutePointerChunk(uint64_t value) : value(value) { + AbsolutePointerChunk(uint64_t Value) : Value(Value) { setAlignment(getSize()); } size_t getSize() const override; - void writeTo(uint8_t *buf) const override; + void writeTo(uint8_t *Buf) const override; private: - uint64_t value; + uint64_t Value; }; // Return true if this file has the hotpatch flag set to true in the S_COMPILE3 // record in codeview debug info. Also returns true for some thunks synthesized // by the linker. inline bool Chunk::isHotPatchable() const { - if (auto *sc = dyn_cast(this)) - return sc->file->hotPatchable; + if (auto *SC = dyn_cast(this)) + return SC->File->HotPatchable; else if (isa(this)) return true; return false; } -void applyMOV32T(uint8_t *off, uint32_t v); -void applyBranch24T(uint8_t *off, int32_t v); +void applyMOV32T(uint8_t *Off, uint32_t V); +void applyBranch24T(uint8_t *Off, int32_t V); -void applyArm64Addr(uint8_t *off, uint64_t s, uint64_t p, int shift); -void applyArm64Imm(uint8_t *off, uint64_t imm, uint32_t rangeLimit); -void applyArm64Branch26(uint8_t *off, int64_t v); +void applyArm64Addr(uint8_t *Off, uint64_t S, uint64_t P, int Shift); +void applyArm64Imm(uint8_t *Off, uint64_t Imm, uint32_t RangeLimit); +void applyArm64Branch26(uint8_t *Off, int64_t V); } // namespace coff } // namespace lld diff --git a/lld/COFF/Config.h b/lld/COFF/Config.h index 309e1fbf99e3be..76ef16a703eec4 100644 --- a/lld/COFF/Config.h +++ b/lld/COFF/Config.h @@ -38,30 +38,30 @@ static const auto I386 = llvm::COFF::IMAGE_FILE_MACHINE_I386; // Represents an /export option. struct Export { - StringRef name; // N in /export:N or /export:E=N - StringRef extName; // E in /export:E=N - Symbol *sym = nullptr; - uint16_t ordinal = 0; - bool noname = false; - bool data = false; - bool isPrivate = false; - bool constant = false; + StringRef Name; // N in /export:N or /export:E=N + StringRef ExtName; // E in /export:E=N + Symbol *Sym = nullptr; + uint16_t Ordinal = 0; + bool Noname = false; + bool Data = false; + bool Private = false; + bool Constant = false; // If an export is a form of /export:foo=dllname.bar, that means // that foo should be exported as an alias to bar in the DLL. - // forwardTo is set to "dllname.bar" part. Usually empty. - StringRef forwardTo; - StringChunk *forwardChunk = nullptr; + // ForwardTo is set to "dllname.bar" part. Usually empty. + StringRef ForwardTo; + StringChunk *ForwardChunk = nullptr; // True if this /export option was in .drectves section. - bool directives = false; - StringRef symbolName; - StringRef exportName; // Name in DLL - - bool operator==(const Export &e) { - return (name == e.name && extName == e.extName && - ordinal == e.ordinal && noname == e.noname && - data == e.data && isPrivate == e.isPrivate); + bool Directives = false; + StringRef SymbolName; + StringRef ExportName; // Name in DLL + + bool operator==(const Export &E) { + return (Name == E.Name && ExtName == E.ExtName && + Ordinal == E.Ordinal && Noname == E.Noname && + Data == E.Data && Private == E.Private); } }; @@ -81,154 +81,137 @@ enum class GuardCFLevel { // Global configuration. struct Configuration { enum ManifestKind { SideBySide, Embed, No }; - bool is64() { return machine == AMD64 || machine == ARM64; } - - llvm::COFF::MachineTypes machine = IMAGE_FILE_MACHINE_UNKNOWN; - size_t wordsize; - bool verbose = false; - WindowsSubsystem subsystem = llvm::COFF::IMAGE_SUBSYSTEM_UNKNOWN; - Symbol *entry = nullptr; - bool noEntry = false; - std::string outputFile; - std::string importName; - bool demangle = true; - bool doGC = true; - bool doICF = true; - bool tailMerge; - bool relocatable = true; - bool forceMultiple = false; - bool forceMultipleRes = false; - bool forceUnresolved = false; - bool debug = false; - bool debugDwarf = false; - bool debugGHashes = false; - bool debugSymtab = false; - bool showTiming = false; - bool showSummary = false; - unsigned debugTypes = static_cast(DebugType::None); - std::vector natvisFiles; - llvm::SmallString<128> pdbAltPath; - llvm::SmallString<128> pdbPath; - llvm::SmallString<128> pdbSourcePath; - std::vector argv; + bool is64() { return Machine == AMD64 || Machine == ARM64; } + + llvm::COFF::MachineTypes Machine = IMAGE_FILE_MACHINE_UNKNOWN; + size_t Wordsize; + bool Verbose = false; + WindowsSubsystem Subsystem = llvm::COFF::IMAGE_SUBSYSTEM_UNKNOWN; + Symbol *Entry = nullptr; + bool NoEntry = false; + std::string OutputFile; + std::string ImportName; + bool Demangle = true; + bool DoGC = true; + bool DoICF = true; + bool TailMerge; + bool Relocatable = true; + bool ForceMultiple = false; + bool ForceMultipleRes = false; + bool ForceUnresolved = false; + bool Debug = false; + bool DebugDwarf = false; + bool DebugGHashes = false; + bool DebugSymtab = false; + bool ShowTiming = false; + bool ShowSummary = false; + unsigned DebugTypes = static_cast(DebugType::None); + std::vector NatvisFiles; + llvm::SmallString<128> PDBAltPath; + llvm::SmallString<128> PDBPath; + llvm::SmallString<128> PDBSourcePath; + std::vector Argv; // Symbols in this set are considered as live by the garbage collector. - std::vector gcroot; + std::vector GCRoot; - std::set noDefaultLibs; - bool noDefaultLibAll = false; + std::set NoDefaultLibs; + bool NoDefaultLibAll = false; // True if we are creating a DLL. - bool dll = false; - StringRef implib; - std::vector exports; - bool hadExplicitExports; - std::set delayLoads; - std::map dllOrder; - Symbol *delayLoadHelper = nullptr; + bool DLL = false; + StringRef Implib; + std::vector Exports; + std::set DelayLoads; + std::map DLLOrder; + Symbol *DelayLoadHelper = nullptr; - bool saveTemps = false; + bool SaveTemps = false; // /guard:cf - GuardCFLevel guardCF = GuardCFLevel::Off; + GuardCFLevel GuardCF = GuardCFLevel::Off; // Used for SafeSEH. - bool safeSEH = false; - Symbol *sehTable = nullptr; - Symbol *sehCount = nullptr; + Symbol *SEHTable = nullptr; + Symbol *SEHCount = nullptr; // Used for /opt:lldlto=N - unsigned ltoo = 2; + unsigned LTOO = 2; // Used for /opt:lldltojobs=N - unsigned thinLTOJobs = 0; + unsigned ThinLTOJobs = 0; // Used for /opt:lldltopartitions=N - unsigned ltoPartitions = 1; + unsigned LTOPartitions = 1; // Used for /opt:lldltocache=path - StringRef ltoCache; + StringRef LTOCache; // Used for /opt:lldltocachepolicy=policy - llvm::CachePruningPolicy ltoCachePolicy; + llvm::CachePruningPolicy LTOCachePolicy; // Used for /merge:from=to (e.g. /merge:.rdata=.text) - std::map merge; + std::map Merge; // Used for /section=.name,{DEKPRSW} to set section attributes. - std::map section; + std::map Section; // Options for manifest files. - ManifestKind manifest = No; - int manifestID = 1; - StringRef manifestDependency; - bool manifestUAC = true; - std::vector manifestInput; - StringRef manifestLevel = "'asInvoker'"; - StringRef manifestUIAccess = "'false'"; - StringRef manifestFile; + ManifestKind Manifest = No; + int ManifestID = 1; + StringRef ManifestDependency; + bool ManifestUAC = true; + std::vector ManifestInput; + StringRef ManifestLevel = "'asInvoker'"; + StringRef ManifestUIAccess = "'false'"; + StringRef ManifestFile; // Used for /aligncomm. - std::map alignComm; + std::map AlignComm; // Used for /failifmismatch. - std::map> mustMatch; + std::map> MustMatch; // Used for /alternatename. - std::map alternateNames; + std::map AlternateNames; // Used for /order. - llvm::StringMap order; + llvm::StringMap Order; // Used for /lldmap. - std::string mapFile; - - // Used for /thinlto-index-only: - llvm::StringRef thinLTOIndexOnlyArg; - - // Used for /thinlto-object-prefix-replace: - std::pair thinLTOPrefixReplace; - - // Used for /thinlto-object-suffix-replace: - std::pair thinLTOObjectSuffixReplace; - - // Used for /lto-obj-path: - llvm::StringRef ltoObjPath; - - uint64_t align = 4096; - uint64_t imageBase = -1; - uint64_t fileAlign = 512; - uint64_t stackReserve = 1024 * 1024; - uint64_t stackCommit = 4096; - uint64_t heapReserve = 1024 * 1024; - uint64_t heapCommit = 4096; - uint32_t majorImageVersion = 0; - uint32_t minorImageVersion = 0; - uint32_t majorOSVersion = 6; - uint32_t minorOSVersion = 0; - uint32_t timestamp = 0; - uint32_t functionPadMin = 0; - bool dynamicBase = true; - bool allowBind = true; - bool nxCompat = true; - bool allowIsolation = true; - bool terminalServerAware = true; - bool largeAddressAware = false; - bool highEntropyVA = false; - bool appContainer = false; - bool mingw = false; - bool warnMissingOrderSymbol = true; - bool warnLocallyDefinedImported = true; - bool warnDebugInfoUnusable = true; - bool incremental = true; - bool integrityCheck = false; - bool killAt = false; - bool repro = false; - bool swaprunCD = false; - bool swaprunNet = false; - bool thinLTOEmitImportsFiles; - bool thinLTOIndexOnly; + std::string MapFile; + + uint64_t ImageBase = -1; + uint64_t FileAlign = 512; + uint64_t StackReserve = 1024 * 1024; + uint64_t StackCommit = 4096; + uint64_t HeapReserve = 1024 * 1024; + uint64_t HeapCommit = 4096; + uint32_t MajorImageVersion = 0; + uint32_t MinorImageVersion = 0; + uint32_t MajorOSVersion = 6; + uint32_t MinorOSVersion = 0; + uint32_t Timestamp = 0; + uint32_t FunctionPadMin = 0; + bool DynamicBase = true; + bool AllowBind = true; + bool NxCompat = true; + bool AllowIsolation = true; + bool TerminalServerAware = true; + bool LargeAddressAware = false; + bool HighEntropyVA = false; + bool AppContainer = false; + bool MinGW = false; + bool WarnMissingOrderSymbol = true; + bool WarnLocallyDefinedImported = true; + bool WarnDebugInfoUnusable = true; + bool Incremental = true; + bool IntegrityCheck = false; + bool KillAt = false; + bool Repro = false; + bool SwaprunCD = false; + bool SwaprunNet = false; }; -extern Configuration *config; +extern Configuration *Config; } // namespace coff } // namespace lld diff --git a/lld/COFF/DLL.cpp b/lld/COFF/DLL.cpp index 210f43fd6c88ce..769f02e7d0d458 100644 --- a/lld/COFF/DLL.cpp +++ b/lld/COFF/DLL.cpp @@ -37,41 +37,41 @@ namespace { // A chunk for the import descriptor table. class HintNameChunk : public NonSectionChunk { public: - HintNameChunk(StringRef n, uint16_t h) : name(n), hint(h) {} + HintNameChunk(StringRef N, uint16_t H) : Name(N), Hint(H) {} size_t getSize() const override { // Starts with 2 byte Hint field, followed by a null-terminated string, // ends with 0 or 1 byte padding. - return alignTo(name.size() + 3, 2); + return alignTo(Name.size() + 3, 2); } - void writeTo(uint8_t *buf) const override { - memset(buf, 0, getSize()); - write16le(buf, hint); - memcpy(buf + 2, name.data(), name.size()); + void writeTo(uint8_t *Buf) const override { + memset(Buf, 0, getSize()); + write16le(Buf, Hint); + memcpy(Buf + 2, Name.data(), Name.size()); } private: - StringRef name; - uint16_t hint; + StringRef Name; + uint16_t Hint; }; // A chunk for the import descriptor table. class LookupChunk : public NonSectionChunk { public: - explicit LookupChunk(Chunk *c) : hintName(c) { - setAlignment(config->wordsize); + explicit LookupChunk(Chunk *C) : HintName(C) { + setAlignment(Config->Wordsize); } - size_t getSize() const override { return config->wordsize; } + size_t getSize() const override { return Config->Wordsize; } - void writeTo(uint8_t *buf) const override { - if (config->is64()) - write64le(buf, hintName->getRVA()); + void writeTo(uint8_t *Buf) const override { + if (Config->is64()) + write64le(Buf, HintName->getRVA()); else - write32le(buf, hintName->getRVA()); + write32le(Buf, HintName->getRVA()); } - Chunk *hintName; + Chunk *HintName; }; // A chunk for the import descriptor table. @@ -79,82 +79,82 @@ class LookupChunk : public NonSectionChunk { // See Microsoft PE/COFF spec 7.1. Import Header for details. class OrdinalOnlyChunk : public NonSectionChunk { public: - explicit OrdinalOnlyChunk(uint16_t v) : ordinal(v) { - setAlignment(config->wordsize); + explicit OrdinalOnlyChunk(uint16_t V) : Ordinal(V) { + setAlignment(Config->Wordsize); } - size_t getSize() const override { return config->wordsize; } + size_t getSize() const override { return Config->Wordsize; } - void writeTo(uint8_t *buf) const override { + void writeTo(uint8_t *Buf) const override { // An import-by-ordinal slot has MSB 1 to indicate that // this is import-by-ordinal (and not import-by-name). - if (config->is64()) { - write64le(buf, (1ULL << 63) | ordinal); + if (Config->is64()) { + write64le(Buf, (1ULL << 63) | Ordinal); } else { - write32le(buf, (1ULL << 31) | ordinal); + write32le(Buf, (1ULL << 31) | Ordinal); } } - uint16_t ordinal; + uint16_t Ordinal; }; // A chunk for the import descriptor table. class ImportDirectoryChunk : public NonSectionChunk { public: - explicit ImportDirectoryChunk(Chunk *n) : dllName(n) {} + explicit ImportDirectoryChunk(Chunk *N) : DLLName(N) {} size_t getSize() const override { return sizeof(ImportDirectoryTableEntry); } - void writeTo(uint8_t *buf) const override { - memset(buf, 0, getSize()); + void writeTo(uint8_t *Buf) const override { + memset(Buf, 0, getSize()); - auto *e = (coff_import_directory_table_entry *)(buf); - e->ImportLookupTableRVA = lookupTab->getRVA(); - e->NameRVA = dllName->getRVA(); - e->ImportAddressTableRVA = addressTab->getRVA(); + auto *E = (coff_import_directory_table_entry *)(Buf); + E->ImportLookupTableRVA = LookupTab->getRVA(); + E->NameRVA = DLLName->getRVA(); + E->ImportAddressTableRVA = AddressTab->getRVA(); } - Chunk *dllName; - Chunk *lookupTab; - Chunk *addressTab; + Chunk *DLLName; + Chunk *LookupTab; + Chunk *AddressTab; }; // A chunk representing null terminator in the import table. // Contents of this chunk is always null bytes. class NullChunk : public NonSectionChunk { public: - explicit NullChunk(size_t n) : size(n) { hasData = false; } - size_t getSize() const override { return size; } + explicit NullChunk(size_t N) : Size(N) { HasData = false; } + size_t getSize() const override { return Size; } - void writeTo(uint8_t *buf) const override { - memset(buf, 0, size); + void writeTo(uint8_t *Buf) const override { + memset(Buf, 0, Size); } private: - size_t size; + size_t Size; }; static std::vector> -binImports(const std::vector &imports) { +binImports(const std::vector &Imports) { // Group DLL-imported symbols by DLL name because that's how // symbols are layed out in the import descriptor table. - auto less = [](const std::string &a, const std::string &b) { - return config->dllOrder[a] < config->dllOrder[b]; + auto Less = [](const std::string &A, const std::string &B) { + return Config->DLLOrder[A] < Config->DLLOrder[B]; }; std::map, - bool(*)(const std::string &, const std::string &)> m(less); - for (DefinedImportData *sym : imports) - m[sym->getDLLName().lower()].push_back(sym); + bool(*)(const std::string &, const std::string &)> M(Less); + for (DefinedImportData *Sym : Imports) + M[Sym->getDLLName().lower()].push_back(Sym); - std::vector> v; - for (auto &kv : m) { + std::vector> V; + for (auto &KV : M) { // Sort symbols by name for each group. - std::vector &syms = kv.second; - std::sort(syms.begin(), syms.end(), - [](DefinedImportData *a, DefinedImportData *b) { - return a->getName() < b->getName(); + std::vector &Syms = KV.second; + std::sort(Syms.begin(), Syms.end(), + [](DefinedImportData *A, DefinedImportData *B) { + return A->getName() < B->getName(); }); - v.push_back(std::move(syms)); + V.push_back(std::move(Syms)); } - return v; + return V; } // Export table @@ -163,39 +163,34 @@ binImports(const std::vector &imports) { // A chunk for the delay import descriptor table etnry. class DelayDirectoryChunk : public NonSectionChunk { public: - explicit DelayDirectoryChunk(Chunk *n) : dllName(n) {} + explicit DelayDirectoryChunk(Chunk *N) : DLLName(N) {} size_t getSize() const override { return sizeof(delay_import_directory_table_entry); } - void writeTo(uint8_t *buf) const override { - memset(buf, 0, getSize()); + void writeTo(uint8_t *Buf) const override { + memset(Buf, 0, getSize()); - auto *e = (delay_import_directory_table_entry *)(buf); - e->Attributes = 1; - e->Name = dllName->getRVA(); - e->ModuleHandle = moduleHandle->getRVA(); - e->DelayImportAddressTable = addressTab->getRVA(); - e->DelayImportNameTable = nameTab->getRVA(); + auto *E = (delay_import_directory_table_entry *)(Buf); + E->Attributes = 1; + E->Name = DLLName->getRVA(); + E->ModuleHandle = ModuleHandle->getRVA(); + E->DelayImportAddressTable = AddressTab->getRVA(); + E->DelayImportNameTable = NameTab->getRVA(); } - Chunk *dllName; - Chunk *moduleHandle; - Chunk *addressTab; - Chunk *nameTab; + Chunk *DLLName; + Chunk *ModuleHandle; + Chunk *AddressTab; + Chunk *NameTab; }; // Initial contents for delay-loaded functions. // This code calls __delayLoadHelper2 function to resolve a symbol -// which then overwrites its jump table slot with the result +// and then overwrites its jump table slot with the result // for subsequent function calls. -static const uint8_t thunkX64[] = { - 0x48, 0x8D, 0x05, 0, 0, 0, 0, // lea rax, [__imp_] - 0xE9, 0, 0, 0, 0, // jmp __tailMerge_ -}; - -static const uint8_t tailMergeX64[] = { +static const uint8_t ThunkX64[] = { 0x51, // push rcx 0x52, // push rdx 0x41, 0x50, // push r8 @@ -205,7 +200,7 @@ static const uint8_t tailMergeX64[] = { 0x66, 0x0F, 0x7F, 0x4C, 0x24, 0x10, // movdqa xmmword ptr [rsp+10h], xmm1 0x66, 0x0F, 0x7F, 0x54, 0x24, 0x20, // movdqa xmmword ptr [rsp+20h], xmm2 0x66, 0x0F, 0x7F, 0x5C, 0x24, 0x30, // movdqa xmmword ptr [rsp+30h], xmm3 - 0x48, 0x8B, 0xD0, // mov rdx, rax + 0x48, 0x8D, 0x15, 0, 0, 0, 0, // lea rdx, [__imp_] 0x48, 0x8D, 0x0D, 0, 0, 0, 0, // lea rcx, [___DELAY_IMPORT_...] 0xE8, 0, 0, 0, 0, // call __delayLoadHelper2 0x66, 0x0F, 0x6F, 0x04, 0x24, // movdqa xmm0, xmmword ptr [rsp] @@ -220,15 +215,10 @@ static const uint8_t tailMergeX64[] = { 0xFF, 0xE0, // jmp rax }; -static const uint8_t thunkX86[] = { - 0xB8, 0, 0, 0, 0, // mov eax, offset ___imp__ - 0xE9, 0, 0, 0, 0, // jmp __tailMerge_ -}; - -static const uint8_t tailMergeX86[] = { +static const uint8_t ThunkX86[] = { 0x51, // push ecx 0x52, // push edx - 0x50, // push eax + 0x68, 0, 0, 0, 0, // push offset ___imp__ 0x68, 0, 0, 0, 0, // push offset ___DELAY_IMPORT_DESCRIPTOR__dll 0xE8, 0, 0, 0, 0, // call ___delayLoadHelper2@8 0x5A, // pop edx @@ -236,13 +226,9 @@ static const uint8_t tailMergeX86[] = { 0xFF, 0xE0, // jmp eax }; -static const uint8_t thunkARM[] = { +static const uint8_t ThunkARM[] = { 0x40, 0xf2, 0x00, 0x0c, // mov.w ip, #0 __imp_ 0xc0, 0xf2, 0x00, 0x0c, // mov.t ip, #0 __imp_ - 0x00, 0xf0, 0x00, 0xb8, // b.w __tailMerge_ -}; - -static const uint8_t tailMergeARM[] = { 0x2d, 0xe9, 0x0f, 0x48, // push.w {r0, r1, r2, r3, r11, lr} 0x0d, 0xf2, 0x10, 0x0b, // addw r11, sp, #16 0x2d, 0xed, 0x10, 0x0b, // vpush {d0, d1, d2, d3, d4, d5, d6, d7} @@ -256,13 +242,9 @@ static const uint8_t tailMergeARM[] = { 0x60, 0x47, // bx ip }; -static const uint8_t thunkARM64[] = { +static const uint8_t ThunkARM64[] = { 0x11, 0x00, 0x00, 0x90, // adrp x17, #0 __imp_ 0x31, 0x02, 0x00, 0x91, // add x17, x17, #0 :lo12:__imp_ - 0x00, 0x00, 0x00, 0x14, // b __tailMerge_ -}; - -static const uint8_t tailMergeARM64[] = { 0xfd, 0x7b, 0xb3, 0xa9, // stp x29, x30, [sp, #-208]! 0xfd, 0x03, 0x00, 0x91, // mov x29, sp 0xe0, 0x07, 0x01, 0xa9, // stp x0, x1, [sp, #16] @@ -293,175 +275,117 @@ static const uint8_t tailMergeARM64[] = { // A chunk for the delay import thunk. class ThunkChunkX64 : public NonSectionChunk { public: - ThunkChunkX64(Defined *i, Chunk *tm) : imp(i), tailMerge(tm) {} - - size_t getSize() const override { return sizeof(thunkX64); } - - void writeTo(uint8_t *buf) const override { - memcpy(buf, thunkX64, sizeof(thunkX64)); - write32le(buf + 3, imp->getRVA() - rva - 7); - write32le(buf + 8, tailMerge->getRVA() - rva - 12); - } - - Defined *imp = nullptr; - Chunk *tailMerge = nullptr; -}; - -class TailMergeChunkX64 : public NonSectionChunk { -public: - TailMergeChunkX64(Chunk *d, Defined *h) : desc(d), helper(h) {} + ThunkChunkX64(Defined *I, Chunk *D, Defined *H) + : Imp(I), Desc(D), Helper(H) {} - size_t getSize() const override { return sizeof(tailMergeX64); } + size_t getSize() const override { return sizeof(ThunkX64); } - void writeTo(uint8_t *buf) const override { - memcpy(buf, tailMergeX64, sizeof(tailMergeX64)); - write32le(buf + 39, desc->getRVA() - rva - 43); - write32le(buf + 44, helper->getRVA() - rva - 48); + void writeTo(uint8_t *Buf) const override { + memcpy(Buf, ThunkX64, sizeof(ThunkX64)); + write32le(Buf + 36, Imp->getRVA() - RVA - 40); + write32le(Buf + 43, Desc->getRVA() - RVA - 47); + write32le(Buf + 48, Helper->getRVA() - RVA - 52); } - Chunk *desc = nullptr; - Defined *helper = nullptr; + Defined *Imp = nullptr; + Chunk *Desc = nullptr; + Defined *Helper = nullptr; }; class ThunkChunkX86 : public NonSectionChunk { public: - ThunkChunkX86(Defined *i, Chunk *tm) : imp(i), tailMerge(tm) {} + ThunkChunkX86(Defined *I, Chunk *D, Defined *H) + : Imp(I), Desc(D), Helper(H) {} - size_t getSize() const override { return sizeof(thunkX86); } + size_t getSize() const override { return sizeof(ThunkX86); } - void writeTo(uint8_t *buf) const override { - memcpy(buf, thunkX86, sizeof(thunkX86)); - write32le(buf + 1, imp->getRVA() + config->imageBase); - write32le(buf + 6, tailMerge->getRVA() - rva - 10); + void writeTo(uint8_t *Buf) const override { + memcpy(Buf, ThunkX86, sizeof(ThunkX86)); + write32le(Buf + 3, Imp->getRVA() + Config->ImageBase); + write32le(Buf + 8, Desc->getRVA() + Config->ImageBase); + write32le(Buf + 13, Helper->getRVA() - RVA - 17); } - void getBaserels(std::vector *res) override { - res->emplace_back(rva + 1); + void getBaserels(std::vector *Res) override { + Res->emplace_back(RVA + 3); + Res->emplace_back(RVA + 8); } - Defined *imp = nullptr; - Chunk *tailMerge = nullptr; -}; - -class TailMergeChunkX86 : public NonSectionChunk { -public: - TailMergeChunkX86(Chunk *d, Defined *h) : desc(d), helper(h) {} - - size_t getSize() const override { return sizeof(tailMergeX86); } - - void writeTo(uint8_t *buf) const override { - memcpy(buf, tailMergeX86, sizeof(tailMergeX86)); - write32le(buf + 4, desc->getRVA() + config->imageBase); - write32le(buf + 9, helper->getRVA() - rva - 13); - } - - void getBaserels(std::vector *res) override { - res->emplace_back(rva + 4); - } - - Chunk *desc = nullptr; - Defined *helper = nullptr; + Defined *Imp = nullptr; + Chunk *Desc = nullptr; + Defined *Helper = nullptr; }; class ThunkChunkARM : public NonSectionChunk { public: - ThunkChunkARM(Defined *i, Chunk *tm) : imp(i), tailMerge(tm) {} - - size_t getSize() const override { return sizeof(thunkARM); } - - void writeTo(uint8_t *buf) const override { - memcpy(buf, thunkARM, sizeof(thunkARM)); - applyMOV32T(buf + 0, imp->getRVA() + config->imageBase); - applyBranch24T(buf + 8, tailMerge->getRVA() - rva - 12); - } - - void getBaserels(std::vector *res) override { - res->emplace_back(rva + 0, IMAGE_REL_BASED_ARM_MOV32T); - } - - Defined *imp = nullptr; - Chunk *tailMerge = nullptr; -}; - -class TailMergeChunkARM : public NonSectionChunk { -public: - TailMergeChunkARM(Chunk *d, Defined *h) : desc(d), helper(h) {} + ThunkChunkARM(Defined *I, Chunk *D, Defined *H) + : Imp(I), Desc(D), Helper(H) {} - size_t getSize() const override { return sizeof(tailMergeARM); } + size_t getSize() const override { return sizeof(ThunkARM); } - void writeTo(uint8_t *buf) const override { - memcpy(buf, tailMergeARM, sizeof(tailMergeARM)); - applyMOV32T(buf + 14, desc->getRVA() + config->imageBase); - applyBranch24T(buf + 22, helper->getRVA() - rva - 26); + void writeTo(uint8_t *Buf) const override { + memcpy(Buf, ThunkARM, sizeof(ThunkARM)); + applyMOV32T(Buf + 0, Imp->getRVA() + Config->ImageBase); + applyMOV32T(Buf + 22, Desc->getRVA() + Config->ImageBase); + applyBranch24T(Buf + 30, Helper->getRVA() - RVA - 34); } - void getBaserels(std::vector *res) override { - res->emplace_back(rva + 14, IMAGE_REL_BASED_ARM_MOV32T); + void getBaserels(std::vector *Res) override { + Res->emplace_back(RVA + 0, IMAGE_REL_BASED_ARM_MOV32T); + Res->emplace_back(RVA + 22, IMAGE_REL_BASED_ARM_MOV32T); } - Chunk *desc = nullptr; - Defined *helper = nullptr; + Defined *Imp = nullptr; + Chunk *Desc = nullptr; + Defined *Helper = nullptr; }; class ThunkChunkARM64 : public NonSectionChunk { public: - ThunkChunkARM64(Defined *i, Chunk *tm) : imp(i), tailMerge(tm) {} - - size_t getSize() const override { return sizeof(thunkARM64); } - - void writeTo(uint8_t *buf) const override { - memcpy(buf, thunkARM64, sizeof(thunkARM64)); - applyArm64Addr(buf + 0, imp->getRVA(), rva + 0, 12); - applyArm64Imm(buf + 4, imp->getRVA() & 0xfff, 0); - applyArm64Branch26(buf + 8, tailMerge->getRVA() - rva - 8); - } - - Defined *imp = nullptr; - Chunk *tailMerge = nullptr; -}; - -class TailMergeChunkARM64 : public NonSectionChunk { -public: - TailMergeChunkARM64(Chunk *d, Defined *h) : desc(d), helper(h) {} + ThunkChunkARM64(Defined *I, Chunk *D, Defined *H) + : Imp(I), Desc(D), Helper(H) {} - size_t getSize() const override { return sizeof(tailMergeARM64); } + size_t getSize() const override { return sizeof(ThunkARM64); } - void writeTo(uint8_t *buf) const override { - memcpy(buf, tailMergeARM64, sizeof(tailMergeARM64)); - applyArm64Addr(buf + 44, desc->getRVA(), rva + 44, 12); - applyArm64Imm(buf + 48, desc->getRVA() & 0xfff, 0); - applyArm64Branch26(buf + 52, helper->getRVA() - rva - 52); + void writeTo(uint8_t *Buf) const override { + memcpy(Buf, ThunkARM64, sizeof(ThunkARM64)); + applyArm64Addr(Buf + 0, Imp->getRVA(), RVA + 0, 12); + applyArm64Imm(Buf + 4, Imp->getRVA() & 0xfff, 0); + applyArm64Addr(Buf + 52, Desc->getRVA(), RVA + 52, 12); + applyArm64Imm(Buf + 56, Desc->getRVA() & 0xfff, 0); + applyArm64Branch26(Buf + 60, Helper->getRVA() - RVA - 60); } - Chunk *desc = nullptr; - Defined *helper = nullptr; + Defined *Imp = nullptr; + Chunk *Desc = nullptr; + Defined *Helper = nullptr; }; // A chunk for the import descriptor table. class DelayAddressChunk : public NonSectionChunk { public: - explicit DelayAddressChunk(Chunk *c) : thunk(c) { - setAlignment(config->wordsize); + explicit DelayAddressChunk(Chunk *C) : Thunk(C) { + setAlignment(Config->Wordsize); } - size_t getSize() const override { return config->wordsize; } + size_t getSize() const override { return Config->Wordsize; } - void writeTo(uint8_t *buf) const override { - if (config->is64()) { - write64le(buf, thunk->getRVA() + config->imageBase); + void writeTo(uint8_t *Buf) const override { + if (Config->is64()) { + write64le(Buf, Thunk->getRVA() + Config->ImageBase); } else { - uint32_t bit = 0; + uint32_t Bit = 0; // Pointer to thumb code must have the LSB set, so adjust it. - if (config->machine == ARMNT) - bit = 1; - write32le(buf, (thunk->getRVA() + config->imageBase) | bit); + if (Config->Machine == ARMNT) + Bit = 1; + write32le(Buf, (Thunk->getRVA() + Config->ImageBase) | Bit); } } - void getBaserels(std::vector *res) override { - res->emplace_back(rva); + void getBaserels(std::vector *Res) override { + Res->emplace_back(RVA); } - Chunk *thunk; + Chunk *Thunk; }; // Export table @@ -470,266 +394,248 @@ class DelayAddressChunk : public NonSectionChunk { // A chunk for the export descriptor table. class ExportDirectoryChunk : public NonSectionChunk { public: - ExportDirectoryChunk(int i, int j, Chunk *d, Chunk *a, Chunk *n, Chunk *o) - : maxOrdinal(i), nameTabSize(j), dllName(d), addressTab(a), nameTab(n), - ordinalTab(o) {} + ExportDirectoryChunk(int I, int J, Chunk *D, Chunk *A, Chunk *N, Chunk *O) + : MaxOrdinal(I), NameTabSize(J), DLLName(D), AddressTab(A), NameTab(N), + OrdinalTab(O) {} size_t getSize() const override { return sizeof(export_directory_table_entry); } - void writeTo(uint8_t *buf) const override { - memset(buf, 0, getSize()); - - auto *e = (export_directory_table_entry *)(buf); - e->NameRVA = dllName->getRVA(); - e->OrdinalBase = 0; - e->AddressTableEntries = maxOrdinal + 1; - e->NumberOfNamePointers = nameTabSize; - e->ExportAddressTableRVA = addressTab->getRVA(); - e->NamePointerRVA = nameTab->getRVA(); - e->OrdinalTableRVA = ordinalTab->getRVA(); + void writeTo(uint8_t *Buf) const override { + memset(Buf, 0, getSize()); + + auto *E = (export_directory_table_entry *)(Buf); + E->NameRVA = DLLName->getRVA(); + E->OrdinalBase = 0; + E->AddressTableEntries = MaxOrdinal + 1; + E->NumberOfNamePointers = NameTabSize; + E->ExportAddressTableRVA = AddressTab->getRVA(); + E->NamePointerRVA = NameTab->getRVA(); + E->OrdinalTableRVA = OrdinalTab->getRVA(); } - uint16_t maxOrdinal; - uint16_t nameTabSize; - Chunk *dllName; - Chunk *addressTab; - Chunk *nameTab; - Chunk *ordinalTab; + uint16_t MaxOrdinal; + uint16_t NameTabSize; + Chunk *DLLName; + Chunk *AddressTab; + Chunk *NameTab; + Chunk *OrdinalTab; }; class AddressTableChunk : public NonSectionChunk { public: - explicit AddressTableChunk(size_t maxOrdinal) : size(maxOrdinal + 1) {} - size_t getSize() const override { return size * 4; } + explicit AddressTableChunk(size_t MaxOrdinal) : Size(MaxOrdinal + 1) {} + size_t getSize() const override { return Size * 4; } - void writeTo(uint8_t *buf) const override { - memset(buf, 0, getSize()); + void writeTo(uint8_t *Buf) const override { + memset(Buf, 0, getSize()); - for (const Export &e : config->exports) { - uint8_t *p = buf + e.ordinal * 4; - uint32_t bit = 0; + for (const Export &E : Config->Exports) { + uint8_t *P = Buf + E.Ordinal * 4; + uint32_t Bit = 0; // Pointer to thumb code must have the LSB set, so adjust it. - if (config->machine == ARMNT && !e.data) - bit = 1; - if (e.forwardChunk) { - write32le(p, e.forwardChunk->getRVA() | bit); + if (Config->Machine == ARMNT && !E.Data) + Bit = 1; + if (E.ForwardChunk) { + write32le(P, E.ForwardChunk->getRVA() | Bit); } else { - write32le(p, cast(e.sym)->getRVA() | bit); + write32le(P, cast(E.Sym)->getRVA() | Bit); } } } private: - size_t size; + size_t Size; }; class NamePointersChunk : public NonSectionChunk { public: - explicit NamePointersChunk(std::vector &v) : chunks(v) {} - size_t getSize() const override { return chunks.size() * 4; } + explicit NamePointersChunk(std::vector &V) : Chunks(V) {} + size_t getSize() const override { return Chunks.size() * 4; } - void writeTo(uint8_t *buf) const override { - for (Chunk *c : chunks) { - write32le(buf, c->getRVA()); - buf += 4; + void writeTo(uint8_t *Buf) const override { + for (Chunk *C : Chunks) { + write32le(Buf, C->getRVA()); + Buf += 4; } } private: - std::vector chunks; + std::vector Chunks; }; class ExportOrdinalChunk : public NonSectionChunk { public: - explicit ExportOrdinalChunk(size_t i) : size(i) {} - size_t getSize() const override { return size * 2; } + explicit ExportOrdinalChunk(size_t I) : Size(I) {} + size_t getSize() const override { return Size * 2; } - void writeTo(uint8_t *buf) const override { - for (Export &e : config->exports) { - if (e.noname) + void writeTo(uint8_t *Buf) const override { + for (Export &E : Config->Exports) { + if (E.Noname) continue; - write16le(buf, e.ordinal); - buf += 2; + write16le(Buf, E.Ordinal); + Buf += 2; } } private: - size_t size; + size_t Size; }; } // anonymous namespace void IdataContents::create() { - std::vector> v = binImports(imports); + std::vector> V = binImports(Imports); // Create .idata contents for each DLL. - for (std::vector &syms : v) { + for (std::vector &Syms : V) { // Create lookup and address tables. If they have external names, - // we need to create hintName chunks to store the names. + // we need to create HintName chunks to store the names. // If they don't (if they are import-by-ordinals), we store only // ordinal values to the table. - size_t base = lookups.size(); - for (DefinedImportData *s : syms) { - uint16_t ord = s->getOrdinal(); - if (s->getExternalName().empty()) { - lookups.push_back(make(ord)); - addresses.push_back(make(ord)); + size_t Base = Lookups.size(); + for (DefinedImportData *S : Syms) { + uint16_t Ord = S->getOrdinal(); + if (S->getExternalName().empty()) { + Lookups.push_back(make(Ord)); + Addresses.push_back(make(Ord)); continue; } - auto *c = make(s->getExternalName(), ord); - lookups.push_back(make(c)); - addresses.push_back(make(c)); - hints.push_back(c); + auto *C = make(S->getExternalName(), Ord); + Lookups.push_back(make(C)); + Addresses.push_back(make(C)); + Hints.push_back(C); } // Terminate with null values. - lookups.push_back(make(config->wordsize)); - addresses.push_back(make(config->wordsize)); + Lookups.push_back(make(Config->Wordsize)); + Addresses.push_back(make(Config->Wordsize)); - for (int i = 0, e = syms.size(); i < e; ++i) - syms[i]->setLocation(addresses[base + i]); + for (int I = 0, E = Syms.size(); I < E; ++I) + Syms[I]->setLocation(Addresses[Base + I]); // Create the import table header. - dllNames.push_back(make(syms[0]->getDLLName())); - auto *dir = make(dllNames.back()); - dir->lookupTab = lookups[base]; - dir->addressTab = addresses[base]; - dirs.push_back(dir); + DLLNames.push_back(make(Syms[0]->getDLLName())); + auto *Dir = make(DLLNames.back()); + Dir->LookupTab = Lookups[Base]; + Dir->AddressTab = Addresses[Base]; + Dirs.push_back(Dir); } // Add null terminator. - dirs.push_back(make(sizeof(ImportDirectoryTableEntry))); + Dirs.push_back(make(sizeof(ImportDirectoryTableEntry))); } std::vector DelayLoadContents::getChunks() { - std::vector v; - v.insert(v.end(), dirs.begin(), dirs.end()); - v.insert(v.end(), names.begin(), names.end()); - v.insert(v.end(), hintNames.begin(), hintNames.end()); - v.insert(v.end(), dllNames.begin(), dllNames.end()); - return v; + std::vector V; + V.insert(V.end(), Dirs.begin(), Dirs.end()); + V.insert(V.end(), Names.begin(), Names.end()); + V.insert(V.end(), HintNames.begin(), HintNames.end()); + V.insert(V.end(), DLLNames.begin(), DLLNames.end()); + return V; } std::vector DelayLoadContents::getDataChunks() { - std::vector v; - v.insert(v.end(), moduleHandles.begin(), moduleHandles.end()); - v.insert(v.end(), addresses.begin(), addresses.end()); - return v; + std::vector V; + V.insert(V.end(), ModuleHandles.begin(), ModuleHandles.end()); + V.insert(V.end(), Addresses.begin(), Addresses.end()); + return V; } uint64_t DelayLoadContents::getDirSize() { - return dirs.size() * sizeof(delay_import_directory_table_entry); + return Dirs.size() * sizeof(delay_import_directory_table_entry); } -void DelayLoadContents::create(Defined *h) { - helper = h; - std::vector> v = binImports(imports); +void DelayLoadContents::create(Defined *H) { + Helper = H; + std::vector> V = binImports(Imports); // Create .didat contents for each DLL. - for (std::vector &syms : v) { + for (std::vector &Syms : V) { // Create the delay import table header. - dllNames.push_back(make(syms[0]->getDLLName())); - auto *dir = make(dllNames.back()); - - size_t base = addresses.size(); - Chunk *tm = newTailMergeChunk(dir); - for (DefinedImportData *s : syms) { - Chunk *t = newThunkChunk(s, tm); - auto *a = make(t); - addresses.push_back(a); - thunks.push_back(t); - StringRef extName = s->getExternalName(); - if (extName.empty()) { - names.push_back(make(s->getOrdinal())); + DLLNames.push_back(make(Syms[0]->getDLLName())); + auto *Dir = make(DLLNames.back()); + + size_t Base = Addresses.size(); + for (DefinedImportData *S : Syms) { + Chunk *T = newThunkChunk(S, Dir); + auto *A = make(T); + Addresses.push_back(A); + Thunks.push_back(T); + StringRef ExtName = S->getExternalName(); + if (ExtName.empty()) { + Names.push_back(make(S->getOrdinal())); } else { - auto *c = make(extName, 0); - names.push_back(make(c)); - hintNames.push_back(c); + auto *C = make(ExtName, 0); + Names.push_back(make(C)); + HintNames.push_back(C); } } - thunks.push_back(tm); // Terminate with null values. - addresses.push_back(make(8)); - names.push_back(make(8)); + Addresses.push_back(make(8)); + Names.push_back(make(8)); - for (int i = 0, e = syms.size(); i < e; ++i) - syms[i]->setLocation(addresses[base + i]); - auto *mh = make(8); - mh->setAlignment(8); - moduleHandles.push_back(mh); + for (int I = 0, E = Syms.size(); I < E; ++I) + Syms[I]->setLocation(Addresses[Base + I]); + auto *MH = make(8); + MH->setAlignment(8); + ModuleHandles.push_back(MH); // Fill the delay import table header fields. - dir->moduleHandle = mh; - dir->addressTab = addresses[base]; - dir->nameTab = names[base]; - dirs.push_back(dir); + Dir->ModuleHandle = MH; + Dir->AddressTab = Addresses[Base]; + Dir->NameTab = Names[Base]; + Dirs.push_back(Dir); } // Add null terminator. - dirs.push_back(make(sizeof(delay_import_directory_table_entry))); + Dirs.push_back(make(sizeof(delay_import_directory_table_entry))); } -Chunk *DelayLoadContents::newTailMergeChunk(Chunk *dir) { - switch (config->machine) { +Chunk *DelayLoadContents::newThunkChunk(DefinedImportData *S, Chunk *Dir) { + switch (Config->Machine) { case AMD64: - return make(dir, helper); + return make(S, Dir, Helper); case I386: - return make(dir, helper); + return make(S, Dir, Helper); case ARMNT: - return make(dir, helper); + return make(S, Dir, Helper); case ARM64: - return make(dir, helper); - default: - llvm_unreachable("unsupported machine type"); - } -} - -Chunk *DelayLoadContents::newThunkChunk(DefinedImportData *s, - Chunk *tailMerge) { - switch (config->machine) { - case AMD64: - return make(s, tailMerge); - case I386: - return make(s, tailMerge); - case ARMNT: - return make(s, tailMerge); - case ARM64: - return make(s, tailMerge); + return make(S, Dir, Helper); default: llvm_unreachable("unsupported machine type"); } } EdataContents::EdataContents() { - uint16_t maxOrdinal = 0; - for (Export &e : config->exports) - maxOrdinal = std::max(maxOrdinal, e.ordinal); - - auto *dllName = make(sys::path::filename(config->outputFile)); - auto *addressTab = make(maxOrdinal); - std::vector names; - for (Export &e : config->exports) - if (!e.noname) - names.push_back(make(e.exportName)); - - std::vector forwards; - for (Export &e : config->exports) { - if (e.forwardTo.empty()) + uint16_t MaxOrdinal = 0; + for (Export &E : Config->Exports) + MaxOrdinal = std::max(MaxOrdinal, E.Ordinal); + + auto *DLLName = make(sys::path::filename(Config->OutputFile)); + auto *AddressTab = make(MaxOrdinal); + std::vector Names; + for (Export &E : Config->Exports) + if (!E.Noname) + Names.push_back(make(E.ExportName)); + + std::vector Forwards; + for (Export &E : Config->Exports) { + if (E.ForwardTo.empty()) continue; - e.forwardChunk = make(e.forwardTo); - forwards.push_back(e.forwardChunk); - } - - auto *nameTab = make(names); - auto *ordinalTab = make(names.size()); - auto *dir = make(maxOrdinal, names.size(), dllName, - addressTab, nameTab, ordinalTab); - chunks.push_back(dir); - chunks.push_back(dllName); - chunks.push_back(addressTab); - chunks.push_back(nameTab); - chunks.push_back(ordinalTab); - chunks.insert(chunks.end(), names.begin(), names.end()); - chunks.insert(chunks.end(), forwards.begin(), forwards.end()); + E.ForwardChunk = make(E.ForwardTo); + Forwards.push_back(E.ForwardChunk); + } + + auto *NameTab = make(Names); + auto *OrdinalTab = make(Names.size()); + auto *Dir = make(MaxOrdinal, Names.size(), DLLName, + AddressTab, NameTab, OrdinalTab); + Chunks.push_back(Dir); + Chunks.push_back(DLLName); + Chunks.push_back(AddressTab); + Chunks.push_back(NameTab); + Chunks.push_back(OrdinalTab); + Chunks.insert(Chunks.end(), Names.begin(), Names.end()); + Chunks.insert(Chunks.end(), Forwards.begin(), Forwards.end()); } } // namespace coff diff --git a/lld/COFF/DLL.h b/lld/COFF/DLL.h index ce0ee01c4a3dfe..4ad029868028a4 100644 --- a/lld/COFF/DLL.h +++ b/lld/COFF/DLL.h @@ -21,46 +21,45 @@ namespace coff { // call create() to populate the chunk vectors. class IdataContents { public: - void add(DefinedImportData *sym) { imports.push_back(sym); } - bool empty() { return imports.empty(); } + void add(DefinedImportData *Sym) { Imports.push_back(Sym); } + bool empty() { return Imports.empty(); } void create(); - std::vector imports; - std::vector dirs; - std::vector lookups; - std::vector addresses; - std::vector hints; - std::vector dllNames; + std::vector Imports; + std::vector Dirs; + std::vector Lookups; + std::vector Addresses; + std::vector Hints; + std::vector DLLNames; }; // Windows-specific. // DelayLoadContents creates all chunks for the delay-load DLL import table. class DelayLoadContents { public: - void add(DefinedImportData *sym) { imports.push_back(sym); } - bool empty() { return imports.empty(); } - void create(Defined *helper); + void add(DefinedImportData *Sym) { Imports.push_back(Sym); } + bool empty() { return Imports.empty(); } + void create(Defined *Helper); std::vector getChunks(); std::vector getDataChunks(); - ArrayRef getCodeChunks() { return thunks; } + ArrayRef getCodeChunks() { return Thunks; } - uint64_t getDirRVA() { return dirs[0]->getRVA(); } + uint64_t getDirRVA() { return Dirs[0]->getRVA(); } uint64_t getDirSize(); private: - Chunk *newThunkChunk(DefinedImportData *s, Chunk *tailMerge); - Chunk *newTailMergeChunk(Chunk *dir); + Chunk *newThunkChunk(DefinedImportData *S, Chunk *Dir); - Defined *helper; - std::vector imports; - std::vector dirs; - std::vector moduleHandles; - std::vector addresses; - std::vector names; - std::vector hintNames; - std::vector thunks; - std::vector dllNames; + Defined *Helper; + std::vector Imports; + std::vector Dirs; + std::vector ModuleHandles; + std::vector Addresses; + std::vector Names; + std::vector HintNames; + std::vector Thunks; + std::vector DLLNames; }; // Windows-specific. @@ -68,11 +67,11 @@ class DelayLoadContents { class EdataContents { public: EdataContents(); - std::vector chunks; + std::vector Chunks; - uint64_t getRVA() { return chunks[0]->getRVA(); } + uint64_t getRVA() { return Chunks[0]->getRVA(); } uint64_t getSize() { - return chunks.back()->getRVA() + chunks.back()->getSize() - getRVA(); + return Chunks.back()->getRVA() + Chunks.back()->getSize() - getRVA(); } }; diff --git a/lld/COFF/DebugTypes.cpp b/lld/COFF/DebugTypes.cpp index c41c49cc319c4f..770de80486c4be 100644 --- a/lld/COFF/DebugTypes.cpp +++ b/lld/COFF/DebugTypes.cpp @@ -32,40 +32,40 @@ namespace { // before any dependent OBJ. class TypeServerSource : public TpiSource { public: - explicit TypeServerSource(MemoryBufferRef m, llvm::pdb::NativeSession *s) - : TpiSource(PDB, nullptr), session(s), mb(m) {} + explicit TypeServerSource(MemoryBufferRef M, llvm::pdb::NativeSession *S) + : TpiSource(PDB, nullptr), Session(S), MB(M) {} // Queue a PDB type server for loading in the COFF Driver - static void enqueue(const ObjFile *dependentFile, - const TypeServer2Record &ts); + static void enqueue(const ObjFile *DependentFile, + const TypeServer2Record &TS); // Create an instance - static Expected getInstance(MemoryBufferRef m); + static Expected getInstance(MemoryBufferRef M); // Fetch the PDB instance loaded for a corresponding dependent OBJ. static Expected - findFromFile(const ObjFile *dependentFile); + findFromFile(const ObjFile *DependentFile); static std::map> - instances; + Instances; // The interface to the PDB (if it was opened successfully) - std::unique_ptr session; + std::unique_ptr Session; private: - MemoryBufferRef mb; + MemoryBufferRef MB; }; // This class represents the debug type stream of an OBJ file that depends on a // PDB type server (see TypeServerSource). class UseTypeServerSource : public TpiSource { public: - UseTypeServerSource(const ObjFile *f, const TypeServer2Record *ts) - : TpiSource(UsingPDB, f), typeServerDependency(*ts) {} + UseTypeServerSource(const ObjFile *F, const TypeServer2Record *TS) + : TpiSource(UsingPDB, F), TypeServerDependency(*TS) {} // Information about the PDB type server dependency, that needs to be loaded // in before merging this OBJ. - TypeServer2Record typeServerDependency; + TypeServer2Record TypeServerDependency; }; // This class represents the debug type stream of a Microsoft precompiled @@ -74,76 +74,76 @@ class UseTypeServerSource : public TpiSource { // such files, clang does not. class PrecompSource : public TpiSource { public: - PrecompSource(const ObjFile *f) : TpiSource(PCH, f) {} + PrecompSource(const ObjFile *F) : TpiSource(PCH, F) {} }; // This class represents the debug type stream of an OBJ file that depends on a // Microsoft precompiled headers OBJ (see PrecompSource). class UsePrecompSource : public TpiSource { public: - UsePrecompSource(const ObjFile *f, const PrecompRecord *precomp) - : TpiSource(UsingPCH, f), precompDependency(*precomp) {} + UsePrecompSource(const ObjFile *F, const PrecompRecord *Precomp) + : TpiSource(UsingPCH, F), PrecompDependency(*Precomp) {} // Information about the Precomp OBJ dependency, that needs to be loaded in // before merging this OBJ. - PrecompRecord precompDependency; + PrecompRecord PrecompDependency; }; } // namespace static std::vector> GC; -TpiSource::TpiSource(TpiKind k, const ObjFile *f) : kind(k), file(f) { +TpiSource::TpiSource(TpiKind K, const ObjFile *F) : Kind(K), File(F) { GC.push_back(std::unique_ptr(this)); } -TpiSource *lld::coff::makeTpiSource(const ObjFile *f) { - return new TpiSource(TpiSource::Regular, f); +TpiSource *lld::coff::makeTpiSource(const ObjFile *F) { + return new TpiSource(TpiSource::Regular, F); } -TpiSource *lld::coff::makeUseTypeServerSource(const ObjFile *f, - const TypeServer2Record *ts) { - TypeServerSource::enqueue(f, *ts); - return new UseTypeServerSource(f, ts); +TpiSource *lld::coff::makeUseTypeServerSource(const ObjFile *F, + const TypeServer2Record *TS) { + TypeServerSource::enqueue(F, *TS); + return new UseTypeServerSource(F, TS); } -TpiSource *lld::coff::makePrecompSource(const ObjFile *f) { - return new PrecompSource(f); +TpiSource *lld::coff::makePrecompSource(const ObjFile *F) { + return new PrecompSource(F); } -TpiSource *lld::coff::makeUsePrecompSource(const ObjFile *f, - const PrecompRecord *precomp) { - return new UsePrecompSource(f, precomp); +TpiSource *lld::coff::makeUsePrecompSource(const ObjFile *F, + const PrecompRecord *Precomp) { + return new UsePrecompSource(F, Precomp); } namespace lld { namespace coff { template <> -const PrecompRecord &retrieveDependencyInfo(const TpiSource *source) { - assert(source->kind == TpiSource::UsingPCH); - return ((const UsePrecompSource *)source)->precompDependency; +const PrecompRecord &retrieveDependencyInfo(const TpiSource *Source) { + assert(Source->Kind == TpiSource::UsingPCH); + return ((const UsePrecompSource *)Source)->PrecompDependency; } template <> -const TypeServer2Record &retrieveDependencyInfo(const TpiSource *source) { - assert(source->kind == TpiSource::UsingPDB); - return ((const UseTypeServerSource *)source)->typeServerDependency; +const TypeServer2Record &retrieveDependencyInfo(const TpiSource *Source) { + assert(Source->Kind == TpiSource::UsingPDB); + return ((const UseTypeServerSource *)Source)->TypeServerDependency; } } // namespace coff } // namespace lld std::map> - TypeServerSource::instances; + TypeServerSource::Instances; // Make a PDB path assuming the PDB is in the same folder as the OBJ -static std::string getPdbBaseName(const ObjFile *file, StringRef tSPath) { - StringRef localPath = - !file->parentName.empty() ? file->parentName : file->getName(); - SmallString<128> path = sys::path::parent_path(localPath); +static std::string getPdbBaseName(const ObjFile *File, StringRef TSPath) { + StringRef LocalPath = + !File->ParentName.empty() ? File->ParentName : File->getName(); + SmallString<128> Path = sys::path::parent_path(LocalPath); // Currently, type server PDBs are only created by MSVC cl, which only runs // on Windows, so we can assume type server paths are Windows style. - sys::path::append(path, sys::path::filename(tSPath, sys::path::Style::windows)); - return path.str(); + sys::path::append(Path, sys::path::filename(TSPath, sys::path::Style::windows)); + return Path.str(); } // The casing of the PDB path stamped in the OBJ can differ from the actual path @@ -158,80 +158,80 @@ static std::string normalizePdbPath(StringRef path) { } // If existing, return the actual PDB path on disk. -static Optional findPdbPath(StringRef pdbPath, - const ObjFile *dependentFile) { +static Optional findPdbPath(StringRef PDBPath, + const ObjFile *DependentFile) { // Ensure the file exists before anything else. In some cases, if the path // points to a removable device, Driver::enqueuePath() would fail with an // error (EAGAIN, "resource unavailable try again") which we want to skip // silently. - if (llvm::sys::fs::exists(pdbPath)) - return normalizePdbPath(pdbPath); - std::string ret = getPdbBaseName(dependentFile, pdbPath); - if (llvm::sys::fs::exists(ret)) - return normalizePdbPath(ret); + if (llvm::sys::fs::exists(PDBPath)) + return normalizePdbPath(PDBPath); + std::string Ret = getPdbBaseName(DependentFile, PDBPath); + if (llvm::sys::fs::exists(Ret)) + return normalizePdbPath(Ret); return None; } // Fetch the PDB instance that was already loaded by the COFF Driver. Expected -TypeServerSource::findFromFile(const ObjFile *dependentFile) { - const TypeServer2Record &ts = - retrieveDependencyInfo(dependentFile->debugTypesObj); +TypeServerSource::findFromFile(const ObjFile *DependentFile) { + const TypeServer2Record &TS = + retrieveDependencyInfo(DependentFile->DebugTypesObj); - Optional p = findPdbPath(ts.Name, dependentFile); - if (!p) - return createFileError(ts.Name, errorCodeToError(std::error_code( + Optional P = findPdbPath(TS.Name, DependentFile); + if (!P) + return createFileError(TS.Name, errorCodeToError(std::error_code( ENOENT, std::generic_category()))); - auto it = TypeServerSource::instances.find(*p); + auto It = TypeServerSource::Instances.find(*P); // The PDB file exists on disk, at this point we expect it to have been // inserted in the map by TypeServerSource::loadPDB() - assert(it != TypeServerSource::instances.end()); + assert(It != TypeServerSource::Instances.end()); - std::pair &pdb = it->second; + std::pair &PDB = It->second; - if (!pdb.second) + if (!PDB.second) return createFileError( - *p, createStringError(inconvertibleErrorCode(), pdb.first.c_str())); + *P, createStringError(inconvertibleErrorCode(), PDB.first.c_str())); - pdb::PDBFile &pdbFile = (pdb.second)->session->getPDBFile(); - pdb::InfoStream &info = cantFail(pdbFile.getPDBInfoStream()); + pdb::PDBFile &PDBFile = (PDB.second)->Session->getPDBFile(); + pdb::InfoStream &Info = cantFail(PDBFile.getPDBInfoStream()); // Just because a file with a matching name was found doesn't mean it can be // used. The GUID must match between the PDB header and the OBJ // TypeServer2 record. The 'Age' is used by MSVC incremental compilation. - if (info.getGuid() != ts.getGuid()) + if (Info.getGuid() != TS.getGuid()) return createFileError( - ts.Name, + TS.Name, make_error(pdb::pdb_error_code::signature_out_of_date)); - return pdb.second; + return PDB.second; } // FIXME: Temporary interface until PDBLinker::maybeMergeTypeServerPDB() is // moved here. Expected -lld::coff::findTypeServerSource(const ObjFile *f) { - Expected ts = TypeServerSource::findFromFile(f); - if (!ts) - return ts.takeError(); - return ts.get()->session.get(); +lld::coff::findTypeServerSource(const ObjFile *F) { + Expected TS = TypeServerSource::findFromFile(F); + if (!TS) + return TS.takeError(); + return TS.get()->Session.get(); } // Queue a PDB type server for loading in the COFF Driver -void TypeServerSource::enqueue(const ObjFile *dependentFile, - const TypeServer2Record &ts) { +void TypeServerSource::enqueue(const ObjFile *DependentFile, + const TypeServer2Record &TS) { // Start by finding where the PDB is located (either the record path or next // to the OBJ file) - Optional p = findPdbPath(ts.Name, dependentFile); - if (!p) + Optional P = findPdbPath(TS.Name, DependentFile); + if (!P) return; - auto it = TypeServerSource::instances.emplace( - *p, std::pair{}); - if (!it.second) + auto It = TypeServerSource::Instances.emplace( + *P, std::pair{}); + if (!It.second) return; // another OBJ already scheduled this PDB for load - driver->enqueuePath(*p, false, false); + Driver->enqueuePath(*P, false); } // Create an instance of TypeServerSource or an error string if the PDB couldn't @@ -239,30 +239,30 @@ void TypeServerSource::enqueue(const ObjFile *dependentFile, // will be merged in. NOTE - a PDB load failure is not a link error: some // debug info will simply be missing from the final PDB - that is the default // accepted behavior. -void lld::coff::loadTypeServerSource(llvm::MemoryBufferRef m) { - std::string path = normalizePdbPath(m.getBufferIdentifier()); +void lld::coff::loadTypeServerSource(llvm::MemoryBufferRef M) { + std::string Path = normalizePdbPath(M.getBufferIdentifier()); - Expected ts = TypeServerSource::getInstance(m); - if (!ts) - TypeServerSource::instances[path] = {toString(ts.takeError()), nullptr}; + Expected TS = TypeServerSource::getInstance(M); + if (!TS) + TypeServerSource::Instances[Path] = {toString(TS.takeError()), nullptr}; else - TypeServerSource::instances[path] = {{}, *ts}; + TypeServerSource::Instances[Path] = {{}, *TS}; } -Expected TypeServerSource::getInstance(MemoryBufferRef m) { - std::unique_ptr iSession; - Error err = pdb::NativeSession::createFromPdb( - MemoryBuffer::getMemBuffer(m, false), iSession); - if (err) - return std::move(err); +Expected TypeServerSource::getInstance(MemoryBufferRef M) { + std::unique_ptr ISession; + Error Err = pdb::NativeSession::createFromPdb( + MemoryBuffer::getMemBuffer(M, false), ISession); + if (Err) + return std::move(Err); - std::unique_ptr session( - static_cast(iSession.release())); + std::unique_ptr Session( + static_cast(ISession.release())); - pdb::PDBFile &pdbFile = session->getPDBFile(); - Expected info = pdbFile.getPDBInfoStream(); + pdb::PDBFile &PDBFile = Session->getPDBFile(); + Expected Info = PDBFile.getPDBInfoStream(); // All PDB Files should have an Info stream. - if (!info) - return info.takeError(); - return new TypeServerSource(m, session.release()); + if (!Info) + return Info.takeError(); + return new TypeServerSource(M, Session.release()); } diff --git a/lld/COFF/DebugTypes.h b/lld/COFF/DebugTypes.h index e37c727232d002..cb03aba5b0d2da 100644 --- a/lld/COFF/DebugTypes.h +++ b/lld/COFF/DebugTypes.h @@ -31,28 +31,28 @@ class TpiSource { public: enum TpiKind { Regular, PCH, UsingPCH, PDB, UsingPDB }; - TpiSource(TpiKind k, const ObjFile *f); + TpiSource(TpiKind K, const ObjFile *F); virtual ~TpiSource() {} - const TpiKind kind; - const ObjFile *file; + const TpiKind Kind; + const ObjFile *File; }; -TpiSource *makeTpiSource(const ObjFile *f); -TpiSource *makeUseTypeServerSource(const ObjFile *f, - const llvm::codeview::TypeServer2Record *ts); -TpiSource *makePrecompSource(const ObjFile *f); -TpiSource *makeUsePrecompSource(const ObjFile *f, - const llvm::codeview::PrecompRecord *precomp); +TpiSource *makeTpiSource(const ObjFile *F); +TpiSource *makeUseTypeServerSource(const ObjFile *F, + const llvm::codeview::TypeServer2Record *TS); +TpiSource *makePrecompSource(const ObjFile *F); +TpiSource *makeUsePrecompSource(const ObjFile *F, + const llvm::codeview::PrecompRecord *Precomp); -void loadTypeServerSource(llvm::MemoryBufferRef m); +void loadTypeServerSource(llvm::MemoryBufferRef M); // Temporary interface to get the dependency -template const T &retrieveDependencyInfo(const TpiSource *source); +template const T &retrieveDependencyInfo(const TpiSource *Source); // Temporary interface until we move PDBLinker::maybeMergeTypeServerPDB here llvm::Expected -findTypeServerSource(const ObjFile *f); +findTypeServerSource(const ObjFile *F); } // namespace coff } // namespace lld diff --git a/lld/COFF/Driver.cpp b/lld/COFF/Driver.cpp index 6e27edbecadf2e..c1520a4ae12ed3 100644 --- a/lld/COFF/Driver.cpp +++ b/lld/COFF/Driver.cpp @@ -36,7 +36,6 @@ #include "llvm/Option/Option.h" #include "llvm/Support/Debug.h" #include "llvm/Support/LEB128.h" -#include "llvm/Support/MathExtras.h" #include "llvm/Support/Path.h" #include "llvm/Support/Process.h" #include "llvm/Support/TarWriter.h" @@ -55,68 +54,54 @@ using llvm::sys::Process; namespace lld { namespace coff { -static Timer inputFileTimer("Input File Reading", Timer::root()); +static Timer InputFileTimer("Input File Reading", Timer::root()); -Configuration *config; -LinkerDriver *driver; +Configuration *Config; +LinkerDriver *Driver; -bool link(ArrayRef args, bool canExitEarly, raw_ostream &diag) { - errorHandler().logName = args::getFilenameWithoutExe(args[0]); - errorHandler().errorOS = &diag; - errorHandler().errorLimitExceededMsg = +bool link(ArrayRef Args, bool CanExitEarly, raw_ostream &Diag) { + errorHandler().LogName = args::getFilenameWithoutExe(Args[0]); + errorHandler().ErrorOS = &Diag; + errorHandler().ColorDiagnostics = Diag.has_colors(); + errorHandler().ErrorLimitExceededMsg = "too many errors emitted, stopping now" " (use /errorlimit:0 to see all errors)"; - errorHandler().exitEarly = canExitEarly; - enableColors(diag.has_colors()); + errorHandler().ExitEarly = CanExitEarly; + Config = make(); - config = make(); - symtab = make(); - driver = make(); + Symtab = make(); - driver->link(args); + Driver = make(); + Driver->link(Args); // Call exit() if we can to avoid calling destructors. - if (canExitEarly) + if (CanExitEarly) exitLld(errorCount() ? 1 : 0); freeArena(); - ObjFile::instances.clear(); - ImportFile::instances.clear(); - BitcodeFile::instances.clear(); - memset(MergeChunk::instances, 0, sizeof(MergeChunk::instances)); + ObjFile::Instances.clear(); + ImportFile::Instances.clear(); + BitcodeFile::Instances.clear(); + memset(MergeChunk::Instances, 0, sizeof(MergeChunk::Instances)); return !errorCount(); } -// Parse options of the form "old;new". -static std::pair getOldNewOptions(opt::InputArgList &args, - unsigned id) { - auto *arg = args.getLastArg(id); - if (!arg) - return {"", ""}; - - StringRef s = arg->getValue(); - std::pair ret = s.split(';'); - if (ret.second.empty()) - error(arg->getSpelling() + " expects 'old;new' format, but got " + s); - return ret; -} - // Drop directory components and replace extension with ".exe" or ".dll". -static std::string getOutputPath(StringRef path) { - auto p = path.find_last_of("\\/"); - StringRef s = (p == StringRef::npos) ? path : path.substr(p + 1); - const char* e = config->dll ? ".dll" : ".exe"; - return (s.substr(0, s.rfind('.')) + e).str(); +static std::string getOutputPath(StringRef Path) { + auto P = Path.find_last_of("\\/"); + StringRef S = (P == StringRef::npos) ? Path : Path.substr(P + 1); + const char* E = Config->DLL ? ".dll" : ".exe"; + return (S.substr(0, S.rfind('.')) + E).str(); } // Returns true if S matches /crtend.?\.o$/. -static bool isCrtend(StringRef s) { - if (!s.endswith(".o")) +static bool isCrtend(StringRef S) { + if (!S.endswith(".o")) return false; - s = s.drop_back(2); - if (s.endswith("crtend")) + S = S.drop_back(2); + if (S.endswith("crtend")) return true; - return !s.empty() && s.drop_back().endswith("crtend"); + return !S.empty() && S.drop_back().endswith("crtend"); } // ErrorOr is not default constructible, so it cannot be used as the type @@ -128,406 +113,397 @@ using MBErrPair = std::pair, std::error_code>; // Create a std::future that opens and maps a file using the best strategy for // the host platform. -static std::future createFutureForFile(std::string path) { +static std::future createFutureForFile(std::string Path) { #if _WIN32 // On Windows, file I/O is relatively slow so it is best to do this // asynchronously. - auto strategy = std::launch::async; + auto Strategy = std::launch::async; #else - auto strategy = std::launch::deferred; + auto Strategy = std::launch::deferred; #endif - return std::async(strategy, [=]() { - auto mbOrErr = MemoryBuffer::getFile(path, + return std::async(Strategy, [=]() { + auto MBOrErr = MemoryBuffer::getFile(Path, /*FileSize*/ -1, /*RequiresNullTerminator*/ false); - if (!mbOrErr) - return MBErrPair{nullptr, mbOrErr.getError()}; - return MBErrPair{std::move(*mbOrErr), std::error_code()}; + if (!MBOrErr) + return MBErrPair{nullptr, MBOrErr.getError()}; + return MBErrPair{std::move(*MBOrErr), std::error_code()}; }); } // Symbol names are mangled by prepending "_" on x86. -static StringRef mangle(StringRef sym) { - assert(config->machine != IMAGE_FILE_MACHINE_UNKNOWN); - if (config->machine == I386) - return saver.save("_" + sym); - return sym; +static StringRef mangle(StringRef Sym) { + assert(Config->Machine != IMAGE_FILE_MACHINE_UNKNOWN); + if (Config->Machine == I386) + return Saver.save("_" + Sym); + return Sym; } -static bool findUnderscoreMangle(StringRef sym) { - Symbol *s = symtab->findMangle(mangle(sym)); - return s && !isa(s); +static bool findUnderscoreMangle(StringRef Sym) { + Symbol *S = Symtab->findMangle(mangle(Sym)); + return S && !isa(S); } -MemoryBufferRef LinkerDriver::takeBuffer(std::unique_ptr mb) { - MemoryBufferRef mbref = *mb; - make>(std::move(mb)); // take ownership +MemoryBufferRef LinkerDriver::takeBuffer(std::unique_ptr MB) { + MemoryBufferRef MBRef = *MB; + make>(std::move(MB)); // take ownership - if (driver->tar) - driver->tar->append(relativeToRoot(mbref.getBufferIdentifier()), - mbref.getBuffer()); - return mbref; + if (Driver->Tar) + Driver->Tar->append(relativeToRoot(MBRef.getBufferIdentifier()), + MBRef.getBuffer()); + return MBRef; } -void LinkerDriver::addBuffer(std::unique_ptr mb, - bool wholeArchive, bool lazy) { - StringRef filename = mb->getBufferIdentifier(); +void LinkerDriver::addBuffer(std::unique_ptr MB, + bool WholeArchive) { + StringRef Filename = MB->getBufferIdentifier(); - MemoryBufferRef mbref = takeBuffer(std::move(mb)); - filePaths.push_back(filename); + MemoryBufferRef MBRef = takeBuffer(std::move(MB)); + FilePaths.push_back(Filename); // File type is detected by contents, not by file extension. - switch (identify_magic(mbref.getBuffer())) { + switch (identify_magic(MBRef.getBuffer())) { case file_magic::windows_resource: - resources.push_back(mbref); + Resources.push_back(MBRef); break; case file_magic::archive: - if (wholeArchive) { - std::unique_ptr file = - CHECK(Archive::create(mbref), filename + ": failed to parse archive"); - Archive *archive = file.get(); - make>(std::move(file)); // take ownership - - for (MemoryBufferRef m : getArchiveMembers(archive)) - addArchiveBuffer(m, "", filename, 0); + if (WholeArchive) { + std::unique_ptr File = + CHECK(Archive::create(MBRef), Filename + ": failed to parse archive"); + + for (MemoryBufferRef M : getArchiveMembers(File.get())) + addArchiveBuffer(M, "", Filename, 0); return; } - symtab->addFile(make(mbref)); + Symtab->addFile(make(MBRef)); break; case file_magic::bitcode: - if (lazy) - symtab->addFile(make(mbref)); - else - symtab->addFile(make(mbref, "", 0)); + Symtab->addFile(make(MBRef, "", 0)); break; case file_magic::coff_object: case file_magic::coff_import_library: - if (lazy) - symtab->addFile(make(mbref)); - else - symtab->addFile(make(mbref)); + Symtab->addFile(make(MBRef)); break; case file_magic::pdb: - loadTypeServerSource(mbref); + loadTypeServerSource(MBRef); break; case file_magic::coff_cl_gl_object: - error(filename + ": is not a native COFF file. Recompile without /GL"); + error(Filename + ": is not a native COFF file. Recompile without /GL"); break; case file_magic::pecoff_executable: - if (filename.endswith_lower(".dll")) { - error(filename + ": bad file type. Did you specify a DLL instead of an " + if (Filename.endswith_lower(".dll")) { + error(Filename + ": bad file type. Did you specify a DLL instead of an " "import library?"); break; } LLVM_FALLTHROUGH; default: - error(mbref.getBufferIdentifier() + ": unknown file type"); + error(MBRef.getBufferIdentifier() + ": unknown file type"); break; } } -void LinkerDriver::enqueuePath(StringRef path, bool wholeArchive, bool lazy) { - auto future = - std::make_shared>(createFutureForFile(path)); - std::string pathStr = path; +void LinkerDriver::enqueuePath(StringRef Path, bool WholeArchive) { + auto Future = + std::make_shared>(createFutureForFile(Path)); + std::string PathStr = Path; enqueueTask([=]() { - auto mbOrErr = future->get(); - if (mbOrErr.second) { - std::string msg = - "could not open '" + pathStr + "': " + mbOrErr.second.message(); + auto MBOrErr = Future->get(); + if (MBOrErr.second) { + std::string Error = + "could not open '" + PathStr + "': " + MBOrErr.second.message(); // Check if the filename is a typo for an option flag. OptTable thinks // that all args that are not known options and that start with / are // filenames, but e.g. `/nodefaultlibs` is more likely a typo for // the option `/nodefaultlib` than a reference to a file in the root // directory. - std::string nearest; - if (COFFOptTable().findNearest(pathStr, nearest) > 1) - error(msg); + std::string Nearest; + if (COFFOptTable().findNearest(PathStr, Nearest) > 1) + error(Error); else - error(msg + "; did you mean '" + nearest + "'"); + error(Error + "; did you mean '" + Nearest + "'"); } else - driver->addBuffer(std::move(mbOrErr.first), wholeArchive, lazy); + Driver->addBuffer(std::move(MBOrErr.first), WholeArchive); }); } -void LinkerDriver::addArchiveBuffer(MemoryBufferRef mb, StringRef symName, - StringRef parentName, - uint64_t offsetInArchive) { - file_magic magic = identify_magic(mb.getBuffer()); - if (magic == file_magic::coff_import_library) { - InputFile *imp = make(mb); - imp->parentName = parentName; - symtab->addFile(imp); +void LinkerDriver::addArchiveBuffer(MemoryBufferRef MB, StringRef SymName, + StringRef ParentName, + uint64_t OffsetInArchive) { + file_magic Magic = identify_magic(MB.getBuffer()); + if (Magic == file_magic::coff_import_library) { + InputFile *Imp = make(MB); + Imp->ParentName = ParentName; + Symtab->addFile(Imp); return; } - InputFile *obj; - if (magic == file_magic::coff_object) { - obj = make(mb); - } else if (magic == file_magic::bitcode) { - obj = make(mb, parentName, offsetInArchive); + InputFile *Obj; + if (Magic == file_magic::coff_object) { + Obj = make(MB); + } else if (Magic == file_magic::bitcode) { + Obj = make(MB, ParentName, OffsetInArchive); } else { - error("unknown file type: " + mb.getBufferIdentifier()); + error("unknown file type: " + MB.getBufferIdentifier()); return; } - obj->parentName = parentName; - symtab->addFile(obj); - log("Loaded " + toString(obj) + " for " + symName); + Obj->ParentName = ParentName; + Symtab->addFile(Obj); + log("Loaded " + toString(Obj) + " for " + SymName); } -void LinkerDriver::enqueueArchiveMember(const Archive::Child &c, - const Archive::Symbol &sym, - StringRef parentName) { +void LinkerDriver::enqueueArchiveMember(const Archive::Child &C, + StringRef SymName, + StringRef ParentName) { - auto reportBufferError = [=](Error &&e, StringRef childName) { + auto ReportBufferError = [=](Error &&E, + StringRef ChildName) { fatal("could not get the buffer for the member defining symbol " + - toCOFFString(sym) + ": " + parentName + "(" + childName + "): " + - toString(std::move(e))); + SymName + ": " + ParentName + "(" + ChildName + "): " + + toString(std::move(E))); }; - if (!c.getParent()->isThin()) { - uint64_t offsetInArchive = c.getChildOffset(); - Expected mbOrErr = c.getMemoryBufferRef(); - if (!mbOrErr) - reportBufferError(mbOrErr.takeError(), check(c.getFullName())); - MemoryBufferRef mb = mbOrErr.get(); + if (!C.getParent()->isThin()) { + uint64_t OffsetInArchive = C.getChildOffset(); + Expected MBOrErr = C.getMemoryBufferRef(); + if (!MBOrErr) + ReportBufferError(MBOrErr.takeError(), check(C.getFullName())); + MemoryBufferRef MB = MBOrErr.get(); enqueueTask([=]() { - driver->addArchiveBuffer(mb, toCOFFString(sym), parentName, - offsetInArchive); + Driver->addArchiveBuffer(MB, SymName, ParentName, OffsetInArchive); }); return; } - std::string childName = CHECK( - c.getFullName(), + std::string ChildName = CHECK( + C.getFullName(), "could not get the filename for the member defining symbol " + - toCOFFString(sym)); - auto future = std::make_shared>( - createFutureForFile(childName)); + SymName); + auto Future = std::make_shared>( + createFutureForFile(ChildName)); enqueueTask([=]() { - auto mbOrErr = future->get(); - if (mbOrErr.second) - reportBufferError(errorCodeToError(mbOrErr.second), childName); - driver->addArchiveBuffer(takeBuffer(std::move(mbOrErr.first)), - toCOFFString(sym), parentName, - /*OffsetInArchive=*/0); + auto MBOrErr = Future->get(); + if (MBOrErr.second) + ReportBufferError(errorCodeToError(MBOrErr.second), ChildName); + Driver->addArchiveBuffer(takeBuffer(std::move(MBOrErr.first)), SymName, + ParentName, /* OffsetInArchive */ 0); }); } -static bool isDecorated(StringRef sym) { - return sym.startswith("@") || sym.contains("@@") || sym.startswith("?") || - (!config->mingw && sym.contains('@')); +static bool isDecorated(StringRef Sym) { + return Sym.startswith("@") || Sym.contains("@@") || Sym.startswith("?") || + (!Config->MinGW && Sym.contains('@')); } // Parses .drectve section contents and returns a list of files // specified by /defaultlib. -void LinkerDriver::parseDirectives(InputFile *file) { - StringRef s = file->getDirectives(); - if (s.empty()) +void LinkerDriver::parseDirectives(InputFile *File) { + StringRef S = File->getDirectives(); + if (S.empty()) return; - log("Directives: " + toString(file) + ": " + s); + log("Directives: " + toString(File) + ": " + S); - ArgParser parser; + ArgParser Parser; // .drectve is always tokenized using Windows shell rules. // /EXPORT: option can appear too many times, processing in fastpath. - opt::InputArgList args; - std::vector exports; - std::tie(args, exports) = parser.parseDirectives(s); + opt::InputArgList Args; + std::vector Exports; + std::tie(Args, Exports) = Parser.parseDirectives(S); - for (StringRef e : exports) { + for (StringRef E : Exports) { // If a common header file contains dllexported function // declarations, many object files may end up with having the // same /EXPORT options. In order to save cost of parsing them, // we dedup them first. - if (!directivesExports.insert(e).second) + if (!DirectivesExports.insert(E).second) continue; - Export exp = parseExport(e); - if (config->machine == I386 && config->mingw) { - if (!isDecorated(exp.name)) - exp.name = saver.save("_" + exp.name); - if (!exp.extName.empty() && !isDecorated(exp.extName)) - exp.extName = saver.save("_" + exp.extName); + Export Exp = parseExport(E); + if (Config->Machine == I386 && Config->MinGW) { + if (!isDecorated(Exp.Name)) + Exp.Name = Saver.save("_" + Exp.Name); + if (!Exp.ExtName.empty() && !isDecorated(Exp.ExtName)) + Exp.ExtName = Saver.save("_" + Exp.ExtName); } - exp.directives = true; - config->exports.push_back(exp); + Exp.Directives = true; + Config->Exports.push_back(Exp); } - for (auto *arg : args) { - switch (arg->getOption().getID()) { + for (auto *Arg : Args) { + switch (Arg->getOption().getUnaliasedOption().getID()) { case OPT_aligncomm: - parseAligncomm(arg->getValue()); + parseAligncomm(Arg->getValue()); break; case OPT_alternatename: - parseAlternateName(arg->getValue()); + parseAlternateName(Arg->getValue()); break; case OPT_defaultlib: - if (Optional path = findLib(arg->getValue())) - enqueuePath(*path, false, false); + if (Optional Path = findLib(Arg->getValue())) + enqueuePath(*Path, false); break; case OPT_entry: - config->entry = addUndefined(mangle(arg->getValue())); + Config->Entry = addUndefined(mangle(Arg->getValue())); break; case OPT_failifmismatch: - checkFailIfMismatch(arg->getValue(), file); + checkFailIfMismatch(Arg->getValue(), File); break; case OPT_incl: - addUndefined(arg->getValue()); + addUndefined(Arg->getValue()); break; case OPT_merge: - parseMerge(arg->getValue()); + parseMerge(Arg->getValue()); break; case OPT_nodefaultlib: - config->noDefaultLibs.insert(doFindLib(arg->getValue()).lower()); + Config->NoDefaultLibs.insert(doFindLib(Arg->getValue()).lower()); break; case OPT_section: - parseSection(arg->getValue()); + parseSection(Arg->getValue()); break; case OPT_subsystem: - parseSubsystem(arg->getValue(), &config->subsystem, - &config->majorOSVersion, &config->minorOSVersion); + parseSubsystem(Arg->getValue(), &Config->Subsystem, + &Config->MajorOSVersion, &Config->MinorOSVersion); break; - // Only add flags here that link.exe accepts in - // `#pragma comment(linker, "/flag")`-generated sections. case OPT_editandcontinue: + case OPT_fastfail: case OPT_guardsym: + case OPT_natvis: case OPT_throwingnew: break; default: - error(arg->getSpelling() + " is not allowed in .drectve"); + error(Arg->getSpelling() + " is not allowed in .drectve"); } } } // Find file from search paths. You can omit ".obj", this function takes // care of that. Note that the returned path is not guaranteed to exist. -StringRef LinkerDriver::doFindFile(StringRef filename) { - bool hasPathSep = (filename.find_first_of("/\\") != StringRef::npos); - if (hasPathSep) - return filename; - bool hasExt = filename.contains('.'); - for (StringRef dir : searchPaths) { - SmallString<128> path = dir; - sys::path::append(path, filename); - if (sys::fs::exists(path.str())) - return saver.save(path.str()); - if (!hasExt) { - path.append(".obj"); - if (sys::fs::exists(path.str())) - return saver.save(path.str()); +StringRef LinkerDriver::doFindFile(StringRef Filename) { + bool HasPathSep = (Filename.find_first_of("/\\") != StringRef::npos); + if (HasPathSep) + return Filename; + bool HasExt = Filename.contains('.'); + for (StringRef Dir : SearchPaths) { + SmallString<128> Path = Dir; + sys::path::append(Path, Filename); + if (sys::fs::exists(Path.str())) + return Saver.save(Path.str()); + if (!HasExt) { + Path.append(".obj"); + if (sys::fs::exists(Path.str())) + return Saver.save(Path.str()); } } - return filename; + return Filename; } -static Optional getUniqueID(StringRef path) { - sys::fs::UniqueID ret; - if (sys::fs::getUniqueID(path, ret)) +static Optional getUniqueID(StringRef Path) { + sys::fs::UniqueID Ret; + if (sys::fs::getUniqueID(Path, Ret)) return None; - return ret; + return Ret; } // Resolves a file path. This never returns the same path // (in that case, it returns None). -Optional LinkerDriver::findFile(StringRef filename) { - StringRef path = doFindFile(filename); +Optional LinkerDriver::findFile(StringRef Filename) { + StringRef Path = doFindFile(Filename); - if (Optional id = getUniqueID(path)) { - bool seen = !visitedFiles.insert(*id).second; - if (seen) + if (Optional ID = getUniqueID(Path)) { + bool Seen = !VisitedFiles.insert(*ID).second; + if (Seen) return None; } - if (path.endswith_lower(".lib")) - visitedLibs.insert(sys::path::filename(path)); - return path; + if (Path.endswith_lower(".lib")) + VisitedLibs.insert(sys::path::filename(Path)); + return Path; } // MinGW specific. If an embedded directive specified to link to // foo.lib, but it isn't found, try libfoo.a instead. -StringRef LinkerDriver::doFindLibMinGW(StringRef filename) { - if (filename.contains('/') || filename.contains('\\')) - return filename; - - SmallString<128> s = filename; - sys::path::replace_extension(s, ".a"); - StringRef libName = saver.save("lib" + s.str()); - return doFindFile(libName); +StringRef LinkerDriver::doFindLibMinGW(StringRef Filename) { + if (Filename.contains('/') || Filename.contains('\\')) + return Filename; + + SmallString<128> S = Filename; + sys::path::replace_extension(S, ".a"); + StringRef LibName = Saver.save("lib" + S.str()); + return doFindFile(LibName); } // Find library file from search path. -StringRef LinkerDriver::doFindLib(StringRef filename) { +StringRef LinkerDriver::doFindLib(StringRef Filename) { // Add ".lib" to Filename if that has no file extension. - bool hasExt = filename.contains('.'); - if (!hasExt) - filename = saver.save(filename + ".lib"); - StringRef ret = doFindFile(filename); + bool HasExt = Filename.contains('.'); + if (!HasExt) + Filename = Saver.save(Filename + ".lib"); + StringRef Ret = doFindFile(Filename); // For MinGW, if the find above didn't turn up anything, try // looking for a MinGW formatted library name. - if (config->mingw && ret == filename) - return doFindLibMinGW(filename); - return ret; + if (Config->MinGW && Ret == Filename) + return doFindLibMinGW(Filename); + return Ret; } // Resolves a library path. /nodefaultlib options are taken into // consideration. This never returns the same path (in that case, // it returns None). -Optional LinkerDriver::findLib(StringRef filename) { - if (config->noDefaultLibAll) +Optional LinkerDriver::findLib(StringRef Filename) { + if (Config->NoDefaultLibAll) return None; - if (!visitedLibs.insert(filename.lower()).second) + if (!VisitedLibs.insert(Filename.lower()).second) return None; - StringRef path = doFindLib(filename); - if (config->noDefaultLibs.count(path.lower())) + StringRef Path = doFindLib(Filename); + if (Config->NoDefaultLibs.count(Path.lower())) return None; - if (Optional id = getUniqueID(path)) - if (!visitedFiles.insert(*id).second) + if (Optional ID = getUniqueID(Path)) + if (!VisitedFiles.insert(*ID).second) return None; - return path; + return Path; } // Parses LIB environment which contains a list of search paths. void LinkerDriver::addLibSearchPaths() { - Optional envOpt = Process::GetEnv("LIB"); - if (!envOpt.hasValue()) + Optional EnvOpt = Process::GetEnv("LIB"); + if (!EnvOpt.hasValue()) return; - StringRef env = saver.save(*envOpt); - while (!env.empty()) { - StringRef path; - std::tie(path, env) = env.split(';'); - searchPaths.push_back(path); + StringRef Env = Saver.save(*EnvOpt); + while (!Env.empty()) { + StringRef Path; + std::tie(Path, Env) = Env.split(';'); + SearchPaths.push_back(Path); } } -Symbol *LinkerDriver::addUndefined(StringRef name) { - Symbol *b = symtab->addUndefined(name); - if (!b->isGCRoot) { - b->isGCRoot = true; - config->gcroot.push_back(b); +Symbol *LinkerDriver::addUndefined(StringRef Name) { + Symbol *B = Symtab->addUndefined(Name); + if (!B->IsGCRoot) { + B->IsGCRoot = true; + Config->GCRoot.push_back(B); } - return b; + return B; } -StringRef LinkerDriver::mangleMaybe(Symbol *s) { +StringRef LinkerDriver::mangleMaybe(Symbol *S) { // If the plain symbol name has already been resolved, do nothing. - Undefined *unmangled = dyn_cast(s); - if (!unmangled) + Undefined *Unmangled = dyn_cast(S); + if (!Unmangled) return ""; // Otherwise, see if a similar, mangled symbol exists in the symbol table. - Symbol *mangled = symtab->findMangle(unmangled->getName()); - if (!mangled) + Symbol *Mangled = Symtab->findMangle(Unmangled->getName()); + if (!Mangled) return ""; // If we find a similar mangled symbol, make this an alias to it and return // its name. - log(unmangled->getName() + " aliased to " + mangled->getName()); - unmangled->weakAlias = symtab->addUndefined(mangled->getName()); - return mangled->getName(); + log(Unmangled->getName() + " aliased to " + Mangled->getName()); + Unmangled->WeakAlias = Symtab->addUndefined(Mangled->getName()); + return Mangled->getName(); } // Windows specific -- find default entry point name. @@ -536,15 +512,15 @@ StringRef LinkerDriver::mangleMaybe(Symbol *s) { // each of which corresponds to a user-defined "main" function. This function // infers an entry point from a user-defined "main" function. StringRef LinkerDriver::findDefaultEntry() { - assert(config->subsystem != IMAGE_SUBSYSTEM_UNKNOWN && + assert(Config->Subsystem != IMAGE_SUBSYSTEM_UNKNOWN && "must handle /subsystem before calling this"); - if (config->mingw) - return mangle(config->subsystem == IMAGE_SUBSYSTEM_WINDOWS_GUI + if (Config->MinGW) + return mangle(Config->Subsystem == IMAGE_SUBSYSTEM_WINDOWS_GUI ? "WinMainCRTStartup" : "mainCRTStartup"); - if (config->subsystem == IMAGE_SUBSYSTEM_WINDOWS_GUI) { + if (Config->Subsystem == IMAGE_SUBSYSTEM_WINDOWS_GUI) { if (findUnderscoreMangle("wWinMain")) { if (!findUnderscoreMangle("WinMain")) return mangle("wWinMainCRTStartup"); @@ -561,44 +537,44 @@ StringRef LinkerDriver::findDefaultEntry() { } WindowsSubsystem LinkerDriver::inferSubsystem() { - if (config->dll) + if (Config->DLL) return IMAGE_SUBSYSTEM_WINDOWS_GUI; - if (config->mingw) + if (Config->MinGW) return IMAGE_SUBSYSTEM_WINDOWS_CUI; // Note that link.exe infers the subsystem from the presence of these // functions even if /entry: or /nodefaultlib are passed which causes them // to not be called. - bool haveMain = findUnderscoreMangle("main"); - bool haveWMain = findUnderscoreMangle("wmain"); - bool haveWinMain = findUnderscoreMangle("WinMain"); - bool haveWWinMain = findUnderscoreMangle("wWinMain"); - if (haveMain || haveWMain) { - if (haveWinMain || haveWWinMain) { - warn(std::string("found ") + (haveMain ? "main" : "wmain") + " and " + - (haveWinMain ? "WinMain" : "wWinMain") + + bool HaveMain = findUnderscoreMangle("main"); + bool HaveWMain = findUnderscoreMangle("wmain"); + bool HaveWinMain = findUnderscoreMangle("WinMain"); + bool HaveWWinMain = findUnderscoreMangle("wWinMain"); + if (HaveMain || HaveWMain) { + if (HaveWinMain || HaveWWinMain) { + warn(std::string("found ") + (HaveMain ? "main" : "wmain") + " and " + + (HaveWinMain ? "WinMain" : "wWinMain") + "; defaulting to /subsystem:console"); } return IMAGE_SUBSYSTEM_WINDOWS_CUI; } - if (haveWinMain || haveWWinMain) + if (HaveWinMain || HaveWWinMain) return IMAGE_SUBSYSTEM_WINDOWS_GUI; return IMAGE_SUBSYSTEM_UNKNOWN; } static uint64_t getDefaultImageBase() { - if (config->is64()) - return config->dll ? 0x180000000 : 0x140000000; - return config->dll ? 0x10000000 : 0x400000; + if (Config->is64()) + return Config->DLL ? 0x180000000 : 0x140000000; + return Config->DLL ? 0x10000000 : 0x400000; } -static std::string createResponseFile(const opt::InputArgList &args, - ArrayRef filePaths, - ArrayRef searchPaths) { - SmallString<0> data; - raw_svector_ostream os(data); +static std::string createResponseFile(const opt::InputArgList &Args, + ArrayRef FilePaths, + ArrayRef SearchPaths) { + SmallString<0> Data; + raw_svector_ostream OS(Data); - for (auto *arg : args) { - switch (arg->getOption().getID()) { + for (auto *Arg : Args) { + switch (Arg->getOption().getID()) { case OPT_linkrepro: case OPT_INPUT: case OPT_defaultlib: @@ -613,34 +589,34 @@ static std::string createResponseFile(const opt::InputArgList &args, case OPT_implib: case OPT_pdb: case OPT_out: - os << arg->getSpelling() << sys::path::filename(arg->getValue()) << "\n"; + OS << Arg->getSpelling() << sys::path::filename(Arg->getValue()) << "\n"; break; default: - os << toString(*arg) << "\n"; + OS << toString(*Arg) << "\n"; } } - for (StringRef path : searchPaths) { - std::string relPath = relativeToRoot(path); - os << "/libpath:" << quote(relPath) << "\n"; + for (StringRef Path : SearchPaths) { + std::string RelPath = relativeToRoot(Path); + OS << "/libpath:" << quote(RelPath) << "\n"; } - for (StringRef path : filePaths) - os << quote(relativeToRoot(path)) << "\n"; + for (StringRef Path : FilePaths) + OS << quote(relativeToRoot(Path)) << "\n"; - return data.str(); + return Data.str(); } enum class DebugKind { Unknown, None, Full, FastLink, GHash, Dwarf, Symtab }; -static DebugKind parseDebugKind(const opt::InputArgList &args) { - auto *a = args.getLastArg(OPT_debug, OPT_debug_opt); - if (!a) +static DebugKind parseDebugKind(const opt::InputArgList &Args) { + auto *A = Args.getLastArg(OPT_debug, OPT_debug_opt); + if (!A) return DebugKind::None; - if (a->getNumValues() == 0) + if (A->getNumValues() == 0) return DebugKind::Full; - DebugKind debug = StringSwitch(a->getValue()) + DebugKind Debug = StringSwitch(A->getValue()) .CaseLower("none", DebugKind::None) .CaseLower("full", DebugKind::Full) .CaseLower("fastlink", DebugKind::FastLink) @@ -650,68 +626,67 @@ static DebugKind parseDebugKind(const opt::InputArgList &args) { .CaseLower("symtab", DebugKind::Symtab) .Default(DebugKind::Unknown); - if (debug == DebugKind::FastLink) { + if (Debug == DebugKind::FastLink) { warn("/debug:fastlink unsupported; using /debug:full"); return DebugKind::Full; } - if (debug == DebugKind::Unknown) { - error("/debug: unknown option: " + Twine(a->getValue())); + if (Debug == DebugKind::Unknown) { + error("/debug: unknown option: " + Twine(A->getValue())); return DebugKind::None; } - return debug; + return Debug; } -static unsigned parseDebugTypes(const opt::InputArgList &args) { - unsigned debugTypes = static_cast(DebugType::None); +static unsigned parseDebugTypes(const opt::InputArgList &Args) { + unsigned DebugTypes = static_cast(DebugType::None); - if (auto *a = args.getLastArg(OPT_debugtype)) { - SmallVector types; - StringRef(a->getValue()) - .split(types, ',', /*MaxSplit=*/-1, /*KeepEmpty=*/false); + if (auto *A = Args.getLastArg(OPT_debugtype)) { + SmallVector Types; + A->getSpelling().split(Types, ',', /*KeepEmpty=*/false); - for (StringRef type : types) { - unsigned v = StringSwitch(type.lower()) + for (StringRef Type : Types) { + unsigned V = StringSwitch(Type.lower()) .Case("cv", static_cast(DebugType::CV)) .Case("pdata", static_cast(DebugType::PData)) .Case("fixup", static_cast(DebugType::Fixup)) .Default(0); - if (v == 0) { - warn("/debugtype: unknown option '" + type + "'"); + if (V == 0) { + warn("/debugtype: unknown option: " + Twine(A->getValue())); continue; } - debugTypes |= v; + DebugTypes |= V; } - return debugTypes; + return DebugTypes; } // Default debug types - debugTypes = static_cast(DebugType::CV); - if (args.hasArg(OPT_driver)) - debugTypes |= static_cast(DebugType::PData); - if (args.hasArg(OPT_profile)) - debugTypes |= static_cast(DebugType::Fixup); + DebugTypes = static_cast(DebugType::CV); + if (Args.hasArg(OPT_driver)) + DebugTypes |= static_cast(DebugType::PData); + if (Args.hasArg(OPT_profile)) + DebugTypes |= static_cast(DebugType::Fixup); - return debugTypes; + return DebugTypes; } -static std::string getMapFile(const opt::InputArgList &args) { - auto *arg = args.getLastArg(OPT_lldmap, OPT_lldmap_file); - if (!arg) +static std::string getMapFile(const opt::InputArgList &Args) { + auto *Arg = Args.getLastArg(OPT_lldmap, OPT_lldmap_file); + if (!Arg) return ""; - if (arg->getOption().getID() == OPT_lldmap_file) - return arg->getValue(); + if (Arg->getOption().getID() == OPT_lldmap_file) + return Arg->getValue(); - assert(arg->getOption().getID() == OPT_lldmap); - StringRef outFile = config->outputFile; - return (outFile.substr(0, outFile.rfind('.')) + ".map").str(); + assert(Arg->getOption().getID() == OPT_lldmap); + StringRef OutFile = Config->OutputFile; + return (OutFile.substr(0, OutFile.rfind('.')) + ".map").str(); } static std::string getImplibPath() { - if (!config->implib.empty()) - return config->implib; - SmallString<128> out = StringRef(config->outputFile); - sys::path::replace_extension(out, ".lib"); - return out.str(); + if (!Config->Implib.empty()) + return Config->Implib; + SmallString<128> Out = StringRef(Config->OutputFile); + sys::path::replace_extension(Out, ".lib"); + return Out.str(); } // @@ -722,312 +697,305 @@ static std::string getImplibPath() { // LINK | {value} | {value}.{.dll/.exe} | {output name} // LIB | {value} | {value}.dll | {output name}.dll // -static std::string getImportName(bool asLib) { - SmallString<128> out; +static std::string getImportName(bool AsLib) { + SmallString<128> Out; - if (config->importName.empty()) { - out.assign(sys::path::filename(config->outputFile)); - if (asLib) - sys::path::replace_extension(out, ".dll"); + if (Config->ImportName.empty()) { + Out.assign(sys::path::filename(Config->OutputFile)); + if (AsLib) + sys::path::replace_extension(Out, ".dll"); } else { - out.assign(config->importName); - if (!sys::path::has_extension(out)) - sys::path::replace_extension(out, - (config->dll || asLib) ? ".dll" : ".exe"); + Out.assign(Config->ImportName); + if (!sys::path::has_extension(Out)) + sys::path::replace_extension(Out, + (Config->DLL || AsLib) ? ".dll" : ".exe"); } - return out.str(); + return Out.str(); } -static void createImportLibrary(bool asLib) { - std::vector exports; - for (Export &e1 : config->exports) { - COFFShortExport e2; - e2.Name = e1.name; - e2.SymbolName = e1.symbolName; - e2.ExtName = e1.extName; - e2.Ordinal = e1.ordinal; - e2.Noname = e1.noname; - e2.Data = e1.data; - e2.Private = e1.isPrivate; - e2.Constant = e1.constant; - exports.push_back(e2); - } - - auto handleError = [](Error &&e) { - handleAllErrors(std::move(e), - [](ErrorInfoBase &eib) { error(eib.message()); }); +static void createImportLibrary(bool AsLib) { + std::vector Exports; + for (Export &E1 : Config->Exports) { + COFFShortExport E2; + E2.Name = E1.Name; + E2.SymbolName = E1.SymbolName; + E2.ExtName = E1.ExtName; + E2.Ordinal = E1.Ordinal; + E2.Noname = E1.Noname; + E2.Data = E1.Data; + E2.Private = E1.Private; + E2.Constant = E1.Constant; + Exports.push_back(E2); + } + + auto HandleError = [](Error &&E) { + handleAllErrors(std::move(E), + [](ErrorInfoBase &EIB) { error(EIB.message()); }); }; - std::string libName = getImportName(asLib); - std::string path = getImplibPath(); + std::string LibName = getImportName(AsLib); + std::string Path = getImplibPath(); - if (!config->incremental) { - handleError(writeImportLibrary(libName, path, exports, config->machine, - config->mingw)); + if (!Config->Incremental) { + HandleError(writeImportLibrary(LibName, Path, Exports, Config->Machine, + Config->MinGW)); return; } // If the import library already exists, replace it only if the contents // have changed. - ErrorOr> oldBuf = MemoryBuffer::getFile( - path, /*FileSize*/ -1, /*RequiresNullTerminator*/ false); - if (!oldBuf) { - handleError(writeImportLibrary(libName, path, exports, config->machine, - config->mingw)); + ErrorOr> OldBuf = MemoryBuffer::getFile( + Path, /*FileSize*/ -1, /*RequiresNullTerminator*/ false); + if (!OldBuf) { + HandleError(writeImportLibrary(LibName, Path, Exports, Config->Machine, + Config->MinGW)); return; } - SmallString<128> tmpName; - if (std::error_code ec = - sys::fs::createUniqueFile(path + ".tmp-%%%%%%%%.lib", tmpName)) - fatal("cannot create temporary file for import library " + path + ": " + - ec.message()); + SmallString<128> TmpName; + if (std::error_code EC = + sys::fs::createUniqueFile(Path + ".tmp-%%%%%%%%.lib", TmpName)) + fatal("cannot create temporary file for import library " + Path + ": " + + EC.message()); - if (Error e = writeImportLibrary(libName, tmpName, exports, config->machine, - config->mingw)) { - handleError(std::move(e)); + if (Error E = writeImportLibrary(LibName, TmpName, Exports, Config->Machine, + Config->MinGW)) { + HandleError(std::move(E)); return; } - std::unique_ptr newBuf = check(MemoryBuffer::getFile( - tmpName, /*FileSize*/ -1, /*RequiresNullTerminator*/ false)); - if ((*oldBuf)->getBuffer() != newBuf->getBuffer()) { - oldBuf->reset(); - handleError(errorCodeToError(sys::fs::rename(tmpName, path))); + std::unique_ptr NewBuf = check(MemoryBuffer::getFile( + TmpName, /*FileSize*/ -1, /*RequiresNullTerminator*/ false)); + if ((*OldBuf)->getBuffer() != NewBuf->getBuffer()) { + OldBuf->reset(); + HandleError(errorCodeToError(sys::fs::rename(TmpName, Path))); } else { - sys::fs::remove(tmpName); + sys::fs::remove(TmpName); } } -static void parseModuleDefs(StringRef path) { - std::unique_ptr mb = CHECK( - MemoryBuffer::getFile(path, -1, false, true), "could not open " + path); - COFFModuleDefinition m = check(parseCOFFModuleDefinition( - mb->getMemBufferRef(), config->machine, config->mingw)); - - if (config->outputFile.empty()) - config->outputFile = saver.save(m.OutputFile); - config->importName = saver.save(m.ImportName); - if (m.ImageBase) - config->imageBase = m.ImageBase; - if (m.StackReserve) - config->stackReserve = m.StackReserve; - if (m.StackCommit) - config->stackCommit = m.StackCommit; - if (m.HeapReserve) - config->heapReserve = m.HeapReserve; - if (m.HeapCommit) - config->heapCommit = m.HeapCommit; - if (m.MajorImageVersion) - config->majorImageVersion = m.MajorImageVersion; - if (m.MinorImageVersion) - config->minorImageVersion = m.MinorImageVersion; - if (m.MajorOSVersion) - config->majorOSVersion = m.MajorOSVersion; - if (m.MinorOSVersion) - config->minorOSVersion = m.MinorOSVersion; - - for (COFFShortExport e1 : m.Exports) { - Export e2; +static void parseModuleDefs(StringRef Path) { + std::unique_ptr MB = CHECK( + MemoryBuffer::getFile(Path, -1, false, true), "could not open " + Path); + COFFModuleDefinition M = check(parseCOFFModuleDefinition( + MB->getMemBufferRef(), Config->Machine, Config->MinGW)); + + if (Config->OutputFile.empty()) + Config->OutputFile = Saver.save(M.OutputFile); + Config->ImportName = Saver.save(M.ImportName); + if (M.ImageBase) + Config->ImageBase = M.ImageBase; + if (M.StackReserve) + Config->StackReserve = M.StackReserve; + if (M.StackCommit) + Config->StackCommit = M.StackCommit; + if (M.HeapReserve) + Config->HeapReserve = M.HeapReserve; + if (M.HeapCommit) + Config->HeapCommit = M.HeapCommit; + if (M.MajorImageVersion) + Config->MajorImageVersion = M.MajorImageVersion; + if (M.MinorImageVersion) + Config->MinorImageVersion = M.MinorImageVersion; + if (M.MajorOSVersion) + Config->MajorOSVersion = M.MajorOSVersion; + if (M.MinorOSVersion) + Config->MinorOSVersion = M.MinorOSVersion; + + for (COFFShortExport E1 : M.Exports) { + Export E2; // In simple cases, only Name is set. Renamed exports are parsed // and set as "ExtName = Name". If Name has the form "OtherDll.Func", // it shouldn't be a normal exported function but a forward to another // DLL instead. This is supported by both MS and GNU linkers. - if (e1.ExtName != e1.Name && StringRef(e1.Name).contains('.')) { - e2.name = saver.save(e1.ExtName); - e2.forwardTo = saver.save(e1.Name); - config->exports.push_back(e2); + if (E1.ExtName != E1.Name && StringRef(E1.Name).contains('.')) { + E2.Name = Saver.save(E1.ExtName); + E2.ForwardTo = Saver.save(E1.Name); + Config->Exports.push_back(E2); continue; } - e2.name = saver.save(e1.Name); - e2.extName = saver.save(e1.ExtName); - e2.ordinal = e1.Ordinal; - e2.noname = e1.Noname; - e2.data = e1.Data; - e2.isPrivate = e1.Private; - e2.constant = e1.Constant; - config->exports.push_back(e2); + E2.Name = Saver.save(E1.Name); + E2.ExtName = Saver.save(E1.ExtName); + E2.Ordinal = E1.Ordinal; + E2.Noname = E1.Noname; + E2.Data = E1.Data; + E2.Private = E1.Private; + E2.Constant = E1.Constant; + Config->Exports.push_back(E2); } } -void LinkerDriver::enqueueTask(std::function task) { - taskQueue.push_back(std::move(task)); +void LinkerDriver::enqueueTask(std::function Task) { + TaskQueue.push_back(std::move(Task)); } bool LinkerDriver::run() { - ScopedTimer t(inputFileTimer); + ScopedTimer T(InputFileTimer); - bool didWork = !taskQueue.empty(); - while (!taskQueue.empty()) { - taskQueue.front()(); - taskQueue.pop_front(); + bool DidWork = !TaskQueue.empty(); + while (!TaskQueue.empty()) { + TaskQueue.front()(); + TaskQueue.pop_front(); } - return didWork; + return DidWork; } // Parse an /order file. If an option is given, the linker places // COMDAT sections in the same order as their names appear in the // given file. -static void parseOrderFile(StringRef arg) { +static void parseOrderFile(StringRef Arg) { // For some reason, the MSVC linker requires a filename to be // preceded by "@". - if (!arg.startswith("@")) { + if (!Arg.startswith("@")) { error("malformed /order option: '@' missing"); return; } // Get a list of all comdat sections for error checking. - DenseSet set; - for (Chunk *c : symtab->getChunks()) - if (auto *sec = dyn_cast(c)) - if (sec->sym) - set.insert(sec->sym->getName()); + DenseSet Set; + for (Chunk *C : Symtab->getChunks()) + if (auto *Sec = dyn_cast(C)) + if (Sec->Sym) + Set.insert(Sec->Sym->getName()); // Open a file. - StringRef path = arg.substr(1); - std::unique_ptr mb = CHECK( - MemoryBuffer::getFile(path, -1, false, true), "could not open " + path); + StringRef Path = Arg.substr(1); + std::unique_ptr MB = CHECK( + MemoryBuffer::getFile(Path, -1, false, true), "could not open " + Path); // Parse a file. An order file contains one symbol per line. // All symbols that were not present in a given order file are // considered to have the lowest priority 0 and are placed at // end of an output section. - for (std::string s : args::getLines(mb->getMemBufferRef())) { - if (config->machine == I386 && !isDecorated(s)) - s = "_" + s; + for (std::string S : args::getLines(MB->getMemBufferRef())) { + if (Config->Machine == I386 && !isDecorated(S)) + S = "_" + S; - if (set.count(s) == 0) { - if (config->warnMissingOrderSymbol) - warn("/order:" + arg + ": missing symbol: " + s + " [LNK4037]"); + if (Set.count(S) == 0) { + if (Config->WarnMissingOrderSymbol) + warn("/order:" + Arg + ": missing symbol: " + S + " [LNK4037]"); } else - config->order[s] = INT_MIN + config->order.size(); + Config->Order[S] = INT_MIN + Config->Order.size(); } } -static void markAddrsig(Symbol *s) { - if (auto *d = dyn_cast_or_null(s)) - if (SectionChunk *c = dyn_cast_or_null(d->getChunk())) - c->keepUnique = true; +static void markAddrsig(Symbol *S) { + if (auto *D = dyn_cast_or_null(S)) + if (SectionChunk *C = dyn_cast_or_null(D->getChunk())) + C->KeepUnique = true; } static void findKeepUniqueSections() { // Exported symbols could be address-significant in other executables or DSOs, // so we conservatively mark them as address-significant. - for (Export &r : config->exports) - markAddrsig(r.sym); + for (Export &R : Config->Exports) + markAddrsig(R.Sym); // Visit the address-significance table in each object file and mark each // referenced symbol as address-significant. - for (ObjFile *obj : ObjFile::instances) { - ArrayRef syms = obj->getSymbols(); - if (obj->addrsigSec) { - ArrayRef contents; + for (ObjFile *Obj : ObjFile::Instances) { + ArrayRef Syms = Obj->getSymbols(); + if (Obj->AddrsigSec) { + ArrayRef Contents; cantFail( - obj->getCOFFObj()->getSectionContents(obj->addrsigSec, contents)); - const uint8_t *cur = contents.begin(); - while (cur != contents.end()) { - unsigned size; - const char *err; - uint64_t symIndex = decodeULEB128(cur, &size, contents.end(), &err); - if (err) - fatal(toString(obj) + ": could not decode addrsig section: " + err); - if (symIndex >= syms.size()) - fatal(toString(obj) + ": invalid symbol index in addrsig section"); - markAddrsig(syms[symIndex]); - cur += size; + Obj->getCOFFObj()->getSectionContents(Obj->AddrsigSec, Contents)); + const uint8_t *Cur = Contents.begin(); + while (Cur != Contents.end()) { + unsigned Size; + const char *Err; + uint64_t SymIndex = decodeULEB128(Cur, &Size, Contents.end(), &Err); + if (Err) + fatal(toString(Obj) + ": could not decode addrsig section: " + Err); + if (SymIndex >= Syms.size()) + fatal(toString(Obj) + ": invalid symbol index in addrsig section"); + markAddrsig(Syms[SymIndex]); + Cur += Size; } } else { // If an object file does not have an address-significance table, // conservatively mark all of its symbols as address-significant. - for (Symbol *s : syms) - markAddrsig(s); + for (Symbol *S : Syms) + markAddrsig(S); } } } -// link.exe replaces each %foo% in altPath with the contents of environment +// link.exe replaces each %foo% in AltPath with the contents of environment // variable foo, and adds the two magic env vars _PDB (expands to the basename // of pdb's output path) and _EXT (expands to the extension of the output // binary). // lld only supports %_PDB% and %_EXT% and warns on references to all other env // vars. -static void parsePDBAltPath(StringRef altPath) { - SmallString<128> buf; - StringRef pdbBasename = - sys::path::filename(config->pdbPath, sys::path::Style::windows); - StringRef binaryExtension = - sys::path::extension(config->outputFile, sys::path::Style::windows); - if (!binaryExtension.empty()) - binaryExtension = binaryExtension.substr(1); // %_EXT% does not include '.'. +static void parsePDBAltPath(StringRef AltPath) { + SmallString<128> Buf; + StringRef PDBBasename = + sys::path::filename(Config->PDBPath, sys::path::Style::windows); + StringRef BinaryExtension = + sys::path::extension(Config->OutputFile, sys::path::Style::windows); + if (!BinaryExtension.empty()) + BinaryExtension = BinaryExtension.substr(1); // %_EXT% does not include '.'. // Invariant: - // +--------- cursor ('a...' might be the empty string). - // | +----- firstMark - // | | +- secondMark + // +--------- Cursor ('a...' might be the empty string). + // | +----- FirstMark + // | | +- SecondMark // v v v // a...%...%... - size_t cursor = 0; - while (cursor < altPath.size()) { - size_t firstMark, secondMark; - if ((firstMark = altPath.find('%', cursor)) == StringRef::npos || - (secondMark = altPath.find('%', firstMark + 1)) == StringRef::npos) { + size_t Cursor = 0; + while (Cursor < AltPath.size()) { + size_t FirstMark, SecondMark; + if ((FirstMark = AltPath.find('%', Cursor)) == StringRef::npos || + (SecondMark = AltPath.find('%', FirstMark + 1)) == StringRef::npos) { // Didn't find another full fragment, treat rest of string as literal. - buf.append(altPath.substr(cursor)); + Buf.append(AltPath.substr(Cursor)); break; } // Found a full fragment. Append text in front of first %, and interpret // text between first and second % as variable name. - buf.append(altPath.substr(cursor, firstMark - cursor)); - StringRef var = altPath.substr(firstMark, secondMark - firstMark + 1); - if (var.equals_lower("%_pdb%")) - buf.append(pdbBasename); - else if (var.equals_lower("%_ext%")) - buf.append(binaryExtension); + Buf.append(AltPath.substr(Cursor, FirstMark - Cursor)); + StringRef Var = AltPath.substr(FirstMark, SecondMark - FirstMark + 1); + if (Var.equals_lower("%_pdb%")) + Buf.append(PDBBasename); + else if (Var.equals_lower("%_ext%")) + Buf.append(BinaryExtension); else { warn("only %_PDB% and %_EXT% supported in /pdbaltpath:, keeping " + - var + " as literal"); - buf.append(var); + Var + " as literal"); + Buf.append(Var); } - cursor = secondMark + 1; + Cursor = SecondMark + 1; } - config->pdbAltPath = buf; + Config->PDBAltPath = Buf; } -/// Convert resource files and potentially merge input resource object -/// trees into one resource tree. +/// Check that at most one resource obj file was used. /// Call after ObjFile::Instances is complete. -void LinkerDriver::convertResources() { - std::vector resourceObjFiles; +static void diagnoseMultipleResourceObjFiles() { + // The .rsrc$01 section in a resource obj file contains a tree description + // of resources. Merging multiple resource obj files would require merging + // the trees instead of using usual linker section merging semantics. + // Since link.exe disallows linking more than one resource obj file with + // LNK4078, mirror that. The normal use of resource files is to give the + // linker many .res files, which are then converted to a single resource obj + // file internally, so this is not a big restriction in practice. + ObjFile *ResourceObjFile = nullptr; + for (ObjFile *F : ObjFile::Instances) { + if (!F->IsResourceObjFile) + continue; - for (ObjFile *f : ObjFile::instances) { - if (f->isResourceObjFile()) - resourceObjFiles.push_back(f); - } + if (!ResourceObjFile) { + ResourceObjFile = F; + continue; + } - if (!config->mingw && - (resourceObjFiles.size() > 1 || - (resourceObjFiles.size() == 1 && !resources.empty()))) { - error((!resources.empty() ? "internal .obj file created from .res files" - : toString(resourceObjFiles[1])) + + error(toString(F) + ": more than one resource obj file not allowed, already got " + - toString(resourceObjFiles.front())); - return; - } - - if (resources.empty() && resourceObjFiles.size() <= 1) { - // No resources to convert, and max one resource object file in - // the input. Keep that preconverted resource section as is. - for (ObjFile *f : resourceObjFiles) - f->includeResourceChunks(); - return; + toString(ResourceObjFile)); } - ObjFile *f = make(convertResToCOFF(resources, resourceObjFiles)); - symtab->addFile(f); - f->includeResourceChunks(); } // In MinGW, if no symbols are chosen to be exported, then all symbols are @@ -1036,45 +1004,39 @@ void LinkerDriver::convertResources() { // explicitly specified. The automatic behavior can be disabled using the // -exclude-all-symbols option, so that lld-link behaves like link.exe rather // than MinGW in the case that nothing is explicitly exported. -void LinkerDriver::maybeExportMinGWSymbols(const opt::InputArgList &args) { - if (!config->dll) +void LinkerDriver::maybeExportMinGWSymbols(const opt::InputArgList &Args) { + if (!Config->DLL) return; - if (!args.hasArg(OPT_export_all_symbols)) { - if (!config->exports.empty()) + if (!Args.hasArg(OPT_export_all_symbols)) { + if (!Config->Exports.empty()) return; - if (args.hasArg(OPT_exclude_all_symbols)) + if (Args.hasArg(OPT_exclude_all_symbols)) return; } - AutoExporter exporter; + AutoExporter Exporter; - for (auto *arg : args.filtered(OPT_wholearchive_file)) - if (Optional path = doFindFile(arg->getValue())) - exporter.addWholeArchive(*path); + for (auto *Arg : Args.filtered(OPT_wholearchive_file)) + if (Optional Path = doFindFile(Arg->getValue())) + Exporter.addWholeArchive(*Path); - symtab->forEachSymbol([&](Symbol *s) { - auto *def = dyn_cast(s); - if (!exporter.shouldExport(def)) + Symtab->forEachSymbol([&](Symbol *S) { + auto *Def = dyn_cast(S); + if (!Exporter.shouldExport(Def)) return; - Export e; - e.name = def->getName(); - e.sym = def; - if (Chunk *c = def->getChunk()) - if (!(c->getOutputCharacteristics() & IMAGE_SCN_MEM_EXECUTE)) - e.data = true; - config->exports.push_back(e); + Export E; + E.Name = Def->getName(); + E.Sym = Def; + if (Chunk *C = Def->getChunk()) + if (!(C->getOutputCharacteristics() & IMAGE_SCN_MEM_EXECUTE)) + E.Data = true; + Config->Exports.push_back(E); }); } -static const char *libcallRoutineNames[] = { -#define HANDLE_LIBCALL(code, name) name, -#include "llvm/IR/RuntimeLibcalls.def" -#undef HANDLE_LIBCALL -}; - -void LinkerDriver::link(ArrayRef argsArr) { +void LinkerDriver::link(ArrayRef ArgsArr) { // Needed for LTO. InitializeAllTargetInfos(); InitializeAllTargets(); @@ -1084,306 +1046,306 @@ void LinkerDriver::link(ArrayRef argsArr) { // If the first command line argument is "/lib", link.exe acts like lib.exe. // We call our own implementation of lib.exe that understands bitcode files. - if (argsArr.size() > 1 && StringRef(argsArr[1]).equals_lower("/lib")) { - if (llvm::libDriverMain(argsArr.slice(1)) != 0) + if (ArgsArr.size() > 1 && StringRef(ArgsArr[1]).equals_lower("/lib")) { + if (llvm::libDriverMain(ArgsArr.slice(1)) != 0) fatal("lib failed"); return; } // Parse command line options. - ArgParser parser; - opt::InputArgList args = parser.parseLINK(argsArr); + ArgParser Parser; + opt::InputArgList Args = Parser.parseLINK(ArgsArr); // Parse and evaluate -mllvm options. - std::vector v; - v.push_back("lld-link (LLVM option parsing)"); - for (auto *arg : args.filtered(OPT_mllvm)) - v.push_back(arg->getValue()); - cl::ParseCommandLineOptions(v.size(), v.data()); + std::vector V; + V.push_back("lld-link (LLVM option parsing)"); + for (auto *Arg : Args.filtered(OPT_mllvm)) + V.push_back(Arg->getValue()); + cl::ParseCommandLineOptions(V.size(), V.data()); // Handle /errorlimit early, because error() depends on it. - if (auto *arg = args.getLastArg(OPT_errorlimit)) { - int n = 20; - StringRef s = arg->getValue(); - if (s.getAsInteger(10, n)) - error(arg->getSpelling() + " number expected, but got " + s); - errorHandler().errorLimit = n; + if (auto *Arg = Args.getLastArg(OPT_errorlimit)) { + int N = 20; + StringRef S = Arg->getValue(); + if (S.getAsInteger(10, N)) + error(Arg->getSpelling() + " number expected, but got " + S); + errorHandler().ErrorLimit = N; } // Handle /help - if (args.hasArg(OPT_help)) { - printHelp(argsArr[0]); + if (Args.hasArg(OPT_help)) { + printHelp(ArgsArr[0]); return; } - lld::threadsEnabled = args.hasFlag(OPT_threads, OPT_threads_no, true); + lld::ThreadsEnabled = Args.hasFlag(OPT_threads, OPT_threads_no, true); - if (args.hasArg(OPT_show_timing)) - config->showTiming = true; + if (Args.hasArg(OPT_show_timing)) + Config->ShowTiming = true; - config->showSummary = args.hasArg(OPT_summary); + Config->ShowSummary = Args.hasArg(OPT_summary); - ScopedTimer t(Timer::root()); + ScopedTimer T(Timer::root()); // Handle --version, which is an lld extension. This option is a bit odd // because it doesn't start with "/", but we deliberately chose "--" to // avoid conflict with /version and for compatibility with clang-cl. - if (args.hasArg(OPT_dash_dash_version)) { + if (Args.hasArg(OPT_dash_dash_version)) { outs() << getLLDVersion() << "\n"; return; } // Handle /lldmingw early, since it can potentially affect how other // options are handled. - config->mingw = args.hasArg(OPT_lldmingw); + Config->MinGW = Args.hasArg(OPT_lldmingw); - if (auto *arg = args.getLastArg(OPT_linkrepro)) { - SmallString<64> path = StringRef(arg->getValue()); - sys::path::append(path, "repro.tar"); + if (auto *Arg = Args.getLastArg(OPT_linkrepro)) { + SmallString<64> Path = StringRef(Arg->getValue()); + sys::path::append(Path, "repro.tar"); - Expected> errOrWriter = - TarWriter::create(path, "repro"); + Expected> ErrOrWriter = + TarWriter::create(Path, "repro"); - if (errOrWriter) { - tar = std::move(*errOrWriter); + if (ErrOrWriter) { + Tar = std::move(*ErrOrWriter); } else { - error("/linkrepro: failed to open " + path + ": " + - toString(errOrWriter.takeError())); + error("/linkrepro: failed to open " + Path + ": " + + toString(ErrOrWriter.takeError())); } } - if (!args.hasArg(OPT_INPUT)) { - if (args.hasArg(OPT_deffile)) - config->noEntry = true; + if (!Args.hasArg(OPT_INPUT)) { + if (Args.hasArg(OPT_deffile)) + Config->NoEntry = true; else fatal("no input files"); } // Construct search path list. - searchPaths.push_back(""); - for (auto *arg : args.filtered(OPT_libpath)) - searchPaths.push_back(arg->getValue()); + SearchPaths.push_back(""); + for (auto *Arg : Args.filtered(OPT_libpath)) + SearchPaths.push_back(Arg->getValue()); addLibSearchPaths(); // Handle /ignore - for (auto *arg : args.filtered(OPT_ignore)) { - SmallVector vec; - StringRef(arg->getValue()).split(vec, ','); - for (StringRef s : vec) { - if (s == "4037") - config->warnMissingOrderSymbol = false; - else if (s == "4099") - config->warnDebugInfoUnusable = false; - else if (s == "4217") - config->warnLocallyDefinedImported = false; + for (auto *Arg : Args.filtered(OPT_ignore)) { + SmallVector Vec; + StringRef(Arg->getValue()).split(Vec, ','); + for (StringRef S : Vec) { + if (S == "4037") + Config->WarnMissingOrderSymbol = false; + else if (S == "4099") + Config->WarnDebugInfoUnusable = false; + else if (S == "4217") + Config->WarnLocallyDefinedImported = false; // Other warning numbers are ignored. } } // Handle /out - if (auto *arg = args.getLastArg(OPT_out)) - config->outputFile = arg->getValue(); + if (auto *Arg = Args.getLastArg(OPT_out)) + Config->OutputFile = Arg->getValue(); // Handle /verbose - if (args.hasArg(OPT_verbose)) - config->verbose = true; - errorHandler().verbose = config->verbose; + if (Args.hasArg(OPT_verbose)) + Config->Verbose = true; + errorHandler().Verbose = Config->Verbose; // Handle /force or /force:unresolved - if (args.hasArg(OPT_force, OPT_force_unresolved)) - config->forceUnresolved = true; + if (Args.hasArg(OPT_force, OPT_force_unresolved)) + Config->ForceUnresolved = true; // Handle /force or /force:multiple - if (args.hasArg(OPT_force, OPT_force_multiple)) - config->forceMultiple = true; + if (Args.hasArg(OPT_force, OPT_force_multiple)) + Config->ForceMultiple = true; // Handle /force or /force:multipleres - if (args.hasArg(OPT_force, OPT_force_multipleres)) - config->forceMultipleRes = true; + if (Args.hasArg(OPT_force, OPT_force_multipleres)) + Config->ForceMultipleRes = true; // Handle /debug - DebugKind debug = parseDebugKind(args); - if (debug == DebugKind::Full || debug == DebugKind::Dwarf || - debug == DebugKind::GHash) { - config->debug = true; - config->incremental = true; + DebugKind Debug = parseDebugKind(Args); + if (Debug == DebugKind::Full || Debug == DebugKind::Dwarf || + Debug == DebugKind::GHash) { + Config->Debug = true; + Config->Incremental = true; } // Handle /demangle - config->demangle = args.hasFlag(OPT_demangle, OPT_demangle_no); + Config->Demangle = Args.hasFlag(OPT_demangle, OPT_demangle_no); // Handle /debugtype - config->debugTypes = parseDebugTypes(args); + Config->DebugTypes = parseDebugTypes(Args); // Handle /pdb - bool shouldCreatePDB = - (debug == DebugKind::Full || debug == DebugKind::GHash); - if (shouldCreatePDB) { - if (auto *arg = args.getLastArg(OPT_pdb)) - config->pdbPath = arg->getValue(); - if (auto *arg = args.getLastArg(OPT_pdbaltpath)) - config->pdbAltPath = arg->getValue(); - if (args.hasArg(OPT_natvis)) - config->natvisFiles = args.getAllArgValues(OPT_natvis); + bool ShouldCreatePDB = + (Debug == DebugKind::Full || Debug == DebugKind::GHash); + if (ShouldCreatePDB) { + if (auto *Arg = Args.getLastArg(OPT_pdb)) + Config->PDBPath = Arg->getValue(); + if (auto *Arg = Args.getLastArg(OPT_pdbaltpath)) + Config->PDBAltPath = Arg->getValue(); + if (Args.hasArg(OPT_natvis)) + Config->NatvisFiles = Args.getAllArgValues(OPT_natvis); - if (auto *arg = args.getLastArg(OPT_pdb_source_path)) - config->pdbSourcePath = arg->getValue(); + if (auto *Arg = Args.getLastArg(OPT_pdb_source_path)) + Config->PDBSourcePath = Arg->getValue(); } // Handle /noentry - if (args.hasArg(OPT_noentry)) { - if (args.hasArg(OPT_dll)) - config->noEntry = true; + if (Args.hasArg(OPT_noentry)) { + if (Args.hasArg(OPT_dll)) + Config->NoEntry = true; else error("/noentry must be specified with /dll"); } // Handle /dll - if (args.hasArg(OPT_dll)) { - config->dll = true; - config->manifestID = 2; + if (Args.hasArg(OPT_dll)) { + Config->DLL = true; + Config->ManifestID = 2; } // Handle /dynamicbase and /fixed. We can't use hasFlag for /dynamicbase // because we need to explicitly check whether that option or its inverse was // present in the argument list in order to handle /fixed. - auto *dynamicBaseArg = args.getLastArg(OPT_dynamicbase, OPT_dynamicbase_no); - if (dynamicBaseArg && - dynamicBaseArg->getOption().getID() == OPT_dynamicbase_no) - config->dynamicBase = false; + auto *DynamicBaseArg = Args.getLastArg(OPT_dynamicbase, OPT_dynamicbase_no); + if (DynamicBaseArg && + DynamicBaseArg->getOption().getID() == OPT_dynamicbase_no) + Config->DynamicBase = false; // MSDN claims "/FIXED:NO is the default setting for a DLL, and /FIXED is the // default setting for any other project type.", but link.exe defaults to // /FIXED:NO for exe outputs as well. Match behavior, not docs. - bool fixed = args.hasFlag(OPT_fixed, OPT_fixed_no, false); - if (fixed) { - if (dynamicBaseArg && - dynamicBaseArg->getOption().getID() == OPT_dynamicbase) { + bool Fixed = Args.hasFlag(OPT_fixed, OPT_fixed_no, false); + if (Fixed) { + if (DynamicBaseArg && + DynamicBaseArg->getOption().getID() == OPT_dynamicbase) { error("/fixed must not be specified with /dynamicbase"); } else { - config->relocatable = false; - config->dynamicBase = false; + Config->Relocatable = false; + Config->DynamicBase = false; } } // Handle /appcontainer - config->appContainer = - args.hasFlag(OPT_appcontainer, OPT_appcontainer_no, false); + Config->AppContainer = + Args.hasFlag(OPT_appcontainer, OPT_appcontainer_no, false); // Handle /machine - if (auto *arg = args.getLastArg(OPT_machine)) { - config->machine = getMachineType(arg->getValue()); - if (config->machine == IMAGE_FILE_MACHINE_UNKNOWN) - fatal(Twine("unknown /machine argument: ") + arg->getValue()); + if (auto *Arg = Args.getLastArg(OPT_machine)) { + Config->Machine = getMachineType(Arg->getValue()); + if (Config->Machine == IMAGE_FILE_MACHINE_UNKNOWN) + fatal(Twine("unknown /machine argument: ") + Arg->getValue()); } // Handle /nodefaultlib: - for (auto *arg : args.filtered(OPT_nodefaultlib)) - config->noDefaultLibs.insert(doFindLib(arg->getValue()).lower()); + for (auto *Arg : Args.filtered(OPT_nodefaultlib)) + Config->NoDefaultLibs.insert(doFindLib(Arg->getValue()).lower()); // Handle /nodefaultlib - if (args.hasArg(OPT_nodefaultlib_all)) - config->noDefaultLibAll = true; + if (Args.hasArg(OPT_nodefaultlib_all)) + Config->NoDefaultLibAll = true; // Handle /base - if (auto *arg = args.getLastArg(OPT_base)) - parseNumbers(arg->getValue(), &config->imageBase); + if (auto *Arg = Args.getLastArg(OPT_base)) + parseNumbers(Arg->getValue(), &Config->ImageBase); // Handle /filealign - if (auto *arg = args.getLastArg(OPT_filealign)) { - parseNumbers(arg->getValue(), &config->fileAlign); - if (!isPowerOf2_64(config->fileAlign)) - error("/filealign: not a power of two: " + Twine(config->fileAlign)); + if (auto *Arg = Args.getLastArg(OPT_filealign)) { + parseNumbers(Arg->getValue(), &Config->FileAlign); + if (!isPowerOf2_64(Config->FileAlign)) + error("/filealign: not a power of two: " + Twine(Config->FileAlign)); } // Handle /stack - if (auto *arg = args.getLastArg(OPT_stack)) - parseNumbers(arg->getValue(), &config->stackReserve, &config->stackCommit); + if (auto *Arg = Args.getLastArg(OPT_stack)) + parseNumbers(Arg->getValue(), &Config->StackReserve, &Config->StackCommit); // Handle /guard:cf - if (auto *arg = args.getLastArg(OPT_guard)) - parseGuard(arg->getValue()); + if (auto *Arg = Args.getLastArg(OPT_guard)) + parseGuard(Arg->getValue()); // Handle /heap - if (auto *arg = args.getLastArg(OPT_heap)) - parseNumbers(arg->getValue(), &config->heapReserve, &config->heapCommit); + if (auto *Arg = Args.getLastArg(OPT_heap)) + parseNumbers(Arg->getValue(), &Config->HeapReserve, &Config->HeapCommit); // Handle /version - if (auto *arg = args.getLastArg(OPT_version)) - parseVersion(arg->getValue(), &config->majorImageVersion, - &config->minorImageVersion); + if (auto *Arg = Args.getLastArg(OPT_version)) + parseVersion(Arg->getValue(), &Config->MajorImageVersion, + &Config->MinorImageVersion); // Handle /subsystem - if (auto *arg = args.getLastArg(OPT_subsystem)) - parseSubsystem(arg->getValue(), &config->subsystem, &config->majorOSVersion, - &config->minorOSVersion); + if (auto *Arg = Args.getLastArg(OPT_subsystem)) + parseSubsystem(Arg->getValue(), &Config->Subsystem, &Config->MajorOSVersion, + &Config->MinorOSVersion); // Handle /timestamp - if (llvm::opt::Arg *arg = args.getLastArg(OPT_timestamp, OPT_repro)) { - if (arg->getOption().getID() == OPT_repro) { - config->timestamp = 0; - config->repro = true; + if (llvm::opt::Arg *Arg = Args.getLastArg(OPT_timestamp, OPT_repro)) { + if (Arg->getOption().getID() == OPT_repro) { + Config->Timestamp = 0; + Config->Repro = true; } else { - config->repro = false; - StringRef value(arg->getValue()); - if (value.getAsInteger(0, config->timestamp)) - fatal(Twine("invalid timestamp: ") + value + + Config->Repro = false; + StringRef Value(Arg->getValue()); + if (Value.getAsInteger(0, Config->Timestamp)) + fatal(Twine("invalid timestamp: ") + Value + ". Expected 32-bit integer"); } } else { - config->repro = false; - config->timestamp = time(nullptr); + Config->Repro = false; + Config->Timestamp = time(nullptr); } // Handle /alternatename - for (auto *arg : args.filtered(OPT_alternatename)) - parseAlternateName(arg->getValue()); + for (auto *Arg : Args.filtered(OPT_alternatename)) + parseAlternateName(Arg->getValue()); // Handle /include - for (auto *arg : args.filtered(OPT_incl)) - addUndefined(arg->getValue()); + for (auto *Arg : Args.filtered(OPT_incl)) + addUndefined(Arg->getValue()); // Handle /implib - if (auto *arg = args.getLastArg(OPT_implib)) - config->implib = arg->getValue(); + if (auto *Arg = Args.getLastArg(OPT_implib)) + Config->Implib = Arg->getValue(); // Handle /opt. - bool doGC = debug == DebugKind::None || args.hasArg(OPT_profile); - unsigned icfLevel = - args.hasArg(OPT_profile) ? 0 : 1; // 0: off, 1: limited, 2: on - unsigned tailMerge = 1; - for (auto *arg : args.filtered(OPT_opt)) { - std::string str = StringRef(arg->getValue()).lower(); - SmallVector vec; - StringRef(str).split(vec, ','); - for (StringRef s : vec) { - if (s == "ref") { - doGC = true; - } else if (s == "noref") { - doGC = false; - } else if (s == "icf" || s.startswith("icf=")) { - icfLevel = 2; - } else if (s == "noicf") { - icfLevel = 0; - } else if (s == "lldtailmerge") { - tailMerge = 2; - } else if (s == "nolldtailmerge") { - tailMerge = 0; - } else if (s.startswith("lldlto=")) { - StringRef optLevel = s.substr(7); - if (optLevel.getAsInteger(10, config->ltoo) || config->ltoo > 3) - error("/opt:lldlto: invalid optimization level: " + optLevel); - } else if (s.startswith("lldltojobs=")) { - StringRef jobs = s.substr(11); - if (jobs.getAsInteger(10, config->thinLTOJobs) || - config->thinLTOJobs == 0) - error("/opt:lldltojobs: invalid job count: " + jobs); - } else if (s.startswith("lldltopartitions=")) { - StringRef n = s.substr(17); - if (n.getAsInteger(10, config->ltoPartitions) || - config->ltoPartitions == 0) - error("/opt:lldltopartitions: invalid partition count: " + n); - } else if (s != "lbr" && s != "nolbr") - error("/opt: unknown option: " + s); + bool DoGC = Debug == DebugKind::None || Args.hasArg(OPT_profile); + unsigned ICFLevel = + Args.hasArg(OPT_profile) ? 0 : 1; // 0: off, 1: limited, 2: on + unsigned TailMerge = 1; + for (auto *Arg : Args.filtered(OPT_opt)) { + std::string Str = StringRef(Arg->getValue()).lower(); + SmallVector Vec; + StringRef(Str).split(Vec, ','); + for (StringRef S : Vec) { + if (S == "ref") { + DoGC = true; + } else if (S == "noref") { + DoGC = false; + } else if (S == "icf" || S.startswith("icf=")) { + ICFLevel = 2; + } else if (S == "noicf") { + ICFLevel = 0; + } else if (S == "lldtailmerge") { + TailMerge = 2; + } else if (S == "nolldtailmerge") { + TailMerge = 0; + } else if (S.startswith("lldlto=")) { + StringRef OptLevel = S.substr(7); + if (OptLevel.getAsInteger(10, Config->LTOO) || Config->LTOO > 3) + error("/opt:lldlto: invalid optimization level: " + OptLevel); + } else if (S.startswith("lldltojobs=")) { + StringRef Jobs = S.substr(11); + if (Jobs.getAsInteger(10, Config->ThinLTOJobs) || + Config->ThinLTOJobs == 0) + error("/opt:lldltojobs: invalid job count: " + Jobs); + } else if (S.startswith("lldltopartitions=")) { + StringRef N = S.substr(17); + if (N.getAsInteger(10, Config->LTOPartitions) || + Config->LTOPartitions == 0) + error("/opt:lldltopartitions: invalid partition count: " + N); + } else if (S != "lbr" && S != "nolbr") + error("/opt: unknown option: " + S); } } @@ -1392,37 +1354,37 @@ void LinkerDriver::link(ArrayRef argsArr) { // FIXME: LLD only implements "limited" ICF, i.e. it only merges identical // code. If the user passes /OPT:ICF explicitly, LLD should merge identical // comdat readonly data. - if (icfLevel == 1 && !doGC) - icfLevel = 0; - config->doGC = doGC; - config->doICF = icfLevel > 0; - config->tailMerge = (tailMerge == 1 && config->doICF) || tailMerge == 2; + if (ICFLevel == 1 && !DoGC) + ICFLevel = 0; + Config->DoGC = DoGC; + Config->DoICF = ICFLevel > 0; + Config->TailMerge = (TailMerge == 1 && Config->DoICF) || TailMerge == 2; // Handle /lldsavetemps - if (args.hasArg(OPT_lldsavetemps)) - config->saveTemps = true; + if (Args.hasArg(OPT_lldsavetemps)) + Config->SaveTemps = true; // Handle /kill-at - if (args.hasArg(OPT_kill_at)) - config->killAt = true; + if (Args.hasArg(OPT_kill_at)) + Config->KillAt = true; // Handle /lldltocache - if (auto *arg = args.getLastArg(OPT_lldltocache)) - config->ltoCache = arg->getValue(); + if (auto *Arg = Args.getLastArg(OPT_lldltocache)) + Config->LTOCache = Arg->getValue(); // Handle /lldsavecachepolicy - if (auto *arg = args.getLastArg(OPT_lldltocachepolicy)) - config->ltoCachePolicy = CHECK( - parseCachePruningPolicy(arg->getValue()), - Twine("/lldltocachepolicy: invalid cache policy: ") + arg->getValue()); + if (auto *Arg = Args.getLastArg(OPT_lldltocachepolicy)) + Config->LTOCachePolicy = CHECK( + parseCachePruningPolicy(Arg->getValue()), + Twine("/lldltocachepolicy: invalid cache policy: ") + Arg->getValue()); // Handle /failifmismatch - for (auto *arg : args.filtered(OPT_failifmismatch)) - checkFailIfMismatch(arg->getValue(), nullptr); + for (auto *Arg : Args.filtered(OPT_failifmismatch)) + checkFailIfMismatch(Arg->getValue(), nullptr); // Handle /merge - for (auto *arg : args.filtered(OPT_merge)) - parseMerge(arg->getValue()); + for (auto *Arg : Args.filtered(OPT_merge)) + parseMerge(Arg->getValue()); // Add default section merging rules after user rules. User rules take // precedence, but we will emit a warning if there is a conflict. @@ -1432,172 +1394,129 @@ void LinkerDriver::link(ArrayRef argsArr) { parseMerge(".xdata=.rdata"); parseMerge(".bss=.data"); - if (config->mingw) { + if (Config->MinGW) { parseMerge(".ctors=.rdata"); parseMerge(".dtors=.rdata"); parseMerge(".CRT=.rdata"); } // Handle /section - for (auto *arg : args.filtered(OPT_section)) - parseSection(arg->getValue()); - - // Handle /align - if (auto *arg = args.getLastArg(OPT_align)) { - parseNumbers(arg->getValue(), &config->align); - if (!isPowerOf2_64(config->align)) - error("/align: not a power of two: " + StringRef(arg->getValue())); - } + for (auto *Arg : Args.filtered(OPT_section)) + parseSection(Arg->getValue()); // Handle /aligncomm - for (auto *arg : args.filtered(OPT_aligncomm)) - parseAligncomm(arg->getValue()); + for (auto *Arg : Args.filtered(OPT_aligncomm)) + parseAligncomm(Arg->getValue()); // Handle /manifestdependency. This enables /manifest unless /manifest:no is // also passed. - if (auto *arg = args.getLastArg(OPT_manifestdependency)) { - config->manifestDependency = arg->getValue(); - config->manifest = Configuration::SideBySide; + if (auto *Arg = Args.getLastArg(OPT_manifestdependency)) { + Config->ManifestDependency = Arg->getValue(); + Config->Manifest = Configuration::SideBySide; } // Handle /manifest and /manifest: - if (auto *arg = args.getLastArg(OPT_manifest, OPT_manifest_colon)) { - if (arg->getOption().getID() == OPT_manifest) - config->manifest = Configuration::SideBySide; + if (auto *Arg = Args.getLastArg(OPT_manifest, OPT_manifest_colon)) { + if (Arg->getOption().getID() == OPT_manifest) + Config->Manifest = Configuration::SideBySide; else - parseManifest(arg->getValue()); + parseManifest(Arg->getValue()); } // Handle /manifestuac - if (auto *arg = args.getLastArg(OPT_manifestuac)) - parseManifestUAC(arg->getValue()); + if (auto *Arg = Args.getLastArg(OPT_manifestuac)) + parseManifestUAC(Arg->getValue()); // Handle /manifestfile - if (auto *arg = args.getLastArg(OPT_manifestfile)) - config->manifestFile = arg->getValue(); + if (auto *Arg = Args.getLastArg(OPT_manifestfile)) + Config->ManifestFile = Arg->getValue(); // Handle /manifestinput - for (auto *arg : args.filtered(OPT_manifestinput)) - config->manifestInput.push_back(arg->getValue()); + for (auto *Arg : Args.filtered(OPT_manifestinput)) + Config->ManifestInput.push_back(Arg->getValue()); - if (!config->manifestInput.empty() && - config->manifest != Configuration::Embed) { + if (!Config->ManifestInput.empty() && + Config->Manifest != Configuration::Embed) { fatal("/manifestinput: requires /manifest:embed"); } - config->thinLTOEmitImportsFiles = args.hasArg(OPT_thinlto_emit_imports_files); - config->thinLTOIndexOnly = args.hasArg(OPT_thinlto_index_only) || - args.hasArg(OPT_thinlto_index_only_arg); - config->thinLTOIndexOnlyArg = - args.getLastArgValue(OPT_thinlto_index_only_arg); - config->thinLTOPrefixReplace = - getOldNewOptions(args, OPT_thinlto_prefix_replace); - config->thinLTOObjectSuffixReplace = - getOldNewOptions(args, OPT_thinlto_object_suffix_replace); - config->ltoObjPath = args.getLastArgValue(OPT_lto_obj_path); // Handle miscellaneous boolean flags. - config->allowBind = args.hasFlag(OPT_allowbind, OPT_allowbind_no, true); - config->allowIsolation = - args.hasFlag(OPT_allowisolation, OPT_allowisolation_no, true); - config->incremental = - args.hasFlag(OPT_incremental, OPT_incremental_no, - !config->doGC && !config->doICF && !args.hasArg(OPT_order) && - !args.hasArg(OPT_profile)); - config->integrityCheck = - args.hasFlag(OPT_integritycheck, OPT_integritycheck_no, false); - config->nxCompat = args.hasFlag(OPT_nxcompat, OPT_nxcompat_no, true); - for (auto *arg : args.filtered(OPT_swaprun)) - parseSwaprun(arg->getValue()); - config->terminalServerAware = - !config->dll && args.hasFlag(OPT_tsaware, OPT_tsaware_no, true); - config->debugDwarf = debug == DebugKind::Dwarf; - config->debugGHashes = debug == DebugKind::GHash; - config->debugSymtab = debug == DebugKind::Symtab; - - config->mapFile = getMapFile(args); - - if (config->incremental && args.hasArg(OPT_profile)) { + Config->AllowBind = Args.hasFlag(OPT_allowbind, OPT_allowbind_no, true); + Config->AllowIsolation = + Args.hasFlag(OPT_allowisolation, OPT_allowisolation_no, true); + Config->Incremental = + Args.hasFlag(OPT_incremental, OPT_incremental_no, + !Config->DoGC && !Config->DoICF && !Args.hasArg(OPT_order) && + !Args.hasArg(OPT_profile)); + Config->IntegrityCheck = + Args.hasFlag(OPT_integritycheck, OPT_integritycheck_no, false); + Config->NxCompat = Args.hasFlag(OPT_nxcompat, OPT_nxcompat_no, true); + for (auto *Arg : Args.filtered(OPT_swaprun)) + parseSwaprun(Arg->getValue()); + Config->TerminalServerAware = + !Config->DLL && Args.hasFlag(OPT_tsaware, OPT_tsaware_no, true); + Config->DebugDwarf = Debug == DebugKind::Dwarf; + Config->DebugGHashes = Debug == DebugKind::GHash; + Config->DebugSymtab = Debug == DebugKind::Symtab; + + Config->MapFile = getMapFile(Args); + + if (Config->Incremental && Args.hasArg(OPT_profile)) { warn("ignoring '/incremental' due to '/profile' specification"); - config->incremental = false; + Config->Incremental = false; } - if (config->incremental && args.hasArg(OPT_order)) { + if (Config->Incremental && Args.hasArg(OPT_order)) { warn("ignoring '/incremental' due to '/order' specification"); - config->incremental = false; + Config->Incremental = false; } - if (config->incremental && config->doGC) { + if (Config->Incremental && Config->DoGC) { warn("ignoring '/incremental' because REF is enabled; use '/opt:noref' to " "disable"); - config->incremental = false; + Config->Incremental = false; } - if (config->incremental && config->doICF) { + if (Config->Incremental && Config->DoICF) { warn("ignoring '/incremental' because ICF is enabled; use '/opt:noicf' to " "disable"); - config->incremental = false; + Config->Incremental = false; } if (errorCount()) return; - std::set wholeArchives; - for (auto *arg : args.filtered(OPT_wholearchive_file)) - if (Optional path = doFindFile(arg->getValue())) - if (Optional id = getUniqueID(*path)) - wholeArchives.insert(*id); + std::set WholeArchives; + for (auto *Arg : Args.filtered(OPT_wholearchive_file)) + if (Optional Path = doFindFile(Arg->getValue())) + if (Optional ID = getUniqueID(*Path)) + WholeArchives.insert(*ID); // A predicate returning true if a given path is an argument for // /wholearchive:, or /wholearchive is enabled globally. // This function is a bit tricky because "foo.obj /wholearchive:././foo.obj" // needs to be handled as "/wholearchive:foo.obj foo.obj". - auto isWholeArchive = [&](StringRef path) -> bool { - if (args.hasArg(OPT_wholearchive_flag)) + auto IsWholeArchive = [&](StringRef Path) -> bool { + if (Args.hasArg(OPT_wholearchive_flag)) return true; - if (Optional id = getUniqueID(path)) - return wholeArchives.count(*id); + if (Optional ID = getUniqueID(Path)) + return WholeArchives.count(*ID); return false; }; - // Create a list of input files. These can be given as OPT_INPUT options - // and OPT_wholearchive_file options, and we also need to track OPT_start_lib - // and OPT_end_lib. - bool inLib = false; - for (auto *arg : args) { - switch (arg->getOption().getID()) { - case OPT_end_lib: - if (!inLib) - error("stray " + arg->getSpelling()); - inLib = false; - break; - case OPT_start_lib: - if (inLib) - error("nested " + arg->getSpelling()); - inLib = true; - break; - case OPT_wholearchive_file: - if (Optional path = findFile(arg->getValue())) - enqueuePath(*path, true, inLib); - break; - case OPT_INPUT: - if (Optional path = findFile(arg->getValue())) - enqueuePath(*path, isWholeArchive(*path), inLib); - break; - default: - // Ignore other options. - break; - } - } + // Create a list of input files. Files can be given as arguments + // for /defaultlib option. + for (auto *Arg : Args.filtered(OPT_INPUT, OPT_wholearchive_file)) + if (Optional Path = findFile(Arg->getValue())) + enqueuePath(*Path, IsWholeArchive(*Path)); - // Process files specified as /defaultlib. These should be enequeued after - // other files, which is why they are in a separate loop. - for (auto *arg : args.filtered(OPT_defaultlib)) - if (Optional path = findLib(arg->getValue())) - enqueuePath(*path, false, false); + for (auto *Arg : Args.filtered(OPT_defaultlib)) + if (Optional Path = findLib(Arg->getValue())) + enqueuePath(*Path, false); // Windows specific -- Create a resource file containing a manifest file. - if (config->manifest == Configuration::Embed) - addBuffer(createManifestRes(), false, false); + if (Config->Manifest == Configuration::Embed) + addBuffer(createManifestRes(), false); // Read all input files given via the command line. run(); @@ -1607,163 +1526,164 @@ void LinkerDriver::link(ArrayRef argsArr) { // We should have inferred a machine type by now from the input files, but if // not we assume x64. - if (config->machine == IMAGE_FILE_MACHINE_UNKNOWN) { + if (Config->Machine == IMAGE_FILE_MACHINE_UNKNOWN) { warn("/machine is not specified. x64 is assumed"); - config->machine = AMD64; + Config->Machine = AMD64; } - config->wordsize = config->is64() ? 8 : 4; - - // Handle /safeseh, x86 only, on by default, except for mingw. - if (config->machine == I386 && - args.hasFlag(OPT_safeseh, OPT_safeseh_no, !config->mingw)) - config->safeSEH = true; + Config->Wordsize = Config->is64() ? 8 : 4; // Handle /functionpadmin - for (auto *arg : args.filtered(OPT_functionpadmin, OPT_functionpadmin_opt)) - parseFunctionPadMin(arg, config->machine); + for (auto *Arg : Args.filtered(OPT_functionpadmin, OPT_functionpadmin_opt)) + parseFunctionPadMin(Arg, Config->Machine); + + // Input files can be Windows resource files (.res files). We use + // WindowsResource to convert resource files to a regular COFF file, + // then link the resulting file normally. + if (!Resources.empty()) + Symtab->addFile(make(convertResToCOFF(Resources))); - if (tar) - tar->append("response.txt", - createResponseFile(args, filePaths, - ArrayRef(searchPaths).slice(1))); + if (Tar) + Tar->append("response.txt", + createResponseFile(Args, FilePaths, + ArrayRef(SearchPaths).slice(1))); // Handle /largeaddressaware - config->largeAddressAware = args.hasFlag( - OPT_largeaddressaware, OPT_largeaddressaware_no, config->is64()); + Config->LargeAddressAware = Args.hasFlag( + OPT_largeaddressaware, OPT_largeaddressaware_no, Config->is64()); // Handle /highentropyva - config->highEntropyVA = - config->is64() && - args.hasFlag(OPT_highentropyva, OPT_highentropyva_no, true); + Config->HighEntropyVA = + Config->is64() && + Args.hasFlag(OPT_highentropyva, OPT_highentropyva_no, true); - if (!config->dynamicBase && - (config->machine == ARMNT || config->machine == ARM64)) + if (!Config->DynamicBase && + (Config->Machine == ARMNT || Config->Machine == ARM64)) error("/dynamicbase:no is not compatible with " + - machineToStr(config->machine)); + machineToStr(Config->Machine)); // Handle /export - for (auto *arg : args.filtered(OPT_export)) { - Export e = parseExport(arg->getValue()); - if (config->machine == I386) { - if (!isDecorated(e.name)) - e.name = saver.save("_" + e.name); - if (!e.extName.empty() && !isDecorated(e.extName)) - e.extName = saver.save("_" + e.extName); + for (auto *Arg : Args.filtered(OPT_export)) { + Export E = parseExport(Arg->getValue()); + if (Config->Machine == I386) { + if (!isDecorated(E.Name)) + E.Name = Saver.save("_" + E.Name); + if (!E.ExtName.empty() && !isDecorated(E.ExtName)) + E.ExtName = Saver.save("_" + E.ExtName); } - config->exports.push_back(e); + Config->Exports.push_back(E); } // Handle /def - if (auto *arg = args.getLastArg(OPT_deffile)) { + if (auto *Arg = Args.getLastArg(OPT_deffile)) { // parseModuleDefs mutates Config object. - parseModuleDefs(arg->getValue()); + parseModuleDefs(Arg->getValue()); } // Handle generation of import library from a def file. - if (!args.hasArg(OPT_INPUT)) { + if (!Args.hasArg(OPT_INPUT)) { fixupExports(); - createImportLibrary(/*asLib=*/true); + createImportLibrary(/*AsLib=*/true); return; } // Windows specific -- if no /subsystem is given, we need to infer // that from entry point name. Must happen before /entry handling, // and after the early return when just writing an import library. - if (config->subsystem == IMAGE_SUBSYSTEM_UNKNOWN) { - config->subsystem = inferSubsystem(); - if (config->subsystem == IMAGE_SUBSYSTEM_UNKNOWN) + if (Config->Subsystem == IMAGE_SUBSYSTEM_UNKNOWN) { + Config->Subsystem = inferSubsystem(); + if (Config->Subsystem == IMAGE_SUBSYSTEM_UNKNOWN) fatal("subsystem must be defined"); } // Handle /entry and /dll - if (auto *arg = args.getLastArg(OPT_entry)) { - config->entry = addUndefined(mangle(arg->getValue())); - } else if (!config->entry && !config->noEntry) { - if (args.hasArg(OPT_dll)) { - StringRef s = (config->machine == I386) ? "__DllMainCRTStartup@12" + if (auto *Arg = Args.getLastArg(OPT_entry)) { + Config->Entry = addUndefined(mangle(Arg->getValue())); + } else if (!Config->Entry && !Config->NoEntry) { + if (Args.hasArg(OPT_dll)) { + StringRef S = (Config->Machine == I386) ? "__DllMainCRTStartup@12" : "_DllMainCRTStartup"; - config->entry = addUndefined(s); + Config->Entry = addUndefined(S); } else { // Windows specific -- If entry point name is not given, we need to // infer that from user-defined entry name. - StringRef s = findDefaultEntry(); - if (s.empty()) + StringRef S = findDefaultEntry(); + if (S.empty()) fatal("entry point must be defined"); - config->entry = addUndefined(s); - log("Entry name inferred: " + s); + Config->Entry = addUndefined(S); + log("Entry name inferred: " + S); } } // Handle /delayload - for (auto *arg : args.filtered(OPT_delayload)) { - config->delayLoads.insert(StringRef(arg->getValue()).lower()); - if (config->machine == I386) { - config->delayLoadHelper = addUndefined("___delayLoadHelper2@8"); + for (auto *Arg : Args.filtered(OPT_delayload)) { + Config->DelayLoads.insert(StringRef(Arg->getValue()).lower()); + if (Config->Machine == I386) { + Config->DelayLoadHelper = addUndefined("___delayLoadHelper2@8"); } else { - config->delayLoadHelper = addUndefined("__delayLoadHelper2"); + Config->DelayLoadHelper = addUndefined("__delayLoadHelper2"); } } // Set default image name if neither /out or /def set it. - if (config->outputFile.empty()) { - config->outputFile = - getOutputPath((*args.filtered(OPT_INPUT).begin())->getValue()); + if (Config->OutputFile.empty()) { + Config->OutputFile = + getOutputPath((*Args.filtered(OPT_INPUT).begin())->getValue()); } // Fail early if an output file is not writable. - if (auto e = tryCreateFile(config->outputFile)) { - error("cannot open output file " + config->outputFile + ": " + e.message()); + if (auto E = tryCreateFile(Config->OutputFile)) { + error("cannot open output file " + Config->OutputFile + ": " + E.message()); return; } - if (shouldCreatePDB) { + if (ShouldCreatePDB) { // Put the PDB next to the image if no /pdb flag was passed. - if (config->pdbPath.empty()) { - config->pdbPath = config->outputFile; - sys::path::replace_extension(config->pdbPath, ".pdb"); + if (Config->PDBPath.empty()) { + Config->PDBPath = Config->OutputFile; + sys::path::replace_extension(Config->PDBPath, ".pdb"); } // The embedded PDB path should be the absolute path to the PDB if no // /pdbaltpath flag was passed. - if (config->pdbAltPath.empty()) { - config->pdbAltPath = config->pdbPath; + if (Config->PDBAltPath.empty()) { + Config->PDBAltPath = Config->PDBPath; // It's important to make the path absolute and remove dots. This path // will eventually be written into the PE header, and certain Microsoft // tools won't work correctly if these assumptions are not held. - sys::fs::make_absolute(config->pdbAltPath); - sys::path::remove_dots(config->pdbAltPath); + sys::fs::make_absolute(Config->PDBAltPath); + sys::path::remove_dots(Config->PDBAltPath); } else { // Don't do this earlier, so that Config->OutputFile is ready. - parsePDBAltPath(config->pdbAltPath); + parsePDBAltPath(Config->PDBAltPath); } } // Set default image base if /base is not given. - if (config->imageBase == uint64_t(-1)) - config->imageBase = getDefaultImageBase(); - - symtab->addSynthetic(mangle("__ImageBase"), nullptr); - if (config->machine == I386) { - symtab->addAbsolute("___safe_se_handler_table", 0); - symtab->addAbsolute("___safe_se_handler_count", 0); - } - - symtab->addAbsolute(mangle("__guard_fids_count"), 0); - symtab->addAbsolute(mangle("__guard_fids_table"), 0); - symtab->addAbsolute(mangle("__guard_flags"), 0); - symtab->addAbsolute(mangle("__guard_iat_count"), 0); - symtab->addAbsolute(mangle("__guard_iat_table"), 0); - symtab->addAbsolute(mangle("__guard_longjmp_count"), 0); - symtab->addAbsolute(mangle("__guard_longjmp_table"), 0); + if (Config->ImageBase == uint64_t(-1)) + Config->ImageBase = getDefaultImageBase(); + + Symtab->addSynthetic(mangle("__ImageBase"), nullptr); + if (Config->Machine == I386) { + Symtab->addAbsolute("___safe_se_handler_table", 0); + Symtab->addAbsolute("___safe_se_handler_count", 0); + } + + Symtab->addAbsolute(mangle("__guard_fids_count"), 0); + Symtab->addAbsolute(mangle("__guard_fids_table"), 0); + Symtab->addAbsolute(mangle("__guard_flags"), 0); + Symtab->addAbsolute(mangle("__guard_iat_count"), 0); + Symtab->addAbsolute(mangle("__guard_iat_table"), 0); + Symtab->addAbsolute(mangle("__guard_longjmp_count"), 0); + Symtab->addAbsolute(mangle("__guard_longjmp_table"), 0); // Needed for MSVC 2017 15.5 CRT. - symtab->addAbsolute(mangle("__enclave_config"), 0); + Symtab->addAbsolute(mangle("__enclave_config"), 0); - if (config->mingw) { - symtab->addAbsolute(mangle("__RUNTIME_PSEUDO_RELOC_LIST__"), 0); - symtab->addAbsolute(mangle("__RUNTIME_PSEUDO_RELOC_LIST_END__"), 0); - symtab->addAbsolute(mangle("__CTOR_LIST__"), 0); - symtab->addAbsolute(mangle("__DTOR_LIST__"), 0); + if (Config->MinGW) { + Symtab->addAbsolute(mangle("__RUNTIME_PSEUDO_RELOC_LIST__"), 0); + Symtab->addAbsolute(mangle("__RUNTIME_PSEUDO_RELOC_LIST_END__"), 0); + Symtab->addAbsolute(mangle("__CTOR_LIST__"), 0); + Symtab->addAbsolute(mangle("__DTOR_LIST__"), 0); } // This code may add new undefined symbols to the link, which may enqueue more @@ -1772,54 +1692,53 @@ void LinkerDriver::link(ArrayRef argsArr) { do { // Windows specific -- if entry point is not found, // search for its mangled names. - if (config->entry) - mangleMaybe(config->entry); + if (Config->Entry) + mangleMaybe(Config->Entry); // Windows specific -- Make sure we resolve all dllexported symbols. - for (Export &e : config->exports) { - if (!e.forwardTo.empty()) + for (Export &E : Config->Exports) { + if (!E.ForwardTo.empty()) continue; - e.sym = addUndefined(e.name); - if (!e.directives) - e.symbolName = mangleMaybe(e.sym); + E.Sym = addUndefined(E.Name); + if (!E.Directives) + E.SymbolName = mangleMaybe(E.Sym); } // Add weak aliases. Weak aliases is a mechanism to give remaining // undefined symbols final chance to be resolved successfully. - for (auto pair : config->alternateNames) { - StringRef from = pair.first; - StringRef to = pair.second; - Symbol *sym = symtab->find(from); - if (!sym) + for (auto Pair : Config->AlternateNames) { + StringRef From = Pair.first; + StringRef To = Pair.second; + Symbol *Sym = Symtab->find(From); + if (!Sym) continue; - if (auto *u = dyn_cast(sym)) - if (!u->weakAlias) - u->weakAlias = symtab->addUndefined(to); + if (auto *U = dyn_cast(Sym)) + if (!U->WeakAlias) + U->WeakAlias = Symtab->addUndefined(To); } - // If any inputs are bitcode files, the LTO code generator may create - // references to library functions that are not explicit in the bitcode - // file's symbol table. If any of those library functions are defined in a - // bitcode file in an archive member, we need to arrange to use LTO to - // compile those archive members by adding them to the link beforehand. - if (!BitcodeFile::instances.empty()) - for (const char *s : libcallRoutineNames) - symtab->addLibcall(s); - // Windows specific -- if __load_config_used can be resolved, resolve it. - if (symtab->findUnderscore("_load_config_used")) + if (Symtab->findUnderscore("_load_config_used")) addUndefined(mangle("_load_config_used")); } while (run()); - if (args.hasArg(OPT_include_optional)) { + if (errorCount()) + return; + + // Do LTO by compiling bitcode input files to a set of native COFF files then + // link those files. + Symtab->addCombinedLTOObjects(); + run(); + + if (Args.hasArg(OPT_include_optional)) { // Handle /includeoptional - for (auto *arg : args.filtered(OPT_include_optional)) - if (dyn_cast_or_null(symtab->find(arg->getValue()))) - addUndefined(arg->getValue()); + for (auto *Arg : Args.filtered(OPT_include_optional)) + if (dyn_cast_or_null(Symtab->find(Arg->getValue()))) + addUndefined(Arg->getValue()); while (run()); } - if (config->mingw) { + if (Config->MinGW) { // Load any further object files that might be needed for doing automatic // imports. // @@ -1833,44 +1752,28 @@ void LinkerDriver::link(ArrayRef argsArr) { // normal object file as well (although that won't be used for the // actual autoimport later on). If this pass adds new undefined references, // we won't iterate further to resolve them. - symtab->loadMinGWAutomaticImports(); + Symtab->loadMinGWAutomaticImports(); run(); } - // At this point, we should not have any symbols that cannot be resolved. - // If we are going to do codegen for link-time optimization, check for - // unresolvable symbols first, so we don't spend time generating code that - // will fail to link anyway. - if (!BitcodeFile::instances.empty() && !config->forceUnresolved) - symtab->reportUnresolvable(); + // Make sure we have resolved all symbols. + Symtab->reportRemainingUndefines(); if (errorCount()) return; - // Do LTO by compiling bitcode input files to a set of native COFF files then - // link those files (unless -thinlto-index-only was given, in which case we - // resolve symbols and write indices, but don't generate native code or link). - symtab->addCombinedLTOObjects(); - - // If -thinlto-index-only is given, we should create only "index - // files" and not object files. Index file creation is already done - // in addCombinedLTOObject, so we are done if that's the case. - if (config->thinLTOIndexOnly) - return; - - // If we generated native object files from bitcode files, this resolves - // references to the symbols we use from them. - run(); - - // Resolve remaining undefined symbols and warn about imported locals. - symtab->resolveRemainingUndefines(); - if (errorCount()) - return; + // Handle /safeseh. + if (Args.hasFlag(OPT_safeseh, OPT_safeseh_no, false)) { + for (ObjFile *File : ObjFile::Instances) + if (!File->hasSafeSEH()) + error("/safeseh: " + File->getName() + " is not compatible with SEH"); + if (errorCount()) + return; + } - config->hadExplicitExports = !config->exports.empty(); - if (config->mingw) { + if (Config->MinGW) { // In MinGW, all symbols are automatically exported if no symbols // are chosen to be exported. - maybeExportMinGWSymbols(args); + maybeExportMinGWSymbols(Args); // Make sure the crtend.o object is the last object file. This object // file can contain terminating section chunks that need to be placed @@ -1878,73 +1781,71 @@ void LinkerDriver::link(ArrayRef argsArr) { // order provided on the command line, while lld will pull in needed // files from static libraries only after the last object file on the // command line. - for (auto i = ObjFile::instances.begin(), e = ObjFile::instances.end(); - i != e; i++) { - ObjFile *file = *i; - if (isCrtend(file->getName())) { - ObjFile::instances.erase(i); - ObjFile::instances.push_back(file); + for (auto I = ObjFile::Instances.begin(), E = ObjFile::Instances.end(); + I != E; I++) { + ObjFile *File = *I; + if (isCrtend(File->getName())) { + ObjFile::Instances.erase(I); + ObjFile::Instances.push_back(File); break; } } } // Windows specific -- when we are creating a .dll file, we also - // need to create a .lib file. In MinGW mode, we only do that when the - // -implib option is given explicitly, for compatibility with GNU ld. - if (!config->exports.empty() || config->dll) { + // need to create a .lib file. + if (!Config->Exports.empty() || Config->DLL) { fixupExports(); - if (!config->mingw || !config->implib.empty()) - createImportLibrary(/*asLib=*/false); + createImportLibrary(/*AsLib=*/false); assignExportOrdinals(); } // Handle /output-def (MinGW specific). - if (auto *arg = args.getLastArg(OPT_output_def)) - writeDefFile(arg->getValue()); + if (auto *Arg = Args.getLastArg(OPT_output_def)) + writeDefFile(Arg->getValue()); // Set extra alignment for .comm symbols - for (auto pair : config->alignComm) { - StringRef name = pair.first; - uint32_t alignment = pair.second; + for (auto Pair : Config->AlignComm) { + StringRef Name = Pair.first; + uint32_t Alignment = Pair.second; - Symbol *sym = symtab->find(name); - if (!sym) { - warn("/aligncomm symbol " + name + " not found"); + Symbol *Sym = Symtab->find(Name); + if (!Sym) { + warn("/aligncomm symbol " + Name + " not found"); continue; } // If the symbol isn't common, it must have been replaced with a regular // symbol, which will carry its own alignment. - auto *dc = dyn_cast(sym); - if (!dc) + auto *DC = dyn_cast(Sym); + if (!DC) continue; - CommonChunk *c = dc->getChunk(); - c->setAlignment(std::max(c->getAlignment(), alignment)); + CommonChunk *C = DC->getChunk(); + C->setAlignment(std::max(C->getAlignment(), Alignment)); } // Windows specific -- Create a side-by-side manifest file. - if (config->manifest == Configuration::SideBySide) + if (Config->Manifest == Configuration::SideBySide) createSideBySideManifest(); // Handle /order. We want to do this at this moment because we // need a complete list of comdat sections to warn on nonexistent // functions. - if (auto *arg = args.getLastArg(OPT_order)) - parseOrderFile(arg->getValue()); + if (auto *Arg = Args.getLastArg(OPT_order)) + parseOrderFile(Arg->getValue()); // Identify unreferenced COMDAT sections. - if (config->doGC) - markLive(symtab->getChunks()); + if (Config->DoGC) + markLive(Symtab->getChunks()); // Needs to happen after the last call to addFile(). - convertResources(); + diagnoseMultipleResourceObjFiles(); // Identify identical COMDAT sections to merge them. - if (config->doICF) { + if (Config->DoICF) { findKeepUniqueSections(); - doICF(symtab->getChunks()); + doICF(Symtab->getChunks()); } // Write the result. @@ -1952,7 +1853,7 @@ void LinkerDriver::link(ArrayRef argsArr) { // Stop early so we can print the results. Timer::root().stop(); - if (config->showTiming) + if (Config->ShowTiming) Timer::root().print(); } diff --git a/lld/COFF/Driver.h b/lld/COFF/Driver.h index 0fd61759540216..1e9353118a6530 100644 --- a/lld/COFF/Driver.h +++ b/lld/COFF/Driver.h @@ -30,7 +30,7 @@ namespace lld { namespace coff { class LinkerDriver; -extern LinkerDriver *driver; +extern LinkerDriver *Driver; using llvm::COFF::MachineTypes; using llvm::COFF::WindowsSubsystem; @@ -44,75 +44,71 @@ class COFFOptTable : public llvm::opt::OptTable { class ArgParser { public: // Concatenate LINK environment variable and given arguments and parse them. - llvm::opt::InputArgList parseLINK(std::vector args); + llvm::opt::InputArgList parseLINK(std::vector Args); // Tokenizes a given string and then parses as command line options. - llvm::opt::InputArgList parse(StringRef s) { return parse(tokenize(s)); } + llvm::opt::InputArgList parse(StringRef S) { return parse(tokenize(S)); } // Tokenizes a given string and then parses as command line options in // .drectve section. /EXPORT options are returned in second element // to be processed in fastpath. std::pair> - parseDirectives(StringRef s); + parseDirectives(StringRef S); private: // Parses command line options. - llvm::opt::InputArgList parse(llvm::ArrayRef args); + llvm::opt::InputArgList parse(llvm::ArrayRef Args); - std::vector tokenize(StringRef s); + std::vector tokenize(StringRef S); - COFFOptTable table; + COFFOptTable Table; }; class LinkerDriver { public: - void link(llvm::ArrayRef args); + void link(llvm::ArrayRef Args); // Used by the resolver to parse .drectve section contents. - void parseDirectives(InputFile *file); + void parseDirectives(InputFile *File); // Used by ArchiveFile to enqueue members. - void enqueueArchiveMember(const Archive::Child &c, const Archive::Symbol &sym, - StringRef parentName); + void enqueueArchiveMember(const Archive::Child &C, StringRef SymName, + StringRef ParentName); - MemoryBufferRef takeBuffer(std::unique_ptr mb); + MemoryBufferRef takeBuffer(std::unique_ptr MB); - void enqueuePath(StringRef path, bool wholeArchive, bool lazy); + void enqueuePath(StringRef Path, bool WholeArchive); private: - std::unique_ptr tar; // for /linkrepro + std::unique_ptr Tar; // for /linkrepro // Opens a file. Path has to be resolved already. - MemoryBufferRef openFile(StringRef path); + MemoryBufferRef openFile(StringRef Path); // Searches a file from search paths. - Optional findFile(StringRef filename); - Optional findLib(StringRef filename); - StringRef doFindFile(StringRef filename); - StringRef doFindLib(StringRef filename); - StringRef doFindLibMinGW(StringRef filename); + Optional findFile(StringRef Filename); + Optional findLib(StringRef Filename); + StringRef doFindFile(StringRef Filename); + StringRef doFindLib(StringRef Filename); + StringRef doFindLibMinGW(StringRef Filename); // Parses LIB environment which contains a list of search paths. void addLibSearchPaths(); // Library search path. The first element is always "" (current directory). - std::vector searchPaths; + std::vector SearchPaths; - // Convert resource files and potentially merge input resource object - // trees into one resource tree. - void convertResources(); - - void maybeExportMinGWSymbols(const llvm::opt::InputArgList &args); + void maybeExportMinGWSymbols(const llvm::opt::InputArgList &Args); // We don't want to add the same file more than once. // Files are uniquified by their filesystem and file number. - std::set visitedFiles; + std::set VisitedFiles; - std::set visitedLibs; + std::set VisitedLibs; - Symbol *addUndefined(StringRef sym); + Symbol *addUndefined(StringRef Sym); - StringRef mangleMaybe(Symbol *s); + StringRef mangleMaybe(Symbol *S); // Windows specific -- "main" is not the only main function in Windows. // You can choose one from these four -- {w,}{WinMain,main}. @@ -124,37 +120,36 @@ class LinkerDriver { StringRef findDefaultEntry(); WindowsSubsystem inferSubsystem(); - void addBuffer(std::unique_ptr mb, bool wholeArchive, - bool lazy); - void addArchiveBuffer(MemoryBufferRef mbref, StringRef symName, - StringRef parentName, uint64_t offsetInArchive); + void addBuffer(std::unique_ptr MB, bool WholeArchive); + void addArchiveBuffer(MemoryBufferRef MBRef, StringRef SymName, + StringRef ParentName, uint64_t OffsetInArchive); - void enqueueTask(std::function task); + void enqueueTask(std::function Task); bool run(); - std::list> taskQueue; - std::vector filePaths; - std::vector resources; + std::list> TaskQueue; + std::vector FilePaths; + std::vector Resources; - llvm::StringSet<> directivesExports; + llvm::StringSet<> DirectivesExports; }; // Functions below this line are defined in DriverUtils.cpp. -void printHelp(const char *argv0); +void printHelp(const char *Argv0); // Parses a string in the form of "[,]". -void parseNumbers(StringRef arg, uint64_t *addr, uint64_t *size = nullptr); +void parseNumbers(StringRef Arg, uint64_t *Addr, uint64_t *Size = nullptr); -void parseGuard(StringRef arg); +void parseGuard(StringRef Arg); // Parses a string in the form of "[.]". // Minor's default value is 0. -void parseVersion(StringRef arg, uint32_t *major, uint32_t *minor); +void parseVersion(StringRef Arg, uint32_t *Major, uint32_t *Minor); // Parses a string in the form of "[,[.]]". -void parseSubsystem(StringRef arg, WindowsSubsystem *sys, uint32_t *major, - uint32_t *minor); +void parseSubsystem(StringRef Arg, WindowsSubsystem *Sys, uint32_t *Major, + uint32_t *Minor); void parseAlternateName(StringRef); void parseMerge(StringRef); @@ -162,23 +157,23 @@ void parseSection(StringRef); void parseAligncomm(StringRef); // Parses a string in the form of "[:]" -void parseFunctionPadMin(llvm::opt::Arg *a, llvm::COFF::MachineTypes machine); +void parseFunctionPadMin(llvm::opt::Arg *A, llvm::COFF::MachineTypes Machine); // Parses a string in the form of "EMBED[,=]|NO". -void parseManifest(StringRef arg); +void parseManifest(StringRef Arg); // Parses a string in the form of "level=|uiAccess=" -void parseManifestUAC(StringRef arg); +void parseManifestUAC(StringRef Arg); // Parses a string in the form of "cd|net[,(cd|net)]*" -void parseSwaprun(StringRef arg); +void parseSwaprun(StringRef Arg); // Create a resource file containing a manifest XML. std::unique_ptr createManifestRes(); void createSideBySideManifest(); // Used for dllexported symbols. -Export parseExport(StringRef arg); +Export parseExport(StringRef Arg); void fixupExports(); void assignExportOrdinals(); @@ -186,13 +181,12 @@ void assignExportOrdinals(); // if value matches previous values for the key. // This feature used in the directive section to reject // incompatible objects. -void checkFailIfMismatch(StringRef arg, InputFile *source); +void checkFailIfMismatch(StringRef Arg, InputFile *Source); // Convert Windows resource files (.res files) to a .obj file. -MemoryBufferRef convertResToCOFF(ArrayRef mbs, - ArrayRef objs); +MemoryBufferRef convertResToCOFF(ArrayRef MBs); -void runMSVCLinker(std::string rsp, ArrayRef objects); +void runMSVCLinker(std::string Rsp, ArrayRef Objects); // Create enum with OPT_xxx values for each option in Options.td enum { diff --git a/lld/COFF/DriverUtils.cpp b/lld/COFF/DriverUtils.cpp index b525ffdae9cee6..35724e08de19a3 100644 --- a/lld/COFF/DriverUtils.cpp +++ b/lld/COFF/DriverUtils.cpp @@ -47,75 +47,75 @@ const uint16_t RT_MANIFEST = 24; class Executor { public: - explicit Executor(StringRef s) : prog(saver.save(s)) {} - void add(StringRef s) { args.push_back(saver.save(s)); } - void add(std::string &s) { args.push_back(saver.save(s)); } - void add(Twine s) { args.push_back(saver.save(s)); } - void add(const char *s) { args.push_back(saver.save(s)); } + explicit Executor(StringRef S) : Prog(Saver.save(S)) {} + void add(StringRef S) { Args.push_back(Saver.save(S)); } + void add(std::string &S) { Args.push_back(Saver.save(S)); } + void add(Twine S) { Args.push_back(Saver.save(S)); } + void add(const char *S) { Args.push_back(Saver.save(S)); } void run() { - ErrorOr exeOrErr = sys::findProgramByName(prog); - if (auto ec = exeOrErr.getError()) - fatal("unable to find " + prog + " in PATH: " + ec.message()); - StringRef exe = saver.save(*exeOrErr); - args.insert(args.begin(), exe); + ErrorOr ExeOrErr = sys::findProgramByName(Prog); + if (auto EC = ExeOrErr.getError()) + fatal("unable to find " + Prog + " in PATH: " + EC.message()); + StringRef Exe = Saver.save(*ExeOrErr); + Args.insert(Args.begin(), Exe); - if (sys::ExecuteAndWait(args[0], args) != 0) + if (sys::ExecuteAndWait(Args[0], Args) != 0) fatal("ExecuteAndWait failed: " + - llvm::join(args.begin(), args.end(), " ")); + llvm::join(Args.begin(), Args.end(), " ")); } private: - StringRef prog; - std::vector args; + StringRef Prog; + std::vector Args; }; } // anonymous namespace // Parses a string in the form of "[,]". -void parseNumbers(StringRef arg, uint64_t *addr, uint64_t *size) { - StringRef s1, s2; - std::tie(s1, s2) = arg.split(','); - if (s1.getAsInteger(0, *addr)) - fatal("invalid number: " + s1); - if (size && !s2.empty() && s2.getAsInteger(0, *size)) - fatal("invalid number: " + s2); +void parseNumbers(StringRef Arg, uint64_t *Addr, uint64_t *Size) { + StringRef S1, S2; + std::tie(S1, S2) = Arg.split(','); + if (S1.getAsInteger(0, *Addr)) + fatal("invalid number: " + S1); + if (Size && !S2.empty() && S2.getAsInteger(0, *Size)) + fatal("invalid number: " + S2); } // Parses a string in the form of "[.]". // If second number is not present, Minor is set to 0. -void parseVersion(StringRef arg, uint32_t *major, uint32_t *minor) { - StringRef s1, s2; - std::tie(s1, s2) = arg.split('.'); - if (s1.getAsInteger(0, *major)) - fatal("invalid number: " + s1); - *minor = 0; - if (!s2.empty() && s2.getAsInteger(0, *minor)) - fatal("invalid number: " + s2); -} - -void parseGuard(StringRef fullArg) { - SmallVector splitArgs; - fullArg.split(splitArgs, ","); - for (StringRef arg : splitArgs) { - if (arg.equals_lower("no")) - config->guardCF = GuardCFLevel::Off; - else if (arg.equals_lower("nolongjmp")) - config->guardCF = GuardCFLevel::NoLongJmp; - else if (arg.equals_lower("cf") || arg.equals_lower("longjmp")) - config->guardCF = GuardCFLevel::Full; +void parseVersion(StringRef Arg, uint32_t *Major, uint32_t *Minor) { + StringRef S1, S2; + std::tie(S1, S2) = Arg.split('.'); + if (S1.getAsInteger(0, *Major)) + fatal("invalid number: " + S1); + *Minor = 0; + if (!S2.empty() && S2.getAsInteger(0, *Minor)) + fatal("invalid number: " + S2); +} + +void parseGuard(StringRef FullArg) { + SmallVector SplitArgs; + FullArg.split(SplitArgs, ","); + for (StringRef Arg : SplitArgs) { + if (Arg.equals_lower("no")) + Config->GuardCF = GuardCFLevel::Off; + else if (Arg.equals_lower("nolongjmp")) + Config->GuardCF = GuardCFLevel::NoLongJmp; + else if (Arg.equals_lower("cf") || Arg.equals_lower("longjmp")) + Config->GuardCF = GuardCFLevel::Full; else - fatal("invalid argument to /guard: " + arg); + fatal("invalid argument to /guard: " + Arg); } } // Parses a string in the form of "[,[.]]". -void parseSubsystem(StringRef arg, WindowsSubsystem *sys, uint32_t *major, - uint32_t *minor) { - StringRef sysStr, ver; - std::tie(sysStr, ver) = arg.split(','); - std::string sysStrLower = sysStr.lower(); - *sys = StringSwitch(sysStrLower) +void parseSubsystem(StringRef Arg, WindowsSubsystem *Sys, uint32_t *Major, + uint32_t *Minor) { + StringRef SysStr, Ver; + std::tie(SysStr, Ver) = Arg.split(','); + std::string SysStrLower = SysStr.lower(); + *Sys = StringSwitch(SysStrLower) .Case("boot_application", IMAGE_SUBSYSTEM_WINDOWS_BOOT_APPLICATION) .Case("console", IMAGE_SUBSYSTEM_WINDOWS_CUI) .Case("default", IMAGE_SUBSYSTEM_UNKNOWN) @@ -127,217 +127,217 @@ void parseSubsystem(StringRef arg, WindowsSubsystem *sys, uint32_t *major, .Case("posix", IMAGE_SUBSYSTEM_POSIX_CUI) .Case("windows", IMAGE_SUBSYSTEM_WINDOWS_GUI) .Default(IMAGE_SUBSYSTEM_UNKNOWN); - if (*sys == IMAGE_SUBSYSTEM_UNKNOWN && sysStrLower != "default") - fatal("unknown subsystem: " + sysStr); - if (!ver.empty()) - parseVersion(ver, major, minor); + if (*Sys == IMAGE_SUBSYSTEM_UNKNOWN && SysStrLower != "default") + fatal("unknown subsystem: " + SysStr); + if (!Ver.empty()) + parseVersion(Ver, Major, Minor); } // Parse a string of the form of "=". // Results are directly written to Config. -void parseAlternateName(StringRef s) { - StringRef from, to; - std::tie(from, to) = s.split('='); - if (from.empty() || to.empty()) - fatal("/alternatename: invalid argument: " + s); - auto it = config->alternateNames.find(from); - if (it != config->alternateNames.end() && it->second != to) - fatal("/alternatename: conflicts: " + s); - config->alternateNames.insert(it, std::make_pair(from, to)); +void parseAlternateName(StringRef S) { + StringRef From, To; + std::tie(From, To) = S.split('='); + if (From.empty() || To.empty()) + fatal("/alternatename: invalid argument: " + S); + auto It = Config->AlternateNames.find(From); + if (It != Config->AlternateNames.end() && It->second != To) + fatal("/alternatename: conflicts: " + S); + Config->AlternateNames.insert(It, std::make_pair(From, To)); } // Parse a string of the form of "=". // Results are directly written to Config. -void parseMerge(StringRef s) { - StringRef from, to; - std::tie(from, to) = s.split('='); - if (from.empty() || to.empty()) - fatal("/merge: invalid argument: " + s); - if (from == ".rsrc" || to == ".rsrc") +void parseMerge(StringRef S) { + StringRef From, To; + std::tie(From, To) = S.split('='); + if (From.empty() || To.empty()) + fatal("/merge: invalid argument: " + S); + if (From == ".rsrc" || To == ".rsrc") fatal("/merge: cannot merge '.rsrc' with any section"); - if (from == ".reloc" || to == ".reloc") + if (From == ".reloc" || To == ".reloc") fatal("/merge: cannot merge '.reloc' with any section"); - auto pair = config->merge.insert(std::make_pair(from, to)); - bool inserted = pair.second; - if (!inserted) { - StringRef existing = pair.first->second; - if (existing != to) - warn(s + ": already merged into " + existing); + auto Pair = Config->Merge.insert(std::make_pair(From, To)); + bool Inserted = Pair.second; + if (!Inserted) { + StringRef Existing = Pair.first->second; + if (Existing != To) + warn(S + ": already merged into " + Existing); } } -static uint32_t parseSectionAttributes(StringRef s) { - uint32_t ret = 0; - for (char c : s.lower()) { - switch (c) { +static uint32_t parseSectionAttributes(StringRef S) { + uint32_t Ret = 0; + for (char C : S.lower()) { + switch (C) { case 'd': - ret |= IMAGE_SCN_MEM_DISCARDABLE; + Ret |= IMAGE_SCN_MEM_DISCARDABLE; break; case 'e': - ret |= IMAGE_SCN_MEM_EXECUTE; + Ret |= IMAGE_SCN_MEM_EXECUTE; break; case 'k': - ret |= IMAGE_SCN_MEM_NOT_CACHED; + Ret |= IMAGE_SCN_MEM_NOT_CACHED; break; case 'p': - ret |= IMAGE_SCN_MEM_NOT_PAGED; + Ret |= IMAGE_SCN_MEM_NOT_PAGED; break; case 'r': - ret |= IMAGE_SCN_MEM_READ; + Ret |= IMAGE_SCN_MEM_READ; break; case 's': - ret |= IMAGE_SCN_MEM_SHARED; + Ret |= IMAGE_SCN_MEM_SHARED; break; case 'w': - ret |= IMAGE_SCN_MEM_WRITE; + Ret |= IMAGE_SCN_MEM_WRITE; break; default: - fatal("/section: invalid argument: " + s); + fatal("/section: invalid argument: " + S); } } - return ret; + return Ret; } // Parses /section option argument. -void parseSection(StringRef s) { - StringRef name, attrs; - std::tie(name, attrs) = s.split(','); - if (name.empty() || attrs.empty()) - fatal("/section: invalid argument: " + s); - config->section[name] = parseSectionAttributes(attrs); +void parseSection(StringRef S) { + StringRef Name, Attrs; + std::tie(Name, Attrs) = S.split(','); + if (Name.empty() || Attrs.empty()) + fatal("/section: invalid argument: " + S); + Config->Section[Name] = parseSectionAttributes(Attrs); } // Parses /aligncomm option argument. -void parseAligncomm(StringRef s) { - StringRef name, align; - std::tie(name, align) = s.split(','); - if (name.empty() || align.empty()) { - error("/aligncomm: invalid argument: " + s); +void parseAligncomm(StringRef S) { + StringRef Name, Align; + std::tie(Name, Align) = S.split(','); + if (Name.empty() || Align.empty()) { + error("/aligncomm: invalid argument: " + S); return; } - int v; - if (align.getAsInteger(0, v)) { - error("/aligncomm: invalid argument: " + s); + int V; + if (Align.getAsInteger(0, V)) { + error("/aligncomm: invalid argument: " + S); return; } - config->alignComm[name] = std::max(config->alignComm[name], 1 << v); + Config->AlignComm[Name] = std::max(Config->AlignComm[Name], 1 << V); } // Parses /functionpadmin option argument. -void parseFunctionPadMin(llvm::opt::Arg *a, llvm::COFF::MachineTypes machine) { - StringRef arg = a->getNumValues() ? a->getValue() : ""; - if (!arg.empty()) { +void parseFunctionPadMin(llvm::opt::Arg *A, llvm::COFF::MachineTypes Machine) { + StringRef Arg = A->getNumValues() ? A->getValue() : ""; + if (!Arg.empty()) { // Optional padding in bytes is given. - if (arg.getAsInteger(0, config->functionPadMin)) - error("/functionpadmin: invalid argument: " + arg); + if (Arg.getAsInteger(0, Config->FunctionPadMin)) + error("/functionpadmin: invalid argument: " + Arg); return; } // No optional argument given. // Set default padding based on machine, similar to link.exe. // There is no default padding for ARM platforms. - if (machine == I386) { - config->functionPadMin = 5; - } else if (machine == AMD64) { - config->functionPadMin = 6; + if (Machine == I386) { + Config->FunctionPadMin = 5; + } else if (Machine == AMD64) { + Config->FunctionPadMin = 6; } else { - error("/functionpadmin: invalid argument for this machine: " + arg); + error("/functionpadmin: invalid argument for this machine: " + Arg); } } // Parses a string in the form of "EMBED[,=]|NO". // Results are directly written to Config. -void parseManifest(StringRef arg) { - if (arg.equals_lower("no")) { - config->manifest = Configuration::No; +void parseManifest(StringRef Arg) { + if (Arg.equals_lower("no")) { + Config->Manifest = Configuration::No; return; } - if (!arg.startswith_lower("embed")) - fatal("invalid option " + arg); - config->manifest = Configuration::Embed; - arg = arg.substr(strlen("embed")); - if (arg.empty()) + if (!Arg.startswith_lower("embed")) + fatal("invalid option " + Arg); + Config->Manifest = Configuration::Embed; + Arg = Arg.substr(strlen("embed")); + if (Arg.empty()) return; - if (!arg.startswith_lower(",id=")) - fatal("invalid option " + arg); - arg = arg.substr(strlen(",id=")); - if (arg.getAsInteger(0, config->manifestID)) - fatal("invalid option " + arg); + if (!Arg.startswith_lower(",id=")) + fatal("invalid option " + Arg); + Arg = Arg.substr(strlen(",id=")); + if (Arg.getAsInteger(0, Config->ManifestID)) + fatal("invalid option " + Arg); } // Parses a string in the form of "level=|uiAccess=|NO". // Results are directly written to Config. -void parseManifestUAC(StringRef arg) { - if (arg.equals_lower("no")) { - config->manifestUAC = false; +void parseManifestUAC(StringRef Arg) { + if (Arg.equals_lower("no")) { + Config->ManifestUAC = false; return; } for (;;) { - arg = arg.ltrim(); - if (arg.empty()) + Arg = Arg.ltrim(); + if (Arg.empty()) return; - if (arg.startswith_lower("level=")) { - arg = arg.substr(strlen("level=")); - std::tie(config->manifestLevel, arg) = arg.split(" "); + if (Arg.startswith_lower("level=")) { + Arg = Arg.substr(strlen("level=")); + std::tie(Config->ManifestLevel, Arg) = Arg.split(" "); continue; } - if (arg.startswith_lower("uiaccess=")) { - arg = arg.substr(strlen("uiaccess=")); - std::tie(config->manifestUIAccess, arg) = arg.split(" "); + if (Arg.startswith_lower("uiaccess=")) { + Arg = Arg.substr(strlen("uiaccess=")); + std::tie(Config->ManifestUIAccess, Arg) = Arg.split(" "); continue; } - fatal("invalid option " + arg); + fatal("invalid option " + Arg); } } // Parses a string in the form of "cd|net[,(cd|net)]*" // Results are directly written to Config. -void parseSwaprun(StringRef arg) { +void parseSwaprun(StringRef Arg) { do { - StringRef swaprun, newArg; - std::tie(swaprun, newArg) = arg.split(','); - if (swaprun.equals_lower("cd")) - config->swaprunCD = true; - else if (swaprun.equals_lower("net")) - config->swaprunNet = true; - else if (swaprun.empty()) + StringRef Swaprun, NewArg; + std::tie(Swaprun, NewArg) = Arg.split(','); + if (Swaprun.equals_lower("cd")) + Config->SwaprunCD = true; + else if (Swaprun.equals_lower("net")) + Config->SwaprunNet = true; + else if (Swaprun.empty()) error("/swaprun: missing argument"); else - error("/swaprun: invalid argument: " + swaprun); + error("/swaprun: invalid argument: " + Swaprun); // To catch trailing commas, e.g. `/spawrun:cd,` - if (newArg.empty() && arg.endswith(",")) + if (NewArg.empty() && Arg.endswith(",")) error("/swaprun: missing argument"); - arg = newArg; - } while (!arg.empty()); + Arg = NewArg; + } while (!Arg.empty()); } // An RAII temporary file class that automatically removes a temporary file. namespace { class TemporaryFile { public: - TemporaryFile(StringRef prefix, StringRef extn, StringRef contents = "") { - SmallString<128> s; - if (auto ec = sys::fs::createTemporaryFile("lld-" + prefix, extn, s)) - fatal("cannot create a temporary file: " + ec.message()); - path = s.str(); - - if (!contents.empty()) { - std::error_code ec; - raw_fd_ostream os(path, ec, sys::fs::OF_None); - if (ec) - fatal("failed to open " + path + ": " + ec.message()); - os << contents; + TemporaryFile(StringRef Prefix, StringRef Extn, StringRef Contents = "") { + SmallString<128> S; + if (auto EC = sys::fs::createTemporaryFile("lld-" + Prefix, Extn, S)) + fatal("cannot create a temporary file: " + EC.message()); + Path = S.str(); + + if (!Contents.empty()) { + std::error_code EC; + raw_fd_ostream OS(Path, EC, sys::fs::F_None); + if (EC) + fatal("failed to open " + Path + ": " + EC.message()); + OS << Contents; } } - TemporaryFile(TemporaryFile &&obj) { - std::swap(path, obj.path); + TemporaryFile(TemporaryFile &&Obj) { + std::swap(Path, Obj.Path); } ~TemporaryFile() { - if (path.empty()) + if (Path.empty()) return; - if (sys::fs::remove(path)) - fatal("failed to remove " + path); + if (sys::fs::remove(Path)) + fatal("failed to remove " + Path); } // Returns a memory buffer of this temporary file. @@ -345,406 +345,390 @@ class TemporaryFile { // so it is safe to remove the file immediately after this function // is called (you cannot remove an opened file on Windows.) std::unique_ptr getMemoryBuffer() { - // IsVolatile=true forces MemoryBuffer to not use mmap(). - return CHECK(MemoryBuffer::getFile(path, /*FileSize=*/-1, + // IsVolatileSize=true forces MemoryBuffer to not use mmap(). + return CHECK(MemoryBuffer::getFile(Path, /*FileSize=*/-1, /*RequiresNullTerminator=*/false, - /*IsVolatile=*/true), - "could not open " + path); + /*IsVolatileSize=*/true), + "could not open " + Path); } - std::string path; + std::string Path; }; } static std::string createDefaultXml() { - std::string ret; - raw_string_ostream os(ret); + std::string Ret; + raw_string_ostream OS(Ret); // Emit the XML. Note that we do *not* verify that the XML attributes are // syntactically correct. This is intentional for link.exe compatibility. - os << "\n" + OS << "\n" << "\n"; - if (config->manifestUAC) { - os << " \n" + if (Config->ManifestUAC) { + OS << " \n" << " \n" << " \n" - << " \n" + << " \n" << " \n" << " \n" << " \n"; } - if (!config->manifestDependency.empty()) { - os << " \n" + if (!Config->ManifestDependency.empty()) { + OS << " \n" << " \n" - << " manifestDependency << " />\n" + << " ManifestDependency << " />\n" << " \n" << " \n"; } - os << "\n"; - return os.str(); + OS << "\n"; + return OS.str(); } -static std::string createManifestXmlWithInternalMt(StringRef defaultXml) { - std::unique_ptr defaultXmlCopy = - MemoryBuffer::getMemBufferCopy(defaultXml); +static std::string createManifestXmlWithInternalMt(StringRef DefaultXml) { + std::unique_ptr DefaultXmlCopy = + MemoryBuffer::getMemBufferCopy(DefaultXml); - windows_manifest::WindowsManifestMerger merger; - if (auto e = merger.merge(*defaultXmlCopy.get())) + windows_manifest::WindowsManifestMerger Merger; + if (auto E = Merger.merge(*DefaultXmlCopy.get())) fatal("internal manifest tool failed on default xml: " + - toString(std::move(e))); + toString(std::move(E))); - for (StringRef filename : config->manifestInput) { - std::unique_ptr manifest = - check(MemoryBuffer::getFile(filename)); - if (auto e = merger.merge(*manifest.get())) - fatal("internal manifest tool failed on file " + filename + ": " + - toString(std::move(e))); + for (StringRef Filename : Config->ManifestInput) { + std::unique_ptr Manifest = + check(MemoryBuffer::getFile(Filename)); + if (auto E = Merger.merge(*Manifest.get())) + fatal("internal manifest tool failed on file " + Filename + ": " + + toString(std::move(E))); } - return merger.getMergedManifest().get()->getBuffer(); + return Merger.getMergedManifest().get()->getBuffer(); } -static std::string createManifestXmlWithExternalMt(StringRef defaultXml) { +static std::string createManifestXmlWithExternalMt(StringRef DefaultXml) { // Create the default manifest file as a temporary file. TemporaryFile Default("defaultxml", "manifest"); - std::error_code ec; - raw_fd_ostream os(Default.path, ec, sys::fs::OF_Text); - if (ec) - fatal("failed to open " + Default.path + ": " + ec.message()); - os << defaultXml; - os.close(); + std::error_code EC; + raw_fd_ostream OS(Default.Path, EC, sys::fs::F_Text); + if (EC) + fatal("failed to open " + Default.Path + ": " + EC.message()); + OS << DefaultXml; + OS.close(); // Merge user-supplied manifests if they are given. Since libxml2 is not // enabled, we must shell out to Microsoft's mt.exe tool. - TemporaryFile user("user", "manifest"); + TemporaryFile User("user", "manifest"); - Executor e("mt.exe"); - e.add("/manifest"); - e.add(Default.path); - for (StringRef filename : config->manifestInput) { - e.add("/manifest"); - e.add(filename); + Executor E("mt.exe"); + E.add("/manifest"); + E.add(Default.Path); + for (StringRef Filename : Config->ManifestInput) { + E.add("/manifest"); + E.add(Filename); } - e.add("/nologo"); - e.add("/out:" + StringRef(user.path)); - e.run(); + E.add("/nologo"); + E.add("/out:" + StringRef(User.Path)); + E.run(); - return CHECK(MemoryBuffer::getFile(user.path), "could not open " + user.path) + return CHECK(MemoryBuffer::getFile(User.Path), "could not open " + User.Path) .get() ->getBuffer(); } static std::string createManifestXml() { - std::string defaultXml = createDefaultXml(); - if (config->manifestInput.empty()) - return defaultXml; + std::string DefaultXml = createDefaultXml(); + if (Config->ManifestInput.empty()) + return DefaultXml; if (windows_manifest::isAvailable()) - return createManifestXmlWithInternalMt(defaultXml); + return createManifestXmlWithInternalMt(DefaultXml); - return createManifestXmlWithExternalMt(defaultXml); + return createManifestXmlWithExternalMt(DefaultXml); } static std::unique_ptr -createMemoryBufferForManifestRes(size_t manifestSize) { - size_t resSize = alignTo( +createMemoryBufferForManifestRes(size_t ManifestSize) { + size_t ResSize = alignTo( object::WIN_RES_MAGIC_SIZE + object::WIN_RES_NULL_ENTRY_SIZE + sizeof(object::WinResHeaderPrefix) + sizeof(object::WinResIDs) + - sizeof(object::WinResHeaderSuffix) + manifestSize, + sizeof(object::WinResHeaderSuffix) + ManifestSize, object::WIN_RES_DATA_ALIGNMENT); - return WritableMemoryBuffer::getNewMemBuffer(resSize, config->outputFile + + return WritableMemoryBuffer::getNewMemBuffer(ResSize, Config->OutputFile + ".manifest.res"); } -static void writeResFileHeader(char *&buf) { - memcpy(buf, COFF::WinResMagic, sizeof(COFF::WinResMagic)); - buf += sizeof(COFF::WinResMagic); - memset(buf, 0, object::WIN_RES_NULL_ENTRY_SIZE); - buf += object::WIN_RES_NULL_ENTRY_SIZE; +static void writeResFileHeader(char *&Buf) { + memcpy(Buf, COFF::WinResMagic, sizeof(COFF::WinResMagic)); + Buf += sizeof(COFF::WinResMagic); + memset(Buf, 0, object::WIN_RES_NULL_ENTRY_SIZE); + Buf += object::WIN_RES_NULL_ENTRY_SIZE; } -static void writeResEntryHeader(char *&buf, size_t manifestSize) { +static void writeResEntryHeader(char *&Buf, size_t ManifestSize) { // Write the prefix. - auto *prefix = reinterpret_cast(buf); - prefix->DataSize = manifestSize; - prefix->HeaderSize = sizeof(object::WinResHeaderPrefix) + + auto *Prefix = reinterpret_cast(Buf); + Prefix->DataSize = ManifestSize; + Prefix->HeaderSize = sizeof(object::WinResHeaderPrefix) + sizeof(object::WinResIDs) + sizeof(object::WinResHeaderSuffix); - buf += sizeof(object::WinResHeaderPrefix); + Buf += sizeof(object::WinResHeaderPrefix); // Write the Type/Name IDs. - auto *iDs = reinterpret_cast(buf); - iDs->setType(RT_MANIFEST); - iDs->setName(config->manifestID); - buf += sizeof(object::WinResIDs); + auto *IDs = reinterpret_cast(Buf); + IDs->setType(RT_MANIFEST); + IDs->setName(Config->ManifestID); + Buf += sizeof(object::WinResIDs); // Write the suffix. - auto *suffix = reinterpret_cast(buf); - suffix->DataVersion = 0; - suffix->MemoryFlags = object::WIN_RES_PURE_MOVEABLE; - suffix->Language = SUBLANG_ENGLISH_US; - suffix->Version = 0; - suffix->Characteristics = 0; - buf += sizeof(object::WinResHeaderSuffix); + auto *Suffix = reinterpret_cast(Buf); + Suffix->DataVersion = 0; + Suffix->MemoryFlags = object::WIN_RES_PURE_MOVEABLE; + Suffix->Language = SUBLANG_ENGLISH_US; + Suffix->Version = 0; + Suffix->Characteristics = 0; + Buf += sizeof(object::WinResHeaderSuffix); } // Create a resource file containing a manifest XML. std::unique_ptr createManifestRes() { - std::string manifest = createManifestXml(); + std::string Manifest = createManifestXml(); - std::unique_ptr res = - createMemoryBufferForManifestRes(manifest.size()); + std::unique_ptr Res = + createMemoryBufferForManifestRes(Manifest.size()); - char *buf = res->getBufferStart(); - writeResFileHeader(buf); - writeResEntryHeader(buf, manifest.size()); + char *Buf = Res->getBufferStart(); + writeResFileHeader(Buf); + writeResEntryHeader(Buf, Manifest.size()); // Copy the manifest data into the .res file. - std::copy(manifest.begin(), manifest.end(), buf); - return std::move(res); + std::copy(Manifest.begin(), Manifest.end(), Buf); + return std::move(Res); } void createSideBySideManifest() { - std::string path = config->manifestFile; - if (path == "") - path = config->outputFile + ".manifest"; - std::error_code ec; - raw_fd_ostream out(path, ec, sys::fs::OF_Text); - if (ec) - fatal("failed to create manifest: " + ec.message()); - out << createManifestXml(); + std::string Path = Config->ManifestFile; + if (Path == "") + Path = Config->OutputFile + ".manifest"; + std::error_code EC; + raw_fd_ostream Out(Path, EC, sys::fs::F_Text); + if (EC) + fatal("failed to create manifest: " + EC.message()); + Out << createManifestXml(); } // Parse a string in the form of // "[=][,@ordinal[,NONAME]][,DATA][,PRIVATE]" // or "=.". // Used for parsing /export arguments. -Export parseExport(StringRef arg) { - Export e; - StringRef rest; - std::tie(e.name, rest) = arg.split(","); - if (e.name.empty()) +Export parseExport(StringRef Arg) { + Export E; + StringRef Rest; + std::tie(E.Name, Rest) = Arg.split(","); + if (E.Name.empty()) goto err; - if (e.name.contains('=')) { - StringRef x, y; - std::tie(x, y) = e.name.split("="); + if (E.Name.contains('=')) { + StringRef X, Y; + std::tie(X, Y) = E.Name.split("="); // If "=.". - if (y.contains(".")) { - e.name = x; - e.forwardTo = y; - return e; + if (Y.contains(".")) { + E.Name = X; + E.ForwardTo = Y; + return E; } - e.extName = x; - e.name = y; - if (e.name.empty()) + E.ExtName = X; + E.Name = Y; + if (E.Name.empty()) goto err; } // If "=[,@ordinal[,NONAME]][,DATA][,PRIVATE]" - while (!rest.empty()) { - StringRef tok; - std::tie(tok, rest) = rest.split(","); - if (tok.equals_lower("noname")) { - if (e.ordinal == 0) + while (!Rest.empty()) { + StringRef Tok; + std::tie(Tok, Rest) = Rest.split(","); + if (Tok.equals_lower("noname")) { + if (E.Ordinal == 0) goto err; - e.noname = true; + E.Noname = true; continue; } - if (tok.equals_lower("data")) { - e.data = true; + if (Tok.equals_lower("data")) { + E.Data = true; continue; } - if (tok.equals_lower("constant")) { - e.constant = true; + if (Tok.equals_lower("constant")) { + E.Constant = true; continue; } - if (tok.equals_lower("private")) { - e.isPrivate = true; + if (Tok.equals_lower("private")) { + E.Private = true; continue; } - if (tok.startswith("@")) { - int32_t ord; - if (tok.substr(1).getAsInteger(0, ord)) + if (Tok.startswith("@")) { + int32_t Ord; + if (Tok.substr(1).getAsInteger(0, Ord)) goto err; - if (ord <= 0 || 65535 < ord) + if (Ord <= 0 || 65535 < Ord) goto err; - e.ordinal = ord; + E.Ordinal = Ord; continue; } goto err; } - return e; + return E; err: - fatal("invalid /export: " + arg); + fatal("invalid /export: " + Arg); } -static StringRef undecorate(StringRef sym) { - if (config->machine != I386) - return sym; +static StringRef undecorate(StringRef Sym) { + if (Config->Machine != I386) + return Sym; // In MSVC mode, a fully decorated stdcall function is exported // as-is with the leading underscore (with type IMPORT_NAME). // In MinGW mode, a decorated stdcall function gets the underscore // removed, just like normal cdecl functions. - if (sym.startswith("_") && sym.contains('@') && !config->mingw) - return sym; - return sym.startswith("_") ? sym.substr(1) : sym; + if (Sym.startswith("_") && Sym.contains('@') && !Config->MinGW) + return Sym; + return Sym.startswith("_") ? Sym.substr(1) : Sym; } // Convert stdcall/fastcall style symbols into unsuffixed symbols, // with or without a leading underscore. (MinGW specific.) -static StringRef killAt(StringRef sym, bool prefix) { - if (sym.empty()) - return sym; +static StringRef killAt(StringRef Sym, bool Prefix) { + if (Sym.empty()) + return Sym; // Strip any trailing stdcall suffix - sym = sym.substr(0, sym.find('@', 1)); - if (!sym.startswith("@")) { - if (prefix && !sym.startswith("_")) - return saver.save("_" + sym); - return sym; + Sym = Sym.substr(0, Sym.find('@', 1)); + if (!Sym.startswith("@")) { + if (Prefix && !Sym.startswith("_")) + return Saver.save("_" + Sym); + return Sym; } // For fastcall, remove the leading @ and replace it with an // underscore, if prefixes are used. - sym = sym.substr(1); - if (prefix) - sym = saver.save("_" + sym); - return sym; + Sym = Sym.substr(1); + if (Prefix) + Sym = Saver.save("_" + Sym); + return Sym; } // Performs error checking on all /export arguments. // It also sets ordinals. void fixupExports() { // Symbol ordinals must be unique. - std::set ords; - for (Export &e : config->exports) { - if (e.ordinal == 0) + std::set Ords; + for (Export &E : Config->Exports) { + if (E.Ordinal == 0) continue; - if (!ords.insert(e.ordinal).second) - fatal("duplicate export ordinal: " + e.name); + if (!Ords.insert(E.Ordinal).second) + fatal("duplicate export ordinal: " + E.Name); } - for (Export &e : config->exports) { - if (!e.forwardTo.empty()) { - e.exportName = undecorate(e.name); + for (Export &E : Config->Exports) { + if (!E.ForwardTo.empty()) { + E.ExportName = undecorate(E.Name); } else { - e.exportName = undecorate(e.extName.empty() ? e.name : e.extName); + E.ExportName = undecorate(E.ExtName.empty() ? E.Name : E.ExtName); } } - if (config->killAt && config->machine == I386) { - for (Export &e : config->exports) { - e.name = killAt(e.name, true); - e.exportName = killAt(e.exportName, false); - e.extName = killAt(e.extName, true); - e.symbolName = killAt(e.symbolName, true); + if (Config->KillAt && Config->Machine == I386) { + for (Export &E : Config->Exports) { + E.Name = killAt(E.Name, true); + E.ExportName = killAt(E.ExportName, false); + E.ExtName = killAt(E.ExtName, true); + E.SymbolName = killAt(E.SymbolName, true); } } // Uniquefy by name. - DenseMap map(config->exports.size()); - std::vector v; - for (Export &e : config->exports) { - auto pair = map.insert(std::make_pair(e.exportName, &e)); - bool inserted = pair.second; - if (inserted) { - v.push_back(e); + DenseMap Map(Config->Exports.size()); + std::vector V; + for (Export &E : Config->Exports) { + auto Pair = Map.insert(std::make_pair(E.ExportName, &E)); + bool Inserted = Pair.second; + if (Inserted) { + V.push_back(E); continue; } - Export *existing = pair.first->second; - if (e == *existing || e.name != existing->name) + Export *Existing = Pair.first->second; + if (E == *Existing || E.Name != Existing->Name) continue; - warn("duplicate /export option: " + e.name); + warn("duplicate /export option: " + E.Name); } - config->exports = std::move(v); + Config->Exports = std::move(V); // Sort by name. - std::sort(config->exports.begin(), config->exports.end(), - [](const Export &a, const Export &b) { - return a.exportName < b.exportName; + std::sort(Config->Exports.begin(), Config->Exports.end(), + [](const Export &A, const Export &B) { + return A.ExportName < B.ExportName; }); } void assignExportOrdinals() { // Assign unique ordinals if default (= 0). - uint16_t max = 0; - for (Export &e : config->exports) - max = std::max(max, e.ordinal); - for (Export &e : config->exports) - if (e.ordinal == 0) - e.ordinal = ++max; + uint16_t Max = 0; + for (Export &E : Config->Exports) + Max = std::max(Max, E.Ordinal); + for (Export &E : Config->Exports) + if (E.Ordinal == 0) + E.Ordinal = ++Max; } // Parses a string in the form of "key=value" and check // if value matches previous values for the same key. -void checkFailIfMismatch(StringRef arg, InputFile *source) { - StringRef k, v; - std::tie(k, v) = arg.split('='); - if (k.empty() || v.empty()) - fatal("/failifmismatch: invalid argument: " + arg); - std::pair existing = config->mustMatch[k]; - if (!existing.first.empty() && v != existing.first) { - std::string sourceStr = source ? toString(source) : "cmd-line"; - std::string existingStr = - existing.second ? toString(existing.second) : "cmd-line"; - fatal("/failifmismatch: mismatch detected for '" + k + "':\n>>> " + - existingStr + " has value " + existing.first + "\n>>> " + sourceStr + - " has value " + v); - } - config->mustMatch[k] = {v, source}; +void checkFailIfMismatch(StringRef Arg, InputFile *Source) { + StringRef K, V; + std::tie(K, V) = Arg.split('='); + if (K.empty() || V.empty()) + fatal("/failifmismatch: invalid argument: " + Arg); + std::pair Existing = Config->MustMatch[K]; + if (!Existing.first.empty() && V != Existing.first) { + std::string SourceStr = Source ? toString(Source) : "cmd-line"; + std::string ExistingStr = + Existing.second ? toString(Existing.second) : "cmd-line"; + fatal("/failifmismatch: mismatch detected for '" + K + "':\n>>> " + + ExistingStr + " has value " + Existing.first + "\n>>> " + SourceStr + + " has value " + V); + } + Config->MustMatch[K] = {V, Source}; } // Convert Windows resource files (.res files) to a .obj file. // Does what cvtres.exe does, but in-process and cross-platform. -MemoryBufferRef convertResToCOFF(ArrayRef mbs, - ArrayRef objs) { - object::WindowsResourceParser parser(/* MinGW */ config->mingw); - - std::vector duplicates; - for (MemoryBufferRef mb : mbs) { - std::unique_ptr bin = check(object::createBinary(mb)); - object::WindowsResource *rf = dyn_cast(bin.get()); - if (!rf) - fatal("cannot compile non-resource file as resource"); +MemoryBufferRef convertResToCOFF(ArrayRef MBs) { + object::WindowsResourceParser Parser; - if (auto ec = parser.parse(rf, duplicates)) - fatal(toString(std::move(ec))); - } + for (MemoryBufferRef MB : MBs) { + std::unique_ptr Bin = check(object::createBinary(MB)); + object::WindowsResource *RF = dyn_cast(Bin.get()); + if (!RF) + fatal("cannot compile non-resource file as resource"); - // Note: This processes all .res files before all objs. Ideally they'd be - // handled in the same order they were linked (to keep the right one, if - // there are duplicates that are tolerated due to forceMultipleRes). - for (ObjFile *f : objs) { - object::ResourceSectionRef rsf; - if (auto ec = rsf.load(f->getCOFFObj())) - fatal(toString(f) + ": " + toString(std::move(ec))); + std::vector Duplicates; + if (auto EC = Parser.parse(RF, Duplicates)) + fatal(toString(std::move(EC))); - if (auto ec = parser.parse(rsf, f->getName(), duplicates)) - fatal(toString(std::move(ec))); + for (const auto &DupeDiag : Duplicates) + if (Config->ForceMultipleRes) + warn(DupeDiag); + else + error(DupeDiag); } - if (config->mingw) - parser.cleanUpManifests(duplicates); - - for (const auto &dupeDiag : duplicates) - if (config->forceMultipleRes) - warn(dupeDiag); - else - error(dupeDiag); - - Expected> e = - llvm::object::writeWindowsResourceCOFF(config->machine, parser, - config->timestamp); - if (!e) - fatal("failed to write .res to COFF: " + toString(e.takeError())); + Expected> E = + llvm::object::writeWindowsResourceCOFF(Config->Machine, Parser, + Config->Timestamp); + if (!E) + fatal("failed to write .res to COFF: " + toString(E.takeError())); - MemoryBufferRef mbref = **e; - make>(std::move(*e)); // take ownership - return mbref; + MemoryBufferRef MBRef = **E; + make>(std::move(*E)); // take ownership + return MBRef; } // Create OptTable @@ -755,7 +739,7 @@ MemoryBufferRef convertResToCOFF(ArrayRef mbs, #undef PREFIX // Create table mapping all options defined in Options.td -static const llvm::opt::OptTable::Info infoTable[] = { +static const llvm::opt::OptTable::Info InfoTable[] = { #define OPTION(X1, X2, ID, KIND, GROUP, ALIAS, X7, X8, X9, X10, X11, X12) \ {X1, X2, X10, X11, OPT_##ID, llvm::opt::Option::KIND##Class, \ X9, X8, OPT_##GROUP, OPT_##ALIAS, X7, X12}, @@ -763,36 +747,36 @@ static const llvm::opt::OptTable::Info infoTable[] = { #undef OPTION }; -COFFOptTable::COFFOptTable() : OptTable(infoTable, true) {} +COFFOptTable::COFFOptTable() : OptTable(InfoTable, true) {} // Set color diagnostics according to --color-diagnostics={auto,always,never} // or --no-color-diagnostics flags. -static void handleColorDiagnostics(opt::InputArgList &args) { - auto *arg = args.getLastArg(OPT_color_diagnostics, OPT_color_diagnostics_eq, +static void handleColorDiagnostics(opt::InputArgList &Args) { + auto *Arg = Args.getLastArg(OPT_color_diagnostics, OPT_color_diagnostics_eq, OPT_no_color_diagnostics); - if (!arg) + if (!Arg) return; - if (arg->getOption().getID() == OPT_color_diagnostics) { - enableColors(true); - } else if (arg->getOption().getID() == OPT_no_color_diagnostics) { - enableColors(false); + if (Arg->getOption().getID() == OPT_color_diagnostics) { + errorHandler().ColorDiagnostics = true; + } else if (Arg->getOption().getID() == OPT_no_color_diagnostics) { + errorHandler().ColorDiagnostics = false; } else { - StringRef s = arg->getValue(); - if (s == "always") - enableColors(true); - else if (s == "never") - enableColors(false); - else if (s != "auto") - error("unknown option: --color-diagnostics=" + s); - } -} - -static cl::TokenizerCallback getQuotingStyle(opt::InputArgList &args) { - if (auto *arg = args.getLastArg(OPT_rsp_quoting)) { - StringRef s = arg->getValue(); - if (s != "windows" && s != "posix") - error("invalid response file quoting: " + s); - if (s == "windows") + StringRef S = Arg->getValue(); + if (S == "always") + errorHandler().ColorDiagnostics = true; + else if (S == "never") + errorHandler().ColorDiagnostics = false; + else if (S != "auto") + error("unknown option: --color-diagnostics=" + S); + } +} + +static cl::TokenizerCallback getQuotingStyle(opt::InputArgList &Args) { + if (auto *Arg = Args.getLastArg(OPT_rsp_quoting)) { + StringRef S = Arg->getValue(); + if (S != "windows" && S != "posix") + error("invalid response file quoting: " + S); + if (S == "windows") return cl::TokenizeWindowsCommandLine; return cl::TokenizeGNUCommandLine; } @@ -801,111 +785,111 @@ static cl::TokenizerCallback getQuotingStyle(opt::InputArgList &args) { } // Parses a given list of options. -opt::InputArgList ArgParser::parse(ArrayRef argv) { +opt::InputArgList ArgParser::parse(ArrayRef Argv) { // Make InputArgList from string vectors. - unsigned missingIndex; - unsigned missingCount; + unsigned MissingIndex; + unsigned MissingCount; // We need to get the quoting style for response files before parsing all // options so we parse here before and ignore all the options but // --rsp-quoting. - opt::InputArgList args = table.ParseArgs(argv, missingIndex, missingCount); + opt::InputArgList Args = Table.ParseArgs(Argv, MissingIndex, MissingCount); // Expand response files (arguments in the form of @) // and then parse the argument again. - SmallVector expandedArgv(argv.data(), - argv.data() + argv.size()); - cl::ExpandResponseFiles(saver, getQuotingStyle(args), expandedArgv); - args = table.ParseArgs(makeArrayRef(expandedArgv).drop_front(), missingIndex, - missingCount); + SmallVector ExpandedArgv(Argv.data(), + Argv.data() + Argv.size()); + cl::ExpandResponseFiles(Saver, getQuotingStyle(Args), ExpandedArgv); + Args = Table.ParseArgs(makeArrayRef(ExpandedArgv).drop_front(), MissingIndex, + MissingCount); // Print the real command line if response files are expanded. - if (args.hasArg(OPT_verbose) && argv.size() != expandedArgv.size()) { - std::string msg = "Command line:"; - for (const char *s : expandedArgv) - msg += " " + std::string(s); - message(msg); + if (Args.hasArg(OPT_verbose) && Argv.size() != ExpandedArgv.size()) { + std::string Msg = "Command line:"; + for (const char *S : ExpandedArgv) + Msg += " " + std::string(S); + message(Msg); } // Save the command line after response file expansion so we can write it to // the PDB if necessary. - config->argv = {expandedArgv.begin(), expandedArgv.end()}; + Config->Argv = {ExpandedArgv.begin(), ExpandedArgv.end()}; // Handle /WX early since it converts missing argument warnings to errors. - errorHandler().fatalWarnings = args.hasFlag(OPT_WX, OPT_WX_no, false); + errorHandler().FatalWarnings = Args.hasFlag(OPT_WX, OPT_WX_no, false); - if (missingCount) - fatal(Twine(args.getArgString(missingIndex)) + ": missing argument"); + if (MissingCount) + fatal(Twine(Args.getArgString(MissingIndex)) + ": missing argument"); - handleColorDiagnostics(args); + handleColorDiagnostics(Args); - for (auto *arg : args.filtered(OPT_UNKNOWN)) { - std::string nearest; - if (table.findNearest(arg->getAsString(args), nearest) > 1) - warn("ignoring unknown argument '" + arg->getAsString(args) + "'"); + for (auto *Arg : Args.filtered(OPT_UNKNOWN)) { + std::string Nearest; + if (Table.findNearest(Arg->getAsString(Args), Nearest) > 1) + warn("ignoring unknown argument '" + Arg->getSpelling() + "'"); else - warn("ignoring unknown argument '" + arg->getAsString(args) + - "', did you mean '" + nearest + "'"); + warn("ignoring unknown argument '" + Arg->getSpelling() + + "', did you mean '" + Nearest + "'"); } - if (args.hasArg(OPT_lib)) + if (Args.hasArg(OPT_lib)) warn("ignoring /lib since it's not the first argument"); - return args; + return Args; } // Tokenizes and parses a given string as command line in .drective section. // /EXPORT options are processed in fastpath. std::pair> -ArgParser::parseDirectives(StringRef s) { - std::vector exports; - SmallVector rest; +ArgParser::parseDirectives(StringRef S) { + std::vector Exports; + SmallVector Rest; - for (StringRef tok : tokenize(s)) { - if (tok.startswith_lower("/export:") || tok.startswith_lower("-export:")) - exports.push_back(tok.substr(strlen("/export:"))); + for (StringRef Tok : tokenize(S)) { + if (Tok.startswith_lower("/export:") || Tok.startswith_lower("-export:")) + Exports.push_back(Tok.substr(strlen("/export:"))); else - rest.push_back(tok.data()); + Rest.push_back(Tok.data()); } // Make InputArgList from unparsed string vectors. - unsigned missingIndex; - unsigned missingCount; + unsigned MissingIndex; + unsigned MissingCount; - opt::InputArgList args = table.ParseArgs(rest, missingIndex, missingCount); + opt::InputArgList Args = Table.ParseArgs(Rest, MissingIndex, MissingCount); - if (missingCount) - fatal(Twine(args.getArgString(missingIndex)) + ": missing argument"); - for (auto *arg : args.filtered(OPT_UNKNOWN)) - warn("ignoring unknown argument: " + arg->getAsString(args)); - return {std::move(args), std::move(exports)}; + if (MissingCount) + fatal(Twine(Args.getArgString(MissingIndex)) + ": missing argument"); + for (auto *Arg : Args.filtered(OPT_UNKNOWN)) + warn("ignoring unknown argument: " + Arg->getSpelling()); + return {std::move(Args), std::move(Exports)}; } // link.exe has an interesting feature. If LINK or _LINK_ environment // variables exist, their contents are handled as command line strings. // So you can pass extra arguments using them. -opt::InputArgList ArgParser::parseLINK(std::vector argv) { +opt::InputArgList ArgParser::parseLINK(std::vector Argv) { // Concatenate LINK env and command line arguments, and then parse them. - if (Optional s = Process::GetEnv("LINK")) { - std::vector v = tokenize(*s); - argv.insert(std::next(argv.begin()), v.begin(), v.end()); + if (Optional S = Process::GetEnv("LINK")) { + std::vector V = tokenize(*S); + Argv.insert(std::next(Argv.begin()), V.begin(), V.end()); } - if (Optional s = Process::GetEnv("_LINK_")) { - std::vector v = tokenize(*s); - argv.insert(std::next(argv.begin()), v.begin(), v.end()); + if (Optional S = Process::GetEnv("_LINK_")) { + std::vector V = tokenize(*S); + Argv.insert(std::next(Argv.begin()), V.begin(), V.end()); } - return parse(argv); + return parse(Argv); } -std::vector ArgParser::tokenize(StringRef s) { - SmallVector tokens; - cl::TokenizeWindowsCommandLine(s, saver, tokens); - return std::vector(tokens.begin(), tokens.end()); +std::vector ArgParser::tokenize(StringRef S) { + SmallVector Tokens; + cl::TokenizeWindowsCommandLine(S, Saver, Tokens); + return std::vector(Tokens.begin(), Tokens.end()); } -void printHelp(const char *argv0) { +void printHelp(const char *Argv0) { COFFOptTable().PrintHelp(outs(), - (std::string(argv0) + " [options] file...").c_str(), + (std::string(Argv0) + " [options] file...").c_str(), "LLVM Linker", false); } diff --git a/lld/COFF/ICF.cpp b/lld/COFF/ICF.cpp index 2b2818de3889cd..7e105ddad75b4a 100644 --- a/lld/COFF/ICF.cpp +++ b/lld/COFF/ICF.cpp @@ -37,32 +37,32 @@ using namespace llvm; namespace lld { namespace coff { -static Timer icfTimer("ICF", Timer::root()); +static Timer ICFTimer("ICF", Timer::root()); class ICF { public: - void run(ArrayRef v); + void run(ArrayRef V); private: - void segregate(size_t begin, size_t end, bool constant); + void segregate(size_t Begin, size_t End, bool Constant); - bool assocEquals(const SectionChunk *a, const SectionChunk *b); + bool assocEquals(const SectionChunk *A, const SectionChunk *B); - bool equalsConstant(const SectionChunk *a, const SectionChunk *b); - bool equalsVariable(const SectionChunk *a, const SectionChunk *b); + bool equalsConstant(const SectionChunk *A, const SectionChunk *B); + bool equalsVariable(const SectionChunk *A, const SectionChunk *B); - bool isEligible(SectionChunk *c); + bool isEligible(SectionChunk *C); - size_t findBoundary(size_t begin, size_t end); + size_t findBoundary(size_t Begin, size_t End); - void forEachClassRange(size_t begin, size_t end, - std::function fn); + void forEachClassRange(size_t Begin, size_t End, + std::function Fn); - void forEachClass(std::function fn); + void forEachClass(std::function Fn); - std::vector chunks; - int cnt = 0; - std::atomic repeat = {false}; + std::vector Chunks; + int Cnt = 0; + std::atomic Repeat = {false}; }; // Returns true if section S is subject of ICF. @@ -76,144 +76,144 @@ class ICF { // merge read-only sections in a couple of cases where the address of the // section is insignificant to the user program and the behaviour matches that // of the Visual C++ linker. -bool ICF::isEligible(SectionChunk *c) { +bool ICF::isEligible(SectionChunk *C) { // Non-comdat chunks, dead chunks, and writable chunks are not elegible. - bool writable = c->getOutputCharacteristics() & llvm::COFF::IMAGE_SCN_MEM_WRITE; - if (!c->isCOMDAT() || !c->live || writable) + bool Writable = C->getOutputCharacteristics() & llvm::COFF::IMAGE_SCN_MEM_WRITE; + if (!C->isCOMDAT() || !C->Live || Writable) return false; // Code sections are eligible. - if (c->getOutputCharacteristics() & llvm::COFF::IMAGE_SCN_MEM_EXECUTE) + if (C->getOutputCharacteristics() & llvm::COFF::IMAGE_SCN_MEM_EXECUTE) return true; // .pdata and .xdata unwind info sections are eligible. - StringRef outSecName = c->getSectionName().split('$').first; - if (outSecName == ".pdata" || outSecName == ".xdata") + StringRef OutSecName = C->getSectionName().split('$').first; + if (OutSecName == ".pdata" || OutSecName == ".xdata") return true; // So are vtables. - if (c->sym && c->sym->getName().startswith("??_7")) + if (C->Sym && C->Sym->getName().startswith("??_7")) return true; // Anything else not in an address-significance table is eligible. - return !c->keepUnique; + return !C->KeepUnique; } // Split an equivalence class into smaller classes. -void ICF::segregate(size_t begin, size_t end, bool constant) { - while (begin < end) { +void ICF::segregate(size_t Begin, size_t End, bool Constant) { + while (Begin < End) { // Divide [Begin, End) into two. Let Mid be the start index of the // second group. - auto bound = std::stable_partition( - chunks.begin() + begin + 1, chunks.begin() + end, [&](SectionChunk *s) { - if (constant) - return equalsConstant(chunks[begin], s); - return equalsVariable(chunks[begin], s); + auto Bound = std::stable_partition( + Chunks.begin() + Begin + 1, Chunks.begin() + End, [&](SectionChunk *S) { + if (Constant) + return equalsConstant(Chunks[Begin], S); + return equalsVariable(Chunks[Begin], S); }); - size_t mid = bound - chunks.begin(); + size_t Mid = Bound - Chunks.begin(); // Split [Begin, End) into [Begin, Mid) and [Mid, End). We use Mid as an // equivalence class ID because every group ends with a unique index. - for (size_t i = begin; i < mid; ++i) - chunks[i]->eqClass[(cnt + 1) % 2] = mid; + for (size_t I = Begin; I < Mid; ++I) + Chunks[I]->Class[(Cnt + 1) % 2] = Mid; // If we created a group, we need to iterate the main loop again. - if (mid != end) - repeat = true; + if (Mid != End) + Repeat = true; - begin = mid; + Begin = Mid; } } // Returns true if two sections' associative children are equal. -bool ICF::assocEquals(const SectionChunk *a, const SectionChunk *b) { - auto childClasses = [&](const SectionChunk *sc) { - std::vector classes; - for (const SectionChunk &c : sc->children()) - if (!c.getSectionName().startswith(".debug") && - c.getSectionName() != ".gfids$y" && c.getSectionName() != ".gljmp$y") - classes.push_back(c.eqClass[cnt % 2]); - return classes; +bool ICF::assocEquals(const SectionChunk *A, const SectionChunk *B) { + auto ChildClasses = [&](const SectionChunk *SC) { + std::vector Classes; + for (const SectionChunk &C : SC->children()) + if (!C.getSectionName().startswith(".debug") && + C.getSectionName() != ".gfids$y" && C.getSectionName() != ".gljmp$y") + Classes.push_back(C.Class[Cnt % 2]); + return Classes; }; - return childClasses(a) == childClasses(b); + return ChildClasses(A) == ChildClasses(B); } // Compare "non-moving" part of two sections, namely everything // except relocation targets. -bool ICF::equalsConstant(const SectionChunk *a, const SectionChunk *b) { - if (a->relocsSize != b->relocsSize) +bool ICF::equalsConstant(const SectionChunk *A, const SectionChunk *B) { + if (A->RelocsSize != B->RelocsSize) return false; // Compare relocations. - auto eq = [&](const coff_relocation &r1, const coff_relocation &r2) { - if (r1.Type != r2.Type || - r1.VirtualAddress != r2.VirtualAddress) { + auto Eq = [&](const coff_relocation &R1, const coff_relocation &R2) { + if (R1.Type != R2.Type || + R1.VirtualAddress != R2.VirtualAddress) { return false; } - Symbol *b1 = a->file->getSymbol(r1.SymbolTableIndex); - Symbol *b2 = b->file->getSymbol(r2.SymbolTableIndex); - if (b1 == b2) + Symbol *B1 = A->File->getSymbol(R1.SymbolTableIndex); + Symbol *B2 = B->File->getSymbol(R2.SymbolTableIndex); + if (B1 == B2) return true; - if (auto *d1 = dyn_cast(b1)) - if (auto *d2 = dyn_cast(b2)) - return d1->getValue() == d2->getValue() && - d1->getChunk()->eqClass[cnt % 2] == d2->getChunk()->eqClass[cnt % 2]; + if (auto *D1 = dyn_cast(B1)) + if (auto *D2 = dyn_cast(B2)) + return D1->getValue() == D2->getValue() && + D1->getChunk()->Class[Cnt % 2] == D2->getChunk()->Class[Cnt % 2]; return false; }; - if (!std::equal(a->getRelocs().begin(), a->getRelocs().end(), - b->getRelocs().begin(), eq)) + if (!std::equal(A->getRelocs().begin(), A->getRelocs().end(), + B->getRelocs().begin(), Eq)) return false; // Compare section attributes and contents. - return a->getOutputCharacteristics() == b->getOutputCharacteristics() && - a->getSectionName() == b->getSectionName() && - a->header->SizeOfRawData == b->header->SizeOfRawData && - a->checksum == b->checksum && a->getContents() == b->getContents() && - assocEquals(a, b); + return A->getOutputCharacteristics() == B->getOutputCharacteristics() && + A->getSectionName() == B->getSectionName() && + A->Header->SizeOfRawData == B->Header->SizeOfRawData && + A->Checksum == B->Checksum && A->getContents() == B->getContents() && + assocEquals(A, B); } // Compare "moving" part of two sections, namely relocation targets. -bool ICF::equalsVariable(const SectionChunk *a, const SectionChunk *b) { +bool ICF::equalsVariable(const SectionChunk *A, const SectionChunk *B) { // Compare relocations. - auto eq = [&](const coff_relocation &r1, const coff_relocation &r2) { - Symbol *b1 = a->file->getSymbol(r1.SymbolTableIndex); - Symbol *b2 = b->file->getSymbol(r2.SymbolTableIndex); - if (b1 == b2) + auto Eq = [&](const coff_relocation &R1, const coff_relocation &R2) { + Symbol *B1 = A->File->getSymbol(R1.SymbolTableIndex); + Symbol *B2 = B->File->getSymbol(R2.SymbolTableIndex); + if (B1 == B2) return true; - if (auto *d1 = dyn_cast(b1)) - if (auto *d2 = dyn_cast(b2)) - return d1->getChunk()->eqClass[cnt % 2] == d2->getChunk()->eqClass[cnt % 2]; + if (auto *D1 = dyn_cast(B1)) + if (auto *D2 = dyn_cast(B2)) + return D1->getChunk()->Class[Cnt % 2] == D2->getChunk()->Class[Cnt % 2]; return false; }; - return std::equal(a->getRelocs().begin(), a->getRelocs().end(), - b->getRelocs().begin(), eq) && - assocEquals(a, b); + return std::equal(A->getRelocs().begin(), A->getRelocs().end(), + B->getRelocs().begin(), Eq) && + assocEquals(A, B); } // Find the first Chunk after Begin that has a different class from Begin. -size_t ICF::findBoundary(size_t begin, size_t end) { - for (size_t i = begin + 1; i < end; ++i) - if (chunks[begin]->eqClass[cnt % 2] != chunks[i]->eqClass[cnt % 2]) - return i; - return end; +size_t ICF::findBoundary(size_t Begin, size_t End) { + for (size_t I = Begin + 1; I < End; ++I) + if (Chunks[Begin]->Class[Cnt % 2] != Chunks[I]->Class[Cnt % 2]) + return I; + return End; } -void ICF::forEachClassRange(size_t begin, size_t end, - std::function fn) { - while (begin < end) { - size_t mid = findBoundary(begin, end); - fn(begin, mid); - begin = mid; +void ICF::forEachClassRange(size_t Begin, size_t End, + std::function Fn) { + while (Begin < End) { + size_t Mid = findBoundary(Begin, End); + Fn(Begin, Mid); + Begin = Mid; } } // Call Fn on each class group. -void ICF::forEachClass(std::function fn) { +void ICF::forEachClass(std::function Fn) { // If the number of sections are too small to use threading, // call Fn sequentially. - if (chunks.size() < 1024) { - forEachClassRange(0, chunks.size(), fn); - ++cnt; + if (Chunks.size() < 1024) { + forEachClassRange(0, Chunks.size(), Fn); + ++Cnt; return; } @@ -221,97 +221,97 @@ void ICF::forEachClass(std::function fn) { // The sharding must be completed before any calls to Fn are made // so that Fn can modify the Chunks in its shard without causing data // races. - const size_t numShards = 256; - size_t step = chunks.size() / numShards; - size_t boundaries[numShards + 1]; - boundaries[0] = 0; - boundaries[numShards] = chunks.size(); - parallelForEachN(1, numShards, [&](size_t i) { - boundaries[i] = findBoundary((i - 1) * step, chunks.size()); + const size_t NumShards = 256; + size_t Step = Chunks.size() / NumShards; + size_t Boundaries[NumShards + 1]; + Boundaries[0] = 0; + Boundaries[NumShards] = Chunks.size(); + parallelForEachN(1, NumShards, [&](size_t I) { + Boundaries[I] = findBoundary((I - 1) * Step, Chunks.size()); }); - parallelForEachN(1, numShards + 1, [&](size_t i) { - if (boundaries[i - 1] < boundaries[i]) { - forEachClassRange(boundaries[i - 1], boundaries[i], fn); + parallelForEachN(1, NumShards + 1, [&](size_t I) { + if (Boundaries[I - 1] < Boundaries[I]) { + forEachClassRange(Boundaries[I - 1], Boundaries[I], Fn); } }); - ++cnt; + ++Cnt; } // Merge identical COMDAT sections. // Two sections are considered the same if their section headers, // contents and relocations are all the same. -void ICF::run(ArrayRef vec) { - ScopedTimer t(icfTimer); +void ICF::run(ArrayRef Vec) { + ScopedTimer T(ICFTimer); // Collect only mergeable sections and group by hash value. - uint32_t nextId = 1; - for (Chunk *c : vec) { - if (auto *sc = dyn_cast(c)) { - if (isEligible(sc)) - chunks.push_back(sc); + uint32_t NextId = 1; + for (Chunk *C : Vec) { + if (auto *SC = dyn_cast(C)) { + if (isEligible(SC)) + Chunks.push_back(SC); else - sc->eqClass[0] = nextId++; + SC->Class[0] = NextId++; } } // Make sure that ICF doesn't merge sections that are being handled by string // tail merging. - for (MergeChunk *mc : MergeChunk::instances) - if (mc) - for (SectionChunk *sc : mc->sections) - sc->eqClass[0] = nextId++; + for (MergeChunk *MC : MergeChunk::Instances) + if (MC) + for (SectionChunk *SC : MC->Sections) + SC->Class[0] = NextId++; // Initially, we use hash values to partition sections. - parallelForEach(chunks, [&](SectionChunk *sc) { - sc->eqClass[0] = xxHash64(sc->getContents()); + parallelForEach(Chunks, [&](SectionChunk *SC) { + SC->Class[0] = xxHash64(SC->getContents()); }); // Combine the hashes of the sections referenced by each section into its // hash. - for (unsigned cnt = 0; cnt != 2; ++cnt) { - parallelForEach(chunks, [&](SectionChunk *sc) { - uint32_t hash = sc->eqClass[cnt % 2]; - for (Symbol *b : sc->symbols()) - if (auto *sym = dyn_cast_or_null(b)) - hash += sym->getChunk()->eqClass[cnt % 2]; + for (unsigned Cnt = 0; Cnt != 2; ++Cnt) { + parallelForEach(Chunks, [&](SectionChunk *SC) { + uint32_t Hash = SC->Class[Cnt % 2]; + for (Symbol *B : SC->symbols()) + if (auto *Sym = dyn_cast_or_null(B)) + Hash += Sym->getChunk()->Class[Cnt % 2]; // Set MSB to 1 to avoid collisions with non-hash classs. - sc->eqClass[(cnt + 1) % 2] = hash | (1U << 31); + SC->Class[(Cnt + 1) % 2] = Hash | (1U << 31); }); } // From now on, sections in Chunks are ordered so that sections in // the same group are consecutive in the vector. - llvm::stable_sort(chunks, [](const SectionChunk *a, const SectionChunk *b) { - return a->eqClass[0] < b->eqClass[0]; + llvm::stable_sort(Chunks, [](const SectionChunk *A, const SectionChunk *B) { + return A->Class[0] < B->Class[0]; }); // Compare static contents and assign unique IDs for each static content. - forEachClass([&](size_t begin, size_t end) { segregate(begin, end, true); }); + forEachClass([&](size_t Begin, size_t End) { segregate(Begin, End, true); }); // Split groups by comparing relocations until convergence is obtained. do { - repeat = false; + Repeat = false; forEachClass( - [&](size_t begin, size_t end) { segregate(begin, end, false); }); - } while (repeat); + [&](size_t Begin, size_t End) { segregate(Begin, End, false); }); + } while (Repeat); - log("ICF needed " + Twine(cnt) + " iterations"); + log("ICF needed " + Twine(Cnt) + " iterations"); // Merge sections in the same classs. - forEachClass([&](size_t begin, size_t end) { - if (end - begin == 1) + forEachClass([&](size_t Begin, size_t End) { + if (End - Begin == 1) return; - log("Selected " + chunks[begin]->getDebugName()); - for (size_t i = begin + 1; i < end; ++i) { - log(" Removed " + chunks[i]->getDebugName()); - chunks[begin]->replace(chunks[i]); + log("Selected " + Chunks[Begin]->getDebugName()); + for (size_t I = Begin + 1; I < End; ++I) { + log(" Removed " + Chunks[I]->getDebugName()); + Chunks[Begin]->replace(Chunks[I]); } }); } // Entry point to ICF. -void doICF(ArrayRef chunks) { ICF().run(chunks); } +void doICF(ArrayRef Chunks) { ICF().run(Chunks); } } // namespace coff } // namespace lld diff --git a/lld/COFF/ICF.h b/lld/COFF/ICF.h index 0b3c8fa2ff2e03..f692c8af35e98a 100644 --- a/lld/COFF/ICF.h +++ b/lld/COFF/ICF.h @@ -17,7 +17,7 @@ namespace coff { class Chunk; -void doICF(ArrayRef chunks); +void doICF(ArrayRef Chunks); } // namespace coff } // namespace lld diff --git a/lld/COFF/InputFiles.cpp b/lld/COFF/InputFiles.cpp index 3f763563b2b3f2..ebf6e441843984 100644 --- a/lld/COFF/InputFiles.cpp +++ b/lld/COFF/InputFiles.cpp @@ -49,127 +49,80 @@ using llvm::support::ulittle32_t; namespace lld { namespace coff { -std::vector ObjFile::instances; -std::vector ImportFile::instances; -std::vector BitcodeFile::instances; +std::vector ObjFile::Instances; +std::vector ImportFile::Instances; +std::vector BitcodeFile::Instances; /// Checks that Source is compatible with being a weak alias to Target. /// If Source is Undefined and has no weak alias set, makes it a weak /// alias to Target. -static void checkAndSetWeakAlias(SymbolTable *symtab, InputFile *f, - Symbol *source, Symbol *target) { - if (auto *u = dyn_cast(source)) { - if (u->weakAlias && u->weakAlias != target) { +static void checkAndSetWeakAlias(SymbolTable *Symtab, InputFile *F, + Symbol *Source, Symbol *Target) { + if (auto *U = dyn_cast(Source)) { + if (U->WeakAlias && U->WeakAlias != Target) { // Weak aliases as produced by GCC are named in the form // .weak.., where is the name // of another symbol emitted near the weak symbol. // Just use the definition from the first object file that defined // this weak symbol. - if (config->mingw) + if (Config->MinGW) return; - symtab->reportDuplicate(source, f); + Symtab->reportDuplicate(Source, F); } - u->weakAlias = target; + U->WeakAlias = Target; } } -static bool ignoredSymbolName(StringRef name) { - return name == "@feat.00" || name == "@comp.id"; -} - -ArchiveFile::ArchiveFile(MemoryBufferRef m) : InputFile(ArchiveKind, m) {} +ArchiveFile::ArchiveFile(MemoryBufferRef M) : InputFile(ArchiveKind, M) {} void ArchiveFile::parse() { // Parse a MemoryBufferRef as an archive file. - file = CHECK(Archive::create(mb), this); + File = CHECK(Archive::create(MB), this); // Read the symbol table to construct Lazy objects. - for (const Archive::Symbol &sym : file->symbols()) - symtab->addLazyArchive(this, sym); + for (const Archive::Symbol &Sym : File->symbols()) + Symtab->addLazy(this, Sym); } // Returns a buffer pointing to a member file containing a given symbol. -void ArchiveFile::addMember(const Archive::Symbol &sym) { - const Archive::Child &c = - CHECK(sym.getMember(), - "could not get the member for symbol " + toCOFFString(sym)); +void ArchiveFile::addMember(const Archive::Symbol *Sym) { + const Archive::Child &C = + CHECK(Sym->getMember(), + "could not get the member for symbol " + Sym->getName()); // Return an empty buffer if we have already returned the same buffer. - if (!seen.insert(c.getChildOffset()).second) + if (!Seen.insert(C.getChildOffset()).second) return; - driver->enqueueArchiveMember(c, sym, getName()); + Driver->enqueueArchiveMember(C, Sym->getName(), getName()); } -std::vector getArchiveMembers(Archive *file) { - std::vector v; - Error err = Error::success(); - for (const ErrorOr &cOrErr : file->children(err)) { - Archive::Child c = - CHECK(cOrErr, - file->getFileName() + ": could not get the child of the archive"); - MemoryBufferRef mbref = - CHECK(c.getMemoryBufferRef(), - file->getFileName() + +std::vector getArchiveMembers(Archive *File) { + std::vector V; + Error Err = Error::success(); + for (const ErrorOr &COrErr : File->children(Err)) { + Archive::Child C = + CHECK(COrErr, + File->getFileName() + ": could not get the child of the archive"); + MemoryBufferRef MBRef = + CHECK(C.getMemoryBufferRef(), + File->getFileName() + ": could not get the buffer for a child of the archive"); - v.push_back(mbref); - } - if (err) - fatal(file->getFileName() + - ": Archive::children failed: " + toString(std::move(err))); - return v; -} - -void LazyObjFile::fetch() { - if (mb.getBuffer().empty()) - return; - - InputFile *file; - if (isBitcode(mb)) - file = make(mb, "", 0, std::move(symbols)); - else - file = make(mb, std::move(symbols)); - mb = {}; - symtab->addFile(file); -} - -void LazyObjFile::parse() { - if (isBitcode(this->mb)) { - // Bitcode file. - std::unique_ptr obj = - CHECK(lto::InputFile::create(this->mb), this); - for (const lto::InputFile::Symbol &sym : obj->symbols()) { - if (!sym.isUndefined()) - symtab->addLazyObject(this, sym.getName()); - } - return; - } - - // Native object file. - std::unique_ptr coffObjPtr = CHECK(createBinary(mb), this); - COFFObjectFile *coffObj = cast(coffObjPtr.get()); - uint32_t numSymbols = coffObj->getNumberOfSymbols(); - for (uint32_t i = 0; i < numSymbols; ++i) { - COFFSymbolRef coffSym = check(coffObj->getSymbol(i)); - if (coffSym.isUndefined() || !coffSym.isExternal() || - coffSym.isWeakExternal()) - continue; - StringRef name; - coffObj->getSymbolName(coffSym, name); - if (coffSym.isAbsolute() && ignoredSymbolName(name)) - continue; - symtab->addLazyObject(this, name); - i += coffSym.getNumberOfAuxSymbols(); + V.push_back(MBRef); } + if (Err) + fatal(File->getFileName() + + ": Archive::children failed: " + toString(std::move(Err))); + return V; } void ObjFile::parse() { // Parse a memory buffer as a COFF file. - std::unique_ptr bin = CHECK(createBinary(mb), this); + std::unique_ptr Bin = CHECK(createBinary(MB), this); - if (auto *obj = dyn_cast(bin.get())) { - bin.release(); - coffObj.reset(obj); + if (auto *Obj = dyn_cast(Bin.get())) { + Bin.release(); + COFFObj.reset(Obj); } else { fatal(toString(this) + " is not a COFF file"); } @@ -181,11 +134,11 @@ void ObjFile::parse() { initializeDependencies(); } -const coff_section* ObjFile::getSection(uint32_t i) { - const coff_section *sec; - if (auto ec = coffObj->getSection(i, sec)) - fatal("getSection failed: #" + Twine(i) + ": " + ec.message()); - return sec; +const coff_section* ObjFile::getSection(uint32_t I) { + const coff_section *Sec; + if (auto EC = COFFObj->getSection(I, Sec)) + fatal("getSection failed: #" + Twine(I) + ": " + EC.message()); + return Sec; } // We set SectionChunk pointers in the SparseChunks vector to this value @@ -194,42 +147,42 @@ const coff_section* ObjFile::getSection(uint32_t i) { // an associative section definition together with the parent comdat's leader, // we set the pointer to either nullptr (to mark the section as discarded) or a // valid SectionChunk for that section. -static SectionChunk *const pendingComdat = reinterpret_cast(1); +static SectionChunk *const PendingComdat = reinterpret_cast(1); void ObjFile::initializeChunks() { - uint32_t numSections = coffObj->getNumberOfSections(); - chunks.reserve(numSections); - sparseChunks.resize(numSections + 1); - for (uint32_t i = 1; i < numSections + 1; ++i) { - const coff_section *sec = getSection(i); - if (sec->Characteristics & IMAGE_SCN_LNK_COMDAT) - sparseChunks[i] = pendingComdat; + uint32_t NumSections = COFFObj->getNumberOfSections(); + Chunks.reserve(NumSections); + SparseChunks.resize(NumSections + 1); + for (uint32_t I = 1; I < NumSections + 1; ++I) { + const coff_section *Sec = getSection(I); + if (Sec->Characteristics & IMAGE_SCN_LNK_COMDAT) + SparseChunks[I] = PendingComdat; else - sparseChunks[i] = readSection(i, nullptr, ""); + SparseChunks[I] = readSection(I, nullptr, ""); } } -SectionChunk *ObjFile::readSection(uint32_t sectionNumber, - const coff_aux_section_definition *def, - StringRef leaderName) { - const coff_section *sec = getSection(sectionNumber); +SectionChunk *ObjFile::readSection(uint32_t SectionNumber, + const coff_aux_section_definition *Def, + StringRef LeaderName) { + const coff_section *Sec = getSection(SectionNumber); - StringRef name; - if (Expected e = coffObj->getSectionName(sec)) - name = *e; + StringRef Name; + if (Expected E = COFFObj->getSectionName(Sec)) + Name = *E; else - fatal("getSectionName failed: #" + Twine(sectionNumber) + ": " + - toString(e.takeError())); + fatal("getSectionName failed: #" + Twine(SectionNumber) + ": " + + toString(E.takeError())); - if (name == ".drectve") { - ArrayRef data; - cantFail(coffObj->getSectionContents(sec, data)); - directives = StringRef((const char *)data.data(), data.size()); + if (Name == ".drectve") { + ArrayRef Data; + cantFail(COFFObj->getSectionContents(Sec, Data)); + Directives = StringRef((const char *)Data.data(), Data.size()); return nullptr; } - if (name == ".llvm_addrsig") { - addrsigSec = sec; + if (Name == ".llvm_addrsig") { + AddrsigSec = Sec; return nullptr; } @@ -244,168 +197,166 @@ SectionChunk *ObjFile::readSection(uint32_t sectionNumber, // and then write it to a separate .pdb file. // Ignore DWARF debug info unless /debug is given. - if (!config->debug && name.startswith(".debug_")) + if (!Config->Debug && Name.startswith(".debug_")) return nullptr; - if (sec->Characteristics & llvm::COFF::IMAGE_SCN_LNK_REMOVE) + if (Sec->Characteristics & llvm::COFF::IMAGE_SCN_LNK_REMOVE) return nullptr; - auto *c = make(this, sec); - if (def) - c->checksum = def->CheckSum; + auto *C = make(this, Sec); + if (Def) + C->Checksum = Def->CheckSum; + + // link.exe uses the presence of .rsrc$01 for LNK4078, so match that. + if (Name == ".rsrc$01") + IsResourceObjFile = true; // CodeView sections are stored to a different vector because they are not // linked in the regular manner. - if (c->isCodeView()) - debugChunks.push_back(c); - else if (name == ".gfids$y") - guardFidChunks.push_back(c); - else if (name == ".gljmp$y") - guardLJmpChunks.push_back(c); - else if (name == ".sxdata") - sXDataChunks.push_back(c); - else if (config->tailMerge && sec->NumberOfRelocations == 0 && - name == ".rdata" && leaderName.startswith("??_C@")) + if (C->isCodeView()) + DebugChunks.push_back(C); + else if (Name == ".gfids$y") + GuardFidChunks.push_back(C); + else if (Name == ".gljmp$y") + GuardLJmpChunks.push_back(C); + else if (Name == ".sxdata") + SXDataChunks.push_back(C); + else if (Config->TailMerge && Sec->NumberOfRelocations == 0 && + Name == ".rdata" && LeaderName.startswith("??_C@")) // COFF sections that look like string literal sections (i.e. no // relocations, in .rdata, leader symbol name matches the MSVC name mangling // for string literals) are subject to string tail merging. - MergeChunk::addSection(c); - else if (name == ".rsrc" || name.startswith(".rsrc$")) - resourceChunks.push_back(c); + MergeChunk::addSection(C); else - chunks.push_back(c); + Chunks.push_back(C); - return c; -} - -void ObjFile::includeResourceChunks() { - chunks.insert(chunks.end(), resourceChunks.begin(), resourceChunks.end()); + return C; } void ObjFile::readAssociativeDefinition( - COFFSymbolRef sym, const coff_aux_section_definition *def) { - readAssociativeDefinition(sym, def, def->getNumber(sym.isBigObj())); -} - -void ObjFile::readAssociativeDefinition(COFFSymbolRef sym, - const coff_aux_section_definition *def, - uint32_t parentIndex) { - SectionChunk *parent = sparseChunks[parentIndex]; - int32_t sectionNumber = sym.getSectionNumber(); - - auto diag = [&]() { - StringRef name, parentName; - coffObj->getSymbolName(sym, name); - - const coff_section *parentSec = getSection(parentIndex); - if (Expected e = coffObj->getSectionName(parentSec)) - parentName = *e; - error(toString(this) + ": associative comdat " + name + " (sec " + - Twine(sectionNumber) + ") has invalid reference to section " + - parentName + " (sec " + Twine(parentIndex) + ")"); + COFFSymbolRef Sym, const coff_aux_section_definition *Def) { + readAssociativeDefinition(Sym, Def, Def->getNumber(Sym.isBigObj())); +} + +void ObjFile::readAssociativeDefinition(COFFSymbolRef Sym, + const coff_aux_section_definition *Def, + uint32_t ParentIndex) { + SectionChunk *Parent = SparseChunks[ParentIndex]; + int32_t SectionNumber = Sym.getSectionNumber(); + + auto Diag = [&]() { + StringRef Name, ParentName; + COFFObj->getSymbolName(Sym, Name); + + const coff_section *ParentSec = getSection(ParentIndex); + if (Expected E = COFFObj->getSectionName(ParentSec)) + ParentName = *E; + error(toString(this) + ": associative comdat " + Name + " (sec " + + Twine(SectionNumber) + ") has invalid reference to section " + + ParentName + " (sec " + Twine(ParentIndex) + ")"); }; - if (parent == pendingComdat) { + if (Parent == PendingComdat) { // This can happen if an associative comdat refers to another associative // comdat that appears after it (invalid per COFF spec) or to a section // without any symbols. - diag(); + Diag(); return; } // Check whether the parent is prevailing. If it is, so are we, and we read // the section; otherwise mark it as discarded. - if (parent) { - SectionChunk *c = readSection(sectionNumber, def, ""); - sparseChunks[sectionNumber] = c; - if (c) { - c->selection = IMAGE_COMDAT_SELECT_ASSOCIATIVE; - parent->addAssociative(c); + if (Parent) { + SectionChunk *C = readSection(SectionNumber, Def, ""); + SparseChunks[SectionNumber] = C; + if (C) { + C->Selection = IMAGE_COMDAT_SELECT_ASSOCIATIVE; + Parent->addAssociative(C); } } else { - sparseChunks[sectionNumber] = nullptr; + SparseChunks[SectionNumber] = nullptr; } } void ObjFile::recordPrevailingSymbolForMingw( - COFFSymbolRef sym, DenseMap &prevailingSectionMap) { + COFFSymbolRef Sym, DenseMap &PrevailingSectionMap) { // For comdat symbols in executable sections, where this is the copy // of the section chunk we actually include instead of discarding it, // add the symbol to a map to allow using it for implicitly // associating .[px]data$ sections to it. - int32_t sectionNumber = sym.getSectionNumber(); - SectionChunk *sc = sparseChunks[sectionNumber]; - if (sc && sc->getOutputCharacteristics() & IMAGE_SCN_MEM_EXECUTE) { - StringRef name; - coffObj->getSymbolName(sym, name); + int32_t SectionNumber = Sym.getSectionNumber(); + SectionChunk *SC = SparseChunks[SectionNumber]; + if (SC && SC->getOutputCharacteristics() & IMAGE_SCN_MEM_EXECUTE) { + StringRef Name; + COFFObj->getSymbolName(Sym, Name); if (getMachineType() == I386) - name.consume_front("_"); - prevailingSectionMap[name] = sectionNumber; + Name.consume_front("_"); + PrevailingSectionMap[Name] = SectionNumber; } } void ObjFile::maybeAssociateSEHForMingw( - COFFSymbolRef sym, const coff_aux_section_definition *def, - const DenseMap &prevailingSectionMap) { - StringRef name; - coffObj->getSymbolName(sym, name); - if (name.consume_front(".pdata$") || name.consume_front(".xdata$") || - name.consume_front(".eh_frame$")) { + COFFSymbolRef Sym, const coff_aux_section_definition *Def, + const DenseMap &PrevailingSectionMap) { + StringRef Name; + COFFObj->getSymbolName(Sym, Name); + if (Name.consume_front(".pdata$") || Name.consume_front(".xdata$") || + Name.consume_front(".eh_frame$")) { // For MinGW, treat .[px]data$ and .eh_frame$ as implicitly // associative to the symbol . - auto parentSym = prevailingSectionMap.find(name); - if (parentSym != prevailingSectionMap.end()) - readAssociativeDefinition(sym, def, parentSym->second); + auto ParentSym = PrevailingSectionMap.find(Name); + if (ParentSym != PrevailingSectionMap.end()) + readAssociativeDefinition(Sym, Def, ParentSym->second); } } -Symbol *ObjFile::createRegular(COFFSymbolRef sym) { - SectionChunk *sc = sparseChunks[sym.getSectionNumber()]; - if (sym.isExternal()) { - StringRef name; - coffObj->getSymbolName(sym, name); - if (sc) - return symtab->addRegular(this, name, sym.getGeneric(), sc); +Symbol *ObjFile::createRegular(COFFSymbolRef Sym) { + SectionChunk *SC = SparseChunks[Sym.getSectionNumber()]; + if (Sym.isExternal()) { + StringRef Name; + COFFObj->getSymbolName(Sym, Name); + if (SC) + return Symtab->addRegular(this, Name, Sym.getGeneric(), SC); // For MinGW symbols named .weak.* that point to a discarded section, // don't create an Undefined symbol. If nothing ever refers to the symbol, // everything should be fine. If something actually refers to the symbol // (e.g. the undefined weak alias), linking will fail due to undefined // references at the end. - if (config->mingw && name.startswith(".weak.")) + if (Config->MinGW && Name.startswith(".weak.")) return nullptr; - return symtab->addUndefined(name, this, false); + return Symtab->addUndefined(Name, this, false); } - if (sc) + if (SC) return make(this, /*Name*/ "", /*IsCOMDAT*/ false, - /*IsExternal*/ false, sym.getGeneric(), sc); + /*IsExternal*/ false, Sym.getGeneric(), SC); return nullptr; } void ObjFile::initializeSymbols() { - uint32_t numSymbols = coffObj->getNumberOfSymbols(); - symbols.resize(numSymbols); - - SmallVector, 8> weakAliases; - std::vector pendingIndexes; - pendingIndexes.reserve(numSymbols); - - DenseMap prevailingSectionMap; - std::vector comdatDefs( - coffObj->getNumberOfSections() + 1); - - for (uint32_t i = 0; i < numSymbols; ++i) { - COFFSymbolRef coffSym = check(coffObj->getSymbol(i)); - bool prevailingComdat; - if (coffSym.isUndefined()) { - symbols[i] = createUndefined(coffSym); - } else if (coffSym.isWeakExternal()) { - symbols[i] = createUndefined(coffSym); - uint32_t tagIndex = coffSym.getAux()->TagIndex; - weakAliases.emplace_back(symbols[i], tagIndex); - } else if (Optional optSym = - createDefined(coffSym, comdatDefs, prevailingComdat)) { - symbols[i] = *optSym; - if (config->mingw && prevailingComdat) - recordPrevailingSymbolForMingw(coffSym, prevailingSectionMap); + uint32_t NumSymbols = COFFObj->getNumberOfSymbols(); + Symbols.resize(NumSymbols); + + SmallVector, 8> WeakAliases; + std::vector PendingIndexes; + PendingIndexes.reserve(NumSymbols); + + DenseMap PrevailingSectionMap; + std::vector ComdatDefs( + COFFObj->getNumberOfSections() + 1); + + for (uint32_t I = 0; I < NumSymbols; ++I) { + COFFSymbolRef COFFSym = check(COFFObj->getSymbol(I)); + bool PrevailingComdat; + if (COFFSym.isUndefined()) { + Symbols[I] = createUndefined(COFFSym); + } else if (COFFSym.isWeakExternal()) { + Symbols[I] = createUndefined(COFFSym); + uint32_t TagIndex = COFFSym.getAux()->TagIndex; + WeakAliases.emplace_back(Symbols[I], TagIndex); + } else if (Optional OptSym = + createDefined(COFFSym, ComdatDefs, PrevailingComdat)) { + Symbols[I] = *OptSym; + if (Config->MinGW && PrevailingComdat) + recordPrevailingSymbolForMingw(COFFSym, PrevailingSectionMap); } else { // createDefined() returns None if a symbol belongs to a section that // was pending at the point when the symbol was read. This can happen in @@ -415,71 +366,71 @@ void ObjFile::initializeSymbols() { // In both of these cases, we can expect the section to be resolved by // the time we finish visiting the remaining symbols in the symbol // table. So we postpone the handling of this symbol until that time. - pendingIndexes.push_back(i); + PendingIndexes.push_back(I); } - i += coffSym.getNumberOfAuxSymbols(); + I += COFFSym.getNumberOfAuxSymbols(); } - for (uint32_t i : pendingIndexes) { - COFFSymbolRef sym = check(coffObj->getSymbol(i)); - if (const coff_aux_section_definition *def = sym.getSectionDefinition()) { - if (def->Selection == IMAGE_COMDAT_SELECT_ASSOCIATIVE) - readAssociativeDefinition(sym, def); - else if (config->mingw) - maybeAssociateSEHForMingw(sym, def, prevailingSectionMap); + for (uint32_t I : PendingIndexes) { + COFFSymbolRef Sym = check(COFFObj->getSymbol(I)); + if (const coff_aux_section_definition *Def = Sym.getSectionDefinition()) { + if (Def->Selection == IMAGE_COMDAT_SELECT_ASSOCIATIVE) + readAssociativeDefinition(Sym, Def); + else if (Config->MinGW) + maybeAssociateSEHForMingw(Sym, Def, PrevailingSectionMap); } - if (sparseChunks[sym.getSectionNumber()] == pendingComdat) { - StringRef name; - coffObj->getSymbolName(sym, name); - log("comdat section " + name + + if (SparseChunks[Sym.getSectionNumber()] == PendingComdat) { + StringRef Name; + COFFObj->getSymbolName(Sym, Name); + log("comdat section " + Name + " without leader and unassociated, discarding"); continue; } - symbols[i] = createRegular(sym); + Symbols[I] = createRegular(Sym); } - for (auto &kv : weakAliases) { - Symbol *sym = kv.first; - uint32_t idx = kv.second; - checkAndSetWeakAlias(symtab, this, sym, symbols[idx]); + for (auto &KV : WeakAliases) { + Symbol *Sym = KV.first; + uint32_t Idx = KV.second; + checkAndSetWeakAlias(Symtab, this, Sym, Symbols[Idx]); } } -Symbol *ObjFile::createUndefined(COFFSymbolRef sym) { - StringRef name; - coffObj->getSymbolName(sym, name); - return symtab->addUndefined(name, this, sym.isWeakExternal()); +Symbol *ObjFile::createUndefined(COFFSymbolRef Sym) { + StringRef Name; + COFFObj->getSymbolName(Sym, Name); + return Symtab->addUndefined(Name, this, Sym.isWeakExternal()); } -void ObjFile::handleComdatSelection(COFFSymbolRef sym, COMDATType &selection, - bool &prevailing, DefinedRegular *leader) { - if (prevailing) +void ObjFile::handleComdatSelection(COFFSymbolRef Sym, COMDATType &Selection, + bool &Prevailing, DefinedRegular *Leader) { + if (Prevailing) return; // There's already an existing comdat for this symbol: `Leader`. // Use the comdats's selection field to determine if the new // symbol in `Sym` should be discarded, produce a duplicate symbol // error, etc. - SectionChunk *leaderChunk = nullptr; - COMDATType leaderSelection = IMAGE_COMDAT_SELECT_ANY; + SectionChunk *LeaderChunk = nullptr; + COMDATType LeaderSelection = IMAGE_COMDAT_SELECT_ANY; - if (leader->data) { - leaderChunk = leader->getChunk(); - leaderSelection = leaderChunk->selection; + if (Leader->Data) { + LeaderChunk = Leader->getChunk(); + LeaderSelection = LeaderChunk->Selection; } else { // FIXME: comdats from LTO files don't know their selection; treat them // as "any". - selection = leaderSelection; + Selection = LeaderSelection; } - if ((selection == IMAGE_COMDAT_SELECT_ANY && - leaderSelection == IMAGE_COMDAT_SELECT_LARGEST) || - (selection == IMAGE_COMDAT_SELECT_LARGEST && - leaderSelection == IMAGE_COMDAT_SELECT_ANY)) { + if ((Selection == IMAGE_COMDAT_SELECT_ANY && + LeaderSelection == IMAGE_COMDAT_SELECT_LARGEST) || + (Selection == IMAGE_COMDAT_SELECT_LARGEST && + LeaderSelection == IMAGE_COMDAT_SELECT_ANY)) { // cl.exe picks "any" for vftables when building with /GR- and // "largest" when building with /GR. To be able to link object files // compiled with each flag, "any" and "largest" are merged as "largest". - leaderSelection = selection = IMAGE_COMDAT_SELECT_LARGEST; + LeaderSelection = Selection = IMAGE_COMDAT_SELECT_LARGEST; } // Other than that, comdat selections must match. This is a bit more @@ -489,18 +440,18 @@ void ObjFile::handleComdatSelection(COFFSymbolRef sym, COMDATType &selection, // Making this symmetric independent of which selection is seen first // seems better though. // (This behavior matches ModuleLinker::getComdatResult().) - if (selection != leaderSelection) { - log(("conflicting comdat type for " + toString(*leader) + ": " + - Twine((int)leaderSelection) + " in " + toString(leader->getFile()) + - " and " + Twine((int)selection) + " in " + toString(this)) + if (Selection != LeaderSelection) { + log(("conflicting comdat type for " + toString(*Leader) + ": " + + Twine((int)LeaderSelection) + " in " + toString(Leader->getFile()) + + " and " + Twine((int)Selection) + " in " + toString(this)) .str()); - symtab->reportDuplicate(leader, this); + Symtab->reportDuplicate(Leader, this); return; } - switch (selection) { + switch (Selection) { case IMAGE_COMDAT_SELECT_NODUPLICATES: - symtab->reportDuplicate(leader, this); + Symtab->reportDuplicate(Leader, this); break; case IMAGE_COMDAT_SELECT_ANY: @@ -508,17 +459,17 @@ void ObjFile::handleComdatSelection(COFFSymbolRef sym, COMDATType &selection, break; case IMAGE_COMDAT_SELECT_SAME_SIZE: - if (leaderChunk->getSize() != getSection(sym)->SizeOfRawData) - symtab->reportDuplicate(leader, this); + if (LeaderChunk->getSize() != getSection(Sym)->SizeOfRawData) + Symtab->reportDuplicate(Leader, this); break; case IMAGE_COMDAT_SELECT_EXACT_MATCH: { - SectionChunk newChunk(this, getSection(sym)); + SectionChunk NewChunk(this, getSection(Sym)); // link.exe only compares section contents here and doesn't complain // if the two comdat sections have e.g. different alignment. // Match that. - if (leaderChunk->getContents() != newChunk.getContents()) - symtab->reportDuplicate(leader, this); + if (LeaderChunk->getContents() != NewChunk.getContents()) + Symtab->reportDuplicate(Leader, this); break; } @@ -530,20 +481,20 @@ void ObjFile::handleComdatSelection(COFFSymbolRef sym, COMDATType &selection, llvm_unreachable("createDefined not called for associative comdats"); case IMAGE_COMDAT_SELECT_LARGEST: - if (leaderChunk->getSize() < getSection(sym)->SizeOfRawData) { + if (LeaderChunk->getSize() < getSection(Sym)->SizeOfRawData) { // Replace the existing comdat symbol with the new one. - StringRef name; - coffObj->getSymbolName(sym, name); + StringRef Name; + COFFObj->getSymbolName(Sym, Name); // FIXME: This is incorrect: With /opt:noref, the previous sections // make it into the final executable as well. Correct handling would // be to undo reading of the whole old section that's being replaced, // or doing one pass that determines what the final largest comdat // is for all IMAGE_COMDAT_SELECT_LARGEST comdats and then reading // only the largest one. - replaceSymbol(leader, this, name, /*IsCOMDAT*/ true, - /*IsExternal*/ true, sym.getGeneric(), + replaceSymbol(Leader, this, Name, /*IsCOMDAT*/ true, + /*IsExternal*/ true, Sym.getGeneric(), nullptr); - prevailing = true; + Prevailing = true; } break; @@ -553,48 +504,50 @@ void ObjFile::handleComdatSelection(COFFSymbolRef sym, COMDATType &selection, } Optional ObjFile::createDefined( - COFFSymbolRef sym, - std::vector &comdatDefs, - bool &prevailing) { - prevailing = false; - auto getName = [&]() { - StringRef s; - coffObj->getSymbolName(sym, s); - return s; + COFFSymbolRef Sym, + std::vector &ComdatDefs, + bool &Prevailing) { + Prevailing = false; + auto GetName = [&]() { + StringRef S; + COFFObj->getSymbolName(Sym, S); + return S; }; - if (sym.isCommon()) { - auto *c = make(sym); - chunks.push_back(c); - return symtab->addCommon(this, getName(), sym.getValue(), sym.getGeneric(), - c); + if (Sym.isCommon()) { + auto *C = make(Sym); + Chunks.push_back(C); + return Symtab->addCommon(this, GetName(), Sym.getValue(), Sym.getGeneric(), + C); } - if (sym.isAbsolute()) { - StringRef name = getName(); + if (Sym.isAbsolute()) { + StringRef Name = GetName(); - if (name == "@feat.00") - feat00Flags = sym.getValue(); // Skip special symbols. - if (ignoredSymbolName(name)) + if (Name == "@comp.id") + return nullptr; + if (Name == "@feat.00") { + Feat00Flags = Sym.getValue(); return nullptr; + } - if (sym.isExternal()) - return symtab->addAbsolute(name, sym); - return make(name, sym); + if (Sym.isExternal()) + return Symtab->addAbsolute(Name, Sym); + return make(Name, Sym); } - int32_t sectionNumber = sym.getSectionNumber(); - if (sectionNumber == llvm::COFF::IMAGE_SYM_DEBUG) + int32_t SectionNumber = Sym.getSectionNumber(); + if (SectionNumber == llvm::COFF::IMAGE_SYM_DEBUG) return nullptr; - if (llvm::COFF::isReservedSectionNumber(sectionNumber)) - fatal(toString(this) + ": " + getName() + - " should not refer to special section " + Twine(sectionNumber)); + if (llvm::COFF::isReservedSectionNumber(SectionNumber)) + fatal(toString(this) + ": " + GetName() + + " should not refer to special section " + Twine(SectionNumber)); - if ((uint32_t)sectionNumber >= sparseChunks.size()) - fatal(toString(this) + ": " + getName() + - " should not refer to non-existent section " + Twine(sectionNumber)); + if ((uint32_t)SectionNumber >= SparseChunks.size()) + fatal(toString(this) + ": " + GetName() + + " should not refer to non-existent section " + Twine(SectionNumber)); // Comdat handling. // A comdat symbol consists of two symbol table entries. @@ -603,69 +556,69 @@ Optional ObjFile::createDefined( // The second symbol entry has the name of the comdat symbol, called the // "comdat leader". // When this function is called for the first symbol entry of a comdat, - // it sets comdatDefs and returns None, and when it's called for the second - // symbol entry it reads comdatDefs and then sets it back to nullptr. + // it sets ComdatDefs and returns None, and when it's called for the second + // symbol entry it reads ComdatDefs and then sets it back to nullptr. // Handle comdat leader. - if (const coff_aux_section_definition *def = comdatDefs[sectionNumber]) { - comdatDefs[sectionNumber] = nullptr; - DefinedRegular *leader; + if (const coff_aux_section_definition *Def = ComdatDefs[SectionNumber]) { + ComdatDefs[SectionNumber] = nullptr; + DefinedRegular *Leader; - if (sym.isExternal()) { - std::tie(leader, prevailing) = - symtab->addComdat(this, getName(), sym.getGeneric()); + if (Sym.isExternal()) { + std::tie(Leader, Prevailing) = + Symtab->addComdat(this, GetName(), Sym.getGeneric()); } else { - leader = make(this, /*Name*/ "", /*IsCOMDAT*/ false, - /*IsExternal*/ false, sym.getGeneric()); - prevailing = true; + Leader = make(this, /*Name*/ "", /*IsCOMDAT*/ false, + /*IsExternal*/ false, Sym.getGeneric()); + Prevailing = true; } - if (def->Selection < (int)IMAGE_COMDAT_SELECT_NODUPLICATES || + if (Def->Selection < (int)IMAGE_COMDAT_SELECT_NODUPLICATES || // Intentionally ends at IMAGE_COMDAT_SELECT_LARGEST: link.exe // doesn't understand IMAGE_COMDAT_SELECT_NEWEST either. - def->Selection > (int)IMAGE_COMDAT_SELECT_LARGEST) { - fatal("unknown comdat type " + std::to_string((int)def->Selection) + - " for " + getName() + " in " + toString(this)); + Def->Selection > (int)IMAGE_COMDAT_SELECT_LARGEST) { + fatal("unknown comdat type " + std::to_string((int)Def->Selection) + + " for " + GetName() + " in " + toString(this)); } - COMDATType selection = (COMDATType)def->Selection; + COMDATType Selection = (COMDATType)Def->Selection; - if (leader->isCOMDAT) - handleComdatSelection(sym, selection, prevailing, leader); + if (Leader->isCOMDAT()) + handleComdatSelection(Sym, Selection, Prevailing, Leader); - if (prevailing) { - SectionChunk *c = readSection(sectionNumber, def, getName()); - sparseChunks[sectionNumber] = c; - c->sym = cast(leader); - c->selection = selection; - cast(leader)->data = &c->repl; + if (Prevailing) { + SectionChunk *C = readSection(SectionNumber, Def, GetName()); + SparseChunks[SectionNumber] = C; + C->Sym = cast(Leader); + C->Selection = Selection; + cast(Leader)->Data = &C->Repl; } else { - sparseChunks[sectionNumber] = nullptr; + SparseChunks[SectionNumber] = nullptr; } - return leader; + return Leader; } // Prepare to handle the comdat leader symbol by setting the section's // ComdatDefs pointer if we encounter a non-associative comdat. - if (sparseChunks[sectionNumber] == pendingComdat) { - if (const coff_aux_section_definition *def = sym.getSectionDefinition()) { - if (def->Selection != IMAGE_COMDAT_SELECT_ASSOCIATIVE) - comdatDefs[sectionNumber] = def; + if (SparseChunks[SectionNumber] == PendingComdat) { + if (const coff_aux_section_definition *Def = Sym.getSectionDefinition()) { + if (Def->Selection != IMAGE_COMDAT_SELECT_ASSOCIATIVE) + ComdatDefs[SectionNumber] = Def; } return None; } - return createRegular(sym); + return createRegular(Sym); } MachineTypes ObjFile::getMachineType() { - if (coffObj) - return static_cast(coffObj->getMachine()); + if (COFFObj) + return static_cast(COFFObj->getMachine()); return IMAGE_FILE_MACHINE_UNKNOWN; } -ArrayRef ObjFile::getDebugSection(StringRef secName) { - if (SectionChunk *sec = SectionChunk::findByName(debugChunks, secName)) - return sec->consumeDebugMagic(); +ArrayRef ObjFile::getDebugSection(StringRef SecName) { + if (SectionChunk *Sec = SectionChunk::findByName(DebugChunks, SecName)) + return Sec->consumeDebugMagic(); return {}; } @@ -673,45 +626,45 @@ ArrayRef ObjFile::getDebugSection(StringRef secName) { // even if the TU was compiled with no debug info. At least two records are // always there. S_OBJNAME stores a 32-bit signature, which is loaded into the // PCHSignature member. S_COMPILE3 stores compile-time cmd-line flags. This is -// currently used to initialize the hotPatchable member. +// currently used to initialize the HotPatchable member. void ObjFile::initializeFlags() { - ArrayRef data = getDebugSection(".debug$S"); - if (data.empty()) + ArrayRef Data = getDebugSection(".debug$S"); + if (Data.empty()) return; - DebugSubsectionArray subsections; + DebugSubsectionArray Subsections; - BinaryStreamReader reader(data, support::little); - ExitOnError exitOnErr; - exitOnErr(reader.readArray(subsections, data.size())); + BinaryStreamReader Reader(Data, support::little); + ExitOnError ExitOnErr; + ExitOnErr(Reader.readArray(Subsections, Data.size())); - for (const DebugSubsectionRecord &ss : subsections) { - if (ss.kind() != DebugSubsectionKind::Symbols) + for (const DebugSubsectionRecord &SS : Subsections) { + if (SS.kind() != DebugSubsectionKind::Symbols) continue; - unsigned offset = 0; + unsigned Offset = 0; // Only parse the first two records. We are only looking for S_OBJNAME // and S_COMPILE3, and they usually appear at the beginning of the // stream. - for (unsigned i = 0; i < 2; ++i) { - Expected sym = readSymbolFromStream(ss.getRecordData(), offset); - if (!sym) { - consumeError(sym.takeError()); + for (unsigned I = 0; I < 2; ++I) { + Expected Sym = readSymbolFromStream(SS.getRecordData(), Offset); + if (!Sym) { + consumeError(Sym.takeError()); return; } - if (sym->kind() == SymbolKind::S_COMPILE3) { - auto cs = - cantFail(SymbolDeserializer::deserializeAs(sym.get())); - hotPatchable = - (cs.Flags & CompileSym3Flags::HotPatch) != CompileSym3Flags::None; + if (Sym->kind() == SymbolKind::S_COMPILE3) { + auto CS = + cantFail(SymbolDeserializer::deserializeAs(Sym.get())); + HotPatchable = + (CS.Flags & CompileSym3Flags::HotPatch) != CompileSym3Flags::None; } - if (sym->kind() == SymbolKind::S_OBJNAME) { - auto objName = cantFail(SymbolDeserializer::deserializeAs( - sym.get())); - pchSignature = objName.Signature; + if (Sym->kind() == SymbolKind::S_OBJNAME) { + auto ObjName = cantFail(SymbolDeserializer::deserializeAs( + Sym.get())); + PCHSignature = ObjName.Signature; } - offset += sym->length(); + Offset += Sym->length(); } } } @@ -724,115 +677,112 @@ void ObjFile::initializeFlags() { // DebugTypes.h). Both cases only happen with cl.exe: clang-cl produces regular // output even with /Yc and /Yu and with /Zi. void ObjFile::initializeDependencies() { - if (!config->debug) + if (!Config->Debug) return; - bool isPCH = false; + bool IsPCH = false; - ArrayRef data = getDebugSection(".debug$P"); - if (!data.empty()) - isPCH = true; + ArrayRef Data = getDebugSection(".debug$P"); + if (!Data.empty()) + IsPCH = true; else - data = getDebugSection(".debug$T"); + Data = getDebugSection(".debug$T"); - if (data.empty()) + if (Data.empty()) return; - CVTypeArray types; - BinaryStreamReader reader(data, support::little); - cantFail(reader.readArray(types, reader.getLength())); + CVTypeArray Types; + BinaryStreamReader Reader(Data, support::little); + cantFail(Reader.readArray(Types, Reader.getLength())); - CVTypeArray::Iterator firstType = types.begin(); - if (firstType == types.end()) + CVTypeArray::Iterator FirstType = Types.begin(); + if (FirstType == Types.end()) return; - debugTypes.emplace(types); + DebugTypes.emplace(Types); - if (isPCH) { - debugTypesObj = makePrecompSource(this); + if (IsPCH) { + DebugTypesObj = makePrecompSource(this); return; } - if (firstType->kind() == LF_TYPESERVER2) { - TypeServer2Record ts = cantFail( - TypeDeserializer::deserializeAs(firstType->data())); - debugTypesObj = makeUseTypeServerSource(this, &ts); + if (FirstType->kind() == LF_TYPESERVER2) { + TypeServer2Record TS = cantFail( + TypeDeserializer::deserializeAs(FirstType->data())); + DebugTypesObj = makeUseTypeServerSource(this, &TS); return; } - if (firstType->kind() == LF_PRECOMP) { - PrecompRecord precomp = cantFail( - TypeDeserializer::deserializeAs(firstType->data())); - debugTypesObj = makeUsePrecompSource(this, &precomp); + if (FirstType->kind() == LF_PRECOMP) { + PrecompRecord Precomp = cantFail( + TypeDeserializer::deserializeAs(FirstType->data())); + DebugTypesObj = makeUsePrecompSource(this, &Precomp); return; } - debugTypesObj = makeTpiSource(this); + DebugTypesObj = makeTpiSource(this); } -StringRef ltrim1(StringRef s, const char *chars) { - if (!s.empty() && strchr(chars, s[0])) - return s.substr(1); - return s; +StringRef ltrim1(StringRef S, const char *Chars) { + if (!S.empty() && strchr(Chars, S[0])) + return S.substr(1); + return S; } void ImportFile::parse() { - const char *buf = mb.getBufferStart(); - const auto *hdr = reinterpret_cast(buf); + const char *Buf = MB.getBufferStart(); + const auto *Hdr = reinterpret_cast(Buf); // Check if the total size is valid. - if (mb.getBufferSize() != sizeof(*hdr) + hdr->SizeOfData) + if (MB.getBufferSize() != sizeof(*Hdr) + Hdr->SizeOfData) fatal("broken import library"); // Read names and create an __imp_ symbol. - StringRef name = saver.save(StringRef(buf + sizeof(*hdr))); - StringRef impName = saver.save("__imp_" + name); - const char *nameStart = buf + sizeof(coff_import_header) + name.size() + 1; - dllName = StringRef(nameStart); - StringRef extName; - switch (hdr->getNameType()) { + StringRef Name = Saver.save(StringRef(Buf + sizeof(*Hdr))); + StringRef ImpName = Saver.save("__imp_" + Name); + const char *NameStart = Buf + sizeof(coff_import_header) + Name.size() + 1; + DLLName = StringRef(NameStart); + StringRef ExtName; + switch (Hdr->getNameType()) { case IMPORT_ORDINAL: - extName = ""; + ExtName = ""; break; case IMPORT_NAME: - extName = name; + ExtName = Name; break; case IMPORT_NAME_NOPREFIX: - extName = ltrim1(name, "?@_"); + ExtName = ltrim1(Name, "?@_"); break; case IMPORT_NAME_UNDECORATE: - extName = ltrim1(name, "?@_"); - extName = extName.substr(0, extName.find('@')); + ExtName = ltrim1(Name, "?@_"); + ExtName = ExtName.substr(0, ExtName.find('@')); break; } - this->hdr = hdr; - externalName = extName; + this->Hdr = Hdr; + ExternalName = ExtName; - impSym = symtab->addImportData(impName, this); + ImpSym = Symtab->addImportData(ImpName, this); // If this was a duplicate, we logged an error but may continue; - // in this case, impSym is nullptr. - if (!impSym) + // in this case, ImpSym is nullptr. + if (!ImpSym) return; - if (hdr->getType() == llvm::COFF::IMPORT_CONST) - static_cast(symtab->addImportData(name, this)); + if (Hdr->getType() == llvm::COFF::IMPORT_CONST) + static_cast(Symtab->addImportData(Name, this)); // If type is function, we need to create a thunk which jump to an // address pointed by the __imp_ symbol. (This allows you to call // DLL functions just like regular non-DLL functions.) - if (hdr->getType() == llvm::COFF::IMPORT_CODE) - thunkSym = symtab->addImportThunk( - name, cast_or_null(impSym), hdr->Machine); + if (Hdr->getType() == llvm::COFF::IMPORT_CODE) + ThunkSym = Symtab->addImportThunk( + Name, cast_or_null(ImpSym), Hdr->Machine); } -BitcodeFile::BitcodeFile(MemoryBufferRef mb, StringRef archiveName, - uint64_t offsetInArchive, - std::vector &&symbols) - : InputFile(BitcodeKind, mb), symbols(std::move(symbols)) { - std::string path = mb.getBufferIdentifier().str(); - if (config->thinLTOIndexOnly) - path = replaceThinLTOSuffix(mb.getBufferIdentifier()); +BitcodeFile::BitcodeFile(MemoryBufferRef MB, StringRef ArchiveName, + uint64_t OffsetInArchive) + : InputFile(BitcodeKind, MB) { + std::string Path = MB.getBufferIdentifier().str(); // ThinLTO assumes that all MemoryBufferRefs given to it have a unique // name. If two archives define two members with the same name, this @@ -840,53 +790,53 @@ BitcodeFile::BitcodeFile(MemoryBufferRef mb, StringRef archiveName, // into consideration at LTO time (which very likely causes undefined // symbols later in the link stage). So we append file offset to make // filename unique. - MemoryBufferRef mbref( - mb.getBuffer(), - saver.save(archiveName + path + - (archiveName.empty() ? "" : utostr(offsetInArchive)))); + MemoryBufferRef MBRef( + MB.getBuffer(), + Saver.save(ArchiveName + Path + + (ArchiveName.empty() ? "" : utostr(OffsetInArchive)))); - obj = check(lto::InputFile::create(mbref)); + Obj = check(lto::InputFile::create(MBRef)); } void BitcodeFile::parse() { - std::vector> comdat(obj->getComdatTable().size()); - for (size_t i = 0; i != obj->getComdatTable().size(); ++i) + std::vector> Comdat(Obj->getComdatTable().size()); + for (size_t I = 0; I != Obj->getComdatTable().size(); ++I) // FIXME: lto::InputFile doesn't keep enough data to do correct comdat // selection handling. - comdat[i] = symtab->addComdat(this, saver.save(obj->getComdatTable()[i])); - for (const lto::InputFile::Symbol &objSym : obj->symbols()) { - StringRef symName = saver.save(objSym.getName()); - int comdatIndex = objSym.getComdatIndex(); - Symbol *sym; - if (objSym.isUndefined()) { - sym = symtab->addUndefined(symName, this, false); - } else if (objSym.isCommon()) { - sym = symtab->addCommon(this, symName, objSym.getCommonSize()); - } else if (objSym.isWeak() && objSym.isIndirect()) { + Comdat[I] = Symtab->addComdat(this, Saver.save(Obj->getComdatTable()[I])); + for (const lto::InputFile::Symbol &ObjSym : Obj->symbols()) { + StringRef SymName = Saver.save(ObjSym.getName()); + int ComdatIndex = ObjSym.getComdatIndex(); + Symbol *Sym; + if (ObjSym.isUndefined()) { + Sym = Symtab->addUndefined(SymName, this, false); + } else if (ObjSym.isCommon()) { + Sym = Symtab->addCommon(this, SymName, ObjSym.getCommonSize()); + } else if (ObjSym.isWeak() && ObjSym.isIndirect()) { // Weak external. - sym = symtab->addUndefined(symName, this, true); - std::string fallback = objSym.getCOFFWeakExternalFallback(); - Symbol *alias = symtab->addUndefined(saver.save(fallback)); - checkAndSetWeakAlias(symtab, this, sym, alias); - } else if (comdatIndex != -1) { - if (symName == obj->getComdatTable()[comdatIndex]) - sym = comdat[comdatIndex].first; - else if (comdat[comdatIndex].second) - sym = symtab->addRegular(this, symName); + Sym = Symtab->addUndefined(SymName, this, true); + std::string Fallback = ObjSym.getCOFFWeakExternalFallback(); + Symbol *Alias = Symtab->addUndefined(Saver.save(Fallback)); + checkAndSetWeakAlias(Symtab, this, Sym, Alias); + } else if (ComdatIndex != -1) { + if (SymName == Obj->getComdatTable()[ComdatIndex]) + Sym = Comdat[ComdatIndex].first; + else if (Comdat[ComdatIndex].second) + Sym = Symtab->addRegular(this, SymName); else - sym = symtab->addUndefined(symName, this, false); + Sym = Symtab->addUndefined(SymName, this, false); } else { - sym = symtab->addRegular(this, symName); + Sym = Symtab->addRegular(this, SymName); } - symbols.push_back(sym); - if (objSym.isUsed()) - config->gcroot.push_back(sym); + Symbols.push_back(Sym); + if (ObjSym.isUsed()) + Config->GCRoot.push_back(Sym); } - directives = obj->getCOFFLinkerOpts(); + Directives = Obj->getCOFFLinkerOpts(); } MachineTypes BitcodeFile::getMachineType() { - switch (Triple(obj->getTargetTriple()).getArch()) { + switch (Triple(Obj->getTargetTriple()).getArch()) { case Triple::x86_64: return AMD64; case Triple::x86: @@ -899,31 +849,22 @@ MachineTypes BitcodeFile::getMachineType() { return IMAGE_FILE_MACHINE_UNKNOWN; } } - -std::string replaceThinLTOSuffix(StringRef path) { - StringRef suffix = config->thinLTOObjectSuffixReplace.first; - StringRef repl = config->thinLTOObjectSuffixReplace.second; - - if (path.consume_back(suffix)) - return (path + repl).str(); - return path; -} } // namespace coff } // namespace lld // Returns the last element of a path, which is supposed to be a filename. -static StringRef getBasename(StringRef path) { - return sys::path::filename(path, sys::path::Style::windows); +static StringRef getBasename(StringRef Path) { + return sys::path::filename(Path, sys::path::Style::windows); } // Returns a string in the format of "foo.obj" or "foo.obj(bar.lib)". -std::string lld::toString(const coff::InputFile *file) { - if (!file) +std::string lld::toString(const coff::InputFile *File) { + if (!File) return ""; - if (file->parentName.empty() || file->kind() == coff::InputFile::ImportKind) - return file->getName(); + if (File->ParentName.empty() || File->kind() == coff::InputFile::ImportKind) + return File->getName(); - return (getBasename(file->parentName) + "(" + getBasename(file->getName()) + + return (getBasename(File->ParentName) + "(" + getBasename(File->getName()) + ")") .str(); } diff --git a/lld/COFF/InputFiles.h b/lld/COFF/InputFiles.h index 108a4caacd6950..22017f78013d62 100644 --- a/lld/COFF/InputFiles.h +++ b/lld/COFF/InputFiles.h @@ -14,7 +14,6 @@ #include "llvm/ADT/ArrayRef.h" #include "llvm/ADT/DenseMap.h" #include "llvm/ADT/DenseSet.h" -#include "llvm/BinaryFormat/Magic.h" #include "llvm/DebugInfo/CodeView/TypeRecord.h" #include "llvm/LTO/LTO.h" #include "llvm/Object/Archive.h" @@ -33,7 +32,7 @@ class DbiModuleDescriptorBuilder; namespace lld { namespace coff { -std::vector getArchiveMembers(llvm::object::Archive *file); +std::vector getArchiveMembers(llvm::object::Archive *File); using llvm::COFF::IMAGE_FILE_MACHINE_UNKNOWN; using llvm::COFF::MachineTypes; @@ -48,6 +47,7 @@ class Defined; class DefinedImportData; class DefinedImportThunk; class DefinedRegular; +class Lazy; class SectionChunk; class Symbol; class Undefined; @@ -56,18 +56,12 @@ class TpiSource; // The root class of input files. class InputFile { public: - enum Kind { - ArchiveKind, - ObjectKind, - LazyObjectKind, - ImportKind, - BitcodeKind - }; - Kind kind() const { return fileKind; } + enum Kind { ArchiveKind, ObjectKind, ImportKind, BitcodeKind }; + Kind kind() const { return FileKind; } virtual ~InputFile() {} // Returns the filename. - StringRef getName() const { return mb.getBufferIdentifier(); } + StringRef getName() const { return MB.getBufferIdentifier(); } // Reads a file (the constructor doesn't do that). virtual void parse() = 0; @@ -75,137 +69,118 @@ class InputFile { // Returns the CPU type this file was compiled to. virtual MachineTypes getMachineType() { return IMAGE_FILE_MACHINE_UNKNOWN; } - MemoryBufferRef mb; + MemoryBufferRef MB; // An archive file name if this file is created from an archive. - StringRef parentName; + StringRef ParentName; // Returns .drectve section contents if exist. - StringRef getDirectives() { return directives; } + StringRef getDirectives() { return Directives; } protected: - InputFile(Kind k, MemoryBufferRef m) : mb(m), fileKind(k) {} + InputFile(Kind K, MemoryBufferRef M) : MB(M), FileKind(K) {} - StringRef directives; + StringRef Directives; private: - const Kind fileKind; + const Kind FileKind; }; // .lib or .a file. class ArchiveFile : public InputFile { public: - explicit ArchiveFile(MemoryBufferRef m); - static bool classof(const InputFile *f) { return f->kind() == ArchiveKind; } + explicit ArchiveFile(MemoryBufferRef M); + static bool classof(const InputFile *F) { return F->kind() == ArchiveKind; } void parse() override; // Enqueues an archive member load for the given symbol. If we've already // enqueued a load for the same archive member, this function does nothing, // which ensures that we don't load the same member more than once. - void addMember(const Archive::Symbol &sym); + void addMember(const Archive::Symbol *Sym); private: - std::unique_ptr file; - llvm::DenseSet seen; -}; - -// .obj or .o file between -start-lib and -end-lib. -class LazyObjFile : public InputFile { -public: - explicit LazyObjFile(MemoryBufferRef m) : InputFile(LazyObjectKind, m) {} - static bool classof(const InputFile *f) { - return f->kind() == LazyObjectKind; - } - // Makes this object file part of the link. - void fetch(); - // Adds the symbols in this file to the symbol table as LazyObject symbols. - void parse() override; - -private: - std::vector symbols; + std::unique_ptr File; + llvm::DenseSet Seen; }; // .obj or .o file. This may be a member of an archive file. class ObjFile : public InputFile { public: - explicit ObjFile(MemoryBufferRef m) : InputFile(ObjectKind, m) {} - explicit ObjFile(MemoryBufferRef m, std::vector &&symbols) - : InputFile(ObjectKind, m), symbols(std::move(symbols)) {} - static bool classof(const InputFile *f) { return f->kind() == ObjectKind; } + explicit ObjFile(MemoryBufferRef M) : InputFile(ObjectKind, M) {} + static bool classof(const InputFile *F) { return F->kind() == ObjectKind; } void parse() override; MachineTypes getMachineType() override; - ArrayRef getChunks() { return chunks; } - ArrayRef getDebugChunks() { return debugChunks; } - ArrayRef getSXDataChunks() { return sXDataChunks; } - ArrayRef getGuardFidChunks() { return guardFidChunks; } - ArrayRef getGuardLJmpChunks() { return guardLJmpChunks; } - ArrayRef getSymbols() { return symbols; } + ArrayRef getChunks() { return Chunks; } + ArrayRef getDebugChunks() { return DebugChunks; } + ArrayRef getSXDataChunks() { return SXDataChunks; } + ArrayRef getGuardFidChunks() { return GuardFidChunks; } + ArrayRef getGuardLJmpChunks() { return GuardLJmpChunks; } + ArrayRef getSymbols() { return Symbols; } - ArrayRef getDebugSection(StringRef secName); + ArrayRef getDebugSection(StringRef SecName); - // Returns a Symbol object for the symbolIndex'th symbol in the + // Returns a Symbol object for the SymbolIndex'th symbol in the // underlying object file. - Symbol *getSymbol(uint32_t symbolIndex) { - return symbols[symbolIndex]; + Symbol *getSymbol(uint32_t SymbolIndex) { + return Symbols[SymbolIndex]; } // Returns the underlying COFF file. - COFFObjectFile *getCOFFObj() { return coffObj.get(); } + COFFObjectFile *getCOFFObj() { return COFFObj.get(); } // Add a symbol for a range extension thunk. Return the new symbol table // index. This index can be used to modify a relocation. - uint32_t addRangeThunkSymbol(Symbol *thunk) { - symbols.push_back(thunk); - return symbols.size() - 1; + uint32_t addRangeThunkSymbol(Symbol *Thunk) { + Symbols.push_back(Thunk); + return Symbols.size() - 1; } - void includeResourceChunks(); - - bool isResourceObjFile() const { return !resourceChunks.empty(); } - - static std::vector instances; + static std::vector Instances; // Flags in the absolute @feat.00 symbol if it is present. These usually // indicate if an object was compiled with certain security features enabled // like stack guard, safeseh, /guard:cf, or other things. - uint32_t feat00Flags = 0; + uint32_t Feat00Flags = 0; // True if this object file is compatible with SEH. COFF-specific and // x86-only. COFF spec 5.10.1. The .sxdata section. - bool hasSafeSEH() { return feat00Flags & 0x1; } + bool hasSafeSEH() { return Feat00Flags & 0x1; } // True if this file was compiled with /guard:cf. - bool hasGuardCF() { return feat00Flags & 0x800; } + bool hasGuardCF() { return Feat00Flags & 0x800; } // Pointer to the PDB module descriptor builder. Various debug info records // will reference object files by "module index", which is here. Things like // source files and section contributions are also recorded here. Will be null // if we are not producing a PDB. - llvm::pdb::DbiModuleDescriptorBuilder *moduleDBI = nullptr; + llvm::pdb::DbiModuleDescriptorBuilder *ModuleDBI = nullptr; - const coff_section *addrsigSec = nullptr; + const coff_section *AddrsigSec = nullptr; // When using Microsoft precompiled headers, this is the PCH's key. // The same key is used by both the precompiled object, and objects using the // precompiled object. Any difference indicates out-of-date objects. - llvm::Optional pchSignature; + llvm::Optional PCHSignature; + + // Whether this is an object file created from .res files. + bool IsResourceObjFile = false; // Whether this file was compiled with /hotpatch. - bool hotPatchable = false; + bool HotPatchable = false; // Whether the object was already merged into the final PDB. - bool mergedIntoPDB = false; + bool MergedIntoPDB = false; // If the OBJ has a .debug$T stream, this tells how it will be handled. - TpiSource *debugTypesObj = nullptr; + TpiSource *DebugTypesObj = nullptr; // The .debug$T stream if there's one. - llvm::Optional debugTypes; + llvm::Optional DebugTypes; private: - const coff_section* getSection(uint32_t i); - const coff_section *getSection(COFFSymbolRef sym) { - return getSection(sym.getSectionNumber()); + const coff_section* getSection(uint32_t I); + const coff_section *getSection(COFFSymbolRef Sym) { + return getSection(Sym.getSectionNumber()); } void initializeChunks(); @@ -214,26 +189,26 @@ class ObjFile : public InputFile { void initializeDependencies(); SectionChunk * - readSection(uint32_t sectionNumber, - const llvm::object::coff_aux_section_definition *def, - StringRef leaderName); + readSection(uint32_t SectionNumber, + const llvm::object::coff_aux_section_definition *Def, + StringRef LeaderName); void readAssociativeDefinition( - COFFSymbolRef coffSym, - const llvm::object::coff_aux_section_definition *def); + COFFSymbolRef COFFSym, + const llvm::object::coff_aux_section_definition *Def); void readAssociativeDefinition( - COFFSymbolRef coffSym, - const llvm::object::coff_aux_section_definition *def, - uint32_t parentSection); + COFFSymbolRef COFFSym, + const llvm::object::coff_aux_section_definition *Def, + uint32_t ParentSection); void recordPrevailingSymbolForMingw( - COFFSymbolRef coffSym, - llvm::DenseMap &prevailingSectionMap); + COFFSymbolRef COFFSym, + llvm::DenseMap &PrevailingSectionMap); void maybeAssociateSEHForMingw( - COFFSymbolRef sym, const llvm::object::coff_aux_section_definition *def, - const llvm::DenseMap &prevailingSectionMap); + COFFSymbolRef Sym, const llvm::object::coff_aux_section_definition *Def, + const llvm::DenseMap &PrevailingSectionMap); // Given a new symbol Sym with comdat selection Selection, if the new // symbol is not (yet) Prevailing and the existing comdat leader set to @@ -241,50 +216,48 @@ class ObjFile : public InputFile { // match the existing symbol and its selection. If either old or new // symbol have selection IMAGE_COMDAT_SELECT_LARGEST, Sym might replace // the existing leader. In that case, Prevailing is set to true. - void handleComdatSelection(COFFSymbolRef sym, - llvm::COFF::COMDATType &selection, - bool &prevailing, DefinedRegular *leader); + void handleComdatSelection(COFFSymbolRef Sym, + llvm::COFF::COMDATType &Selection, + bool &Prevailing, DefinedRegular *Leader); llvm::Optional - createDefined(COFFSymbolRef sym, + createDefined(COFFSymbolRef Sym, std::vector - &comdatDefs, - bool &prevailingComdat); - Symbol *createRegular(COFFSymbolRef sym); - Symbol *createUndefined(COFFSymbolRef sym); + &ComdatDefs, + bool &PrevailingComdat); + Symbol *createRegular(COFFSymbolRef Sym); + Symbol *createUndefined(COFFSymbolRef Sym); - std::unique_ptr coffObj; + std::unique_ptr COFFObj; // List of all chunks defined by this file. This includes both section // chunks and non-section chunks for common symbols. - std::vector chunks; - - std::vector resourceChunks; + std::vector Chunks; // CodeView debug info sections. - std::vector debugChunks; + std::vector DebugChunks; // Chunks containing symbol table indices of exception handlers. Only used for // 32-bit x86. - std::vector sXDataChunks; + std::vector SXDataChunks; // Chunks containing symbol table indices of address taken symbols and longjmp // targets. These are not linked into the final binary when /guard:cf is set. - std::vector guardFidChunks; - std::vector guardLJmpChunks; + std::vector GuardFidChunks; + std::vector GuardLJmpChunks; // This vector contains the same chunks as Chunks, but they are // indexed such that you can get a SectionChunk by section index. // Nonexistent section indices are filled with null pointers. // (Because section number is 1-based, the first slot is always a // null pointer.) - std::vector sparseChunks; + std::vector SparseChunks; // This vector contains a list of all symbols defined or referenced by this // file. They are indexed such that you can get a Symbol by symbol // index. Nonexistent indices (which are occupied by auxiliary // symbols in the real symbol table) are filled with null pointers. - std::vector symbols; + std::vector Symbols; }; // This type represents import library members that contain DLL names @@ -292,23 +265,23 @@ class ObjFile : public InputFile { // for details about the format. class ImportFile : public InputFile { public: - explicit ImportFile(MemoryBufferRef m) : InputFile(ImportKind, m) {} + explicit ImportFile(MemoryBufferRef M) : InputFile(ImportKind, M) {} - static bool classof(const InputFile *f) { return f->kind() == ImportKind; } + static bool classof(const InputFile *F) { return F->kind() == ImportKind; } - static std::vector instances; + static std::vector Instances; - Symbol *impSym = nullptr; - Symbol *thunkSym = nullptr; - std::string dllName; + Symbol *ImpSym = nullptr; + Symbol *ThunkSym = nullptr; + std::string DLLName; private: void parse() override; public: - StringRef externalName; - const coff_import_header *hdr; - Chunk *location = nullptr; + StringRef ExternalName; + const coff_import_header *Hdr; + Chunk *Location = nullptr; // We want to eliminate dllimported symbols if no one actually refers them. // These "Live" bits are used to keep track of which import library members @@ -318,39 +291,29 @@ class ImportFile : public InputFile { // symbols provided by this import library member. We also track whether the // imported symbol is used separately from whether the thunk is used in order // to avoid creating unnecessary thunks. - bool live = !config->doGC; - bool thunkLive = !config->doGC; + bool Live = !Config->DoGC; + bool ThunkLive = !Config->DoGC; }; // Used for LTO. class BitcodeFile : public InputFile { public: - BitcodeFile(MemoryBufferRef mb, StringRef archiveName, - uint64_t offsetInArchive) - : BitcodeFile(mb, archiveName, offsetInArchive, {}) {} - explicit BitcodeFile(MemoryBufferRef m, StringRef archiveName, - uint64_t offsetInArchive, - std::vector &&symbols); - static bool classof(const InputFile *f) { return f->kind() == BitcodeKind; } - ArrayRef getSymbols() { return symbols; } + BitcodeFile(MemoryBufferRef MB, StringRef ArchiveName, + uint64_t OffsetInArchive); + static bool classof(const InputFile *F) { return F->kind() == BitcodeKind; } + ArrayRef getSymbols() { return Symbols; } MachineTypes getMachineType() override; - static std::vector instances; - std::unique_ptr obj; + static std::vector Instances; + std::unique_ptr Obj; private: void parse() override; - std::vector symbols; + std::vector Symbols; }; - -inline bool isBitcode(MemoryBufferRef mb) { - return identify_magic(mb.getBuffer()) == llvm::file_magic::bitcode; -} - -std::string replaceThinLTOSuffix(StringRef path); } // namespace coff -std::string toString(const coff::InputFile *file); +std::string toString(const coff::InputFile *File); } // namespace lld #endif diff --git a/lld/COFF/LTO.cpp b/lld/COFF/LTO.cpp index 7aa3b17e24d5c3..bfbfc24c7675f6 100644 --- a/lld/COFF/LTO.cpp +++ b/lld/COFF/LTO.cpp @@ -18,7 +18,6 @@ #include "llvm/ADT/SmallString.h" #include "llvm/ADT/StringRef.h" #include "llvm/ADT/Twine.h" -#include "llvm/Bitcode/BitcodeWriter.h" #include "llvm/IR/DiagnosticPrinter.h" #include "llvm/LTO/Caching.h" #include "llvm/LTO/Config.h" @@ -42,167 +41,113 @@ using namespace llvm::object; using namespace lld; using namespace lld::coff; -// Creates an empty file to and returns a raw_fd_ostream to write to it. -static std::unique_ptr openFile(StringRef file) { - std::error_code ec; - auto ret = - std::make_unique(file, ec, sys::fs::OpenFlags::OF_None); - if (ec) { - error("cannot open " + file + ": " + ec.message()); - return nullptr; - } - return ret; -} - -static std::string getThinLTOOutputFile(StringRef path) { - return lto::getThinLTOOutputFile(path, - config->thinLTOPrefixReplace.first, - config->thinLTOPrefixReplace.second); -} - -static lto::Config createConfig() { - lto::Config c; - c.Options = initTargetOptionsFromCodeGenFlags(); +static std::unique_ptr createLTO() { + lto::Config C; + C.Options = initTargetOptionsFromCodeGenFlags(); // Always emit a section per function/datum with LTO. LLVM LTO should get most // of the benefit of linker GC, but there are still opportunities for ICF. - c.Options.FunctionSections = true; - c.Options.DataSections = true; + C.Options.FunctionSections = true; + C.Options.DataSections = true; // Use static reloc model on 32-bit x86 because it usually results in more // compact code, and because there are also known code generation bugs when // using the PIC model (see PR34306). - if (config->machine == COFF::IMAGE_FILE_MACHINE_I386) - c.RelocModel = Reloc::Static; + if (Config->Machine == COFF::IMAGE_FILE_MACHINE_I386) + C.RelocModel = Reloc::Static; else - c.RelocModel = Reloc::PIC_; - c.DisableVerify = true; - c.DiagHandler = diagnosticHandler; - c.OptLevel = config->ltoo; - c.CPU = getCPUStr(); - c.MAttrs = getMAttrs(); - c.CGOptLevel = args::getCGOptLevel(config->ltoo); - - if (config->saveTemps) - checkError(c.addSaveTemps(std::string(config->outputFile) + ".", + C.RelocModel = Reloc::PIC_; + C.DisableVerify = true; + C.DiagHandler = diagnosticHandler; + C.OptLevel = Config->LTOO; + C.CPU = getCPUStr(); + C.MAttrs = getMAttrs(); + C.CGOptLevel = args::getCGOptLevel(Config->LTOO); + + if (Config->SaveTemps) + checkError(C.addSaveTemps(std::string(Config->OutputFile) + ".", /*UseInputModulePath*/ true)); - return c; + lto::ThinBackend Backend; + if (Config->ThinLTOJobs != 0) + Backend = lto::createInProcessThinBackend(Config->ThinLTOJobs); + return llvm::make_unique(std::move(C), Backend, + Config->LTOPartitions); } -BitcodeCompiler::BitcodeCompiler() { - // Initialize indexFile. - if (!config->thinLTOIndexOnlyArg.empty()) - indexFile = openFile(config->thinLTOIndexOnlyArg); - - // Initialize ltoObj. - lto::ThinBackend backend; - if (config->thinLTOIndexOnly) { - auto OnIndexWrite = [&](StringRef S) { thinIndices.erase(S); }; - backend = lto::createWriteIndexesThinBackend( - config->thinLTOPrefixReplace.first, config->thinLTOPrefixReplace.second, - config->thinLTOEmitImportsFiles, indexFile.get(), OnIndexWrite); - } else if (config->thinLTOJobs != 0) { - backend = lto::createInProcessThinBackend(config->thinLTOJobs); - } - - ltoObj = std::make_unique(createConfig(), backend, - config->ltoPartitions); -} +BitcodeCompiler::BitcodeCompiler() : LTOObj(createLTO()) {} BitcodeCompiler::~BitcodeCompiler() = default; -static void undefine(Symbol *s) { replaceSymbol(s, s->getName()); } - -void BitcodeCompiler::add(BitcodeFile &f) { - lto::InputFile &obj = *f.obj; - unsigned symNum = 0; - std::vector symBodies = f.getSymbols(); - std::vector resols(symBodies.size()); +static void undefine(Symbol *S) { replaceSymbol(S, S->getName()); } - if (config->thinLTOIndexOnly) - thinIndices.insert(obj.getName()); +void BitcodeCompiler::add(BitcodeFile &F) { + lto::InputFile &Obj = *F.Obj; + unsigned SymNum = 0; + std::vector SymBodies = F.getSymbols(); + std::vector Resols(SymBodies.size()); // Provide a resolution to the LTO API for each symbol. - for (const lto::InputFile::Symbol &objSym : obj.symbols()) { - Symbol *sym = symBodies[symNum]; - lto::SymbolResolution &r = resols[symNum]; - ++symNum; + for (const lto::InputFile::Symbol &ObjSym : Obj.symbols()) { + Symbol *Sym = SymBodies[SymNum]; + lto::SymbolResolution &R = Resols[SymNum]; + ++SymNum; // Ideally we shouldn't check for SF_Undefined but currently IRObjectFile // reports two symbols for module ASM defined. Without this check, lld // flags an undefined in IR with a definition in ASM as prevailing. // Once IRObjectFile is fixed to report only one symbol this hack can // be removed. - r.Prevailing = !objSym.isUndefined() && sym->getFile() == &f; - r.VisibleToRegularObj = sym->isUsedInRegularObj; - if (r.Prevailing) - undefine(sym); + R.Prevailing = !ObjSym.isUndefined() && Sym->getFile() == &F; + R.VisibleToRegularObj = Sym->IsUsedInRegularObj; + if (R.Prevailing) + undefine(Sym); } - checkError(ltoObj->add(std::move(f.obj), resols)); + checkError(LTOObj->add(std::move(F.Obj), Resols)); } // Merge all the bitcode files we have seen, codegen the result // and return the resulting objects. std::vector BitcodeCompiler::compile() { - unsigned maxTasks = ltoObj->getMaxTasks(); - buf.resize(maxTasks); - files.resize(maxTasks); + unsigned MaxTasks = LTOObj->getMaxTasks(); + Buf.resize(MaxTasks); + Files.resize(MaxTasks); // The /lldltocache option specifies the path to a directory in which to cache // native object files for ThinLTO incremental builds. If a path was // specified, configure LTO to use it as the cache directory. - lto::NativeObjectCache cache; - if (!config->ltoCache.empty()) - cache = check(lto::localCache( - config->ltoCache, [&](size_t task, std::unique_ptr mb) { - files[task] = std::move(mb); + lto::NativeObjectCache Cache; + if (!Config->LTOCache.empty()) + Cache = check(lto::localCache( + Config->LTOCache, [&](size_t Task, std::unique_ptr MB) { + Files[Task] = std::move(MB); })); - checkError(ltoObj->run( - [&](size_t task) { - return std::make_unique( - std::make_unique(buf[task])); + checkError(LTOObj->run( + [&](size_t Task) { + return llvm::make_unique( + llvm::make_unique(Buf[Task])); }, - cache)); - - // Emit empty index files for non-indexed files - for (StringRef s : thinIndices) { - std::string path = getThinLTOOutputFile(s); - openFile(path + ".thinlto.bc"); - if (config->thinLTOEmitImportsFiles) - openFile(path + ".imports"); - } - - // ThinLTO with index only option is required to generate only the index - // files. After that, we exit from linker and ThinLTO backend runs in a - // distributed environment. - if (config->thinLTOIndexOnly) { - if (!config->ltoObjPath.empty()) - saveBuffer(buf[0], config->ltoObjPath); - if (indexFile) - indexFile->close(); - return {}; - } + Cache)); - if (!config->ltoCache.empty()) - pruneCache(config->ltoCache, config->ltoCachePolicy); + if (!Config->LTOCache.empty()) + pruneCache(Config->LTOCache, Config->LTOCachePolicy); - std::vector ret; - for (unsigned i = 0; i != maxTasks; ++i) { - if (buf[i].empty()) + std::vector Ret; + for (unsigned I = 0; I != MaxTasks; ++I) { + if (Buf[I].empty()) continue; - if (config->saveTemps) { - if (i == 0) - saveBuffer(buf[i], config->outputFile + ".lto.obj"); + if (Config->SaveTemps) { + if (I == 0) + saveBuffer(Buf[I], Config->OutputFile + ".lto.obj"); else - saveBuffer(buf[i], config->outputFile + Twine(i) + ".lto.obj"); + saveBuffer(Buf[I], Config->OutputFile + Twine(I) + ".lto.obj"); } - ret.emplace_back(buf[i].data(), buf[i].size()); + Ret.emplace_back(Buf[I].data(), Buf[I].size()); } - for (std::unique_ptr &file : files) - if (file) - ret.push_back(file->getBuffer()); + for (std::unique_ptr &File : Files) + if (File) + Ret.push_back(File->getBuffer()); - return ret; + return Ret; } diff --git a/lld/COFF/LTO.h b/lld/COFF/LTO.h index 2a0cfa061c9516..222945c81de54c 100644 --- a/lld/COFF/LTO.h +++ b/lld/COFF/LTO.h @@ -21,9 +21,7 @@ #define LLD_COFF_LTO_H #include "lld/Common/LLVM.h" -#include "llvm/ADT/DenseSet.h" #include "llvm/ADT/SmallString.h" -#include "llvm/Support/raw_ostream.h" #include #include @@ -44,15 +42,13 @@ class BitcodeCompiler { BitcodeCompiler(); ~BitcodeCompiler(); - void add(BitcodeFile &f); + void add(BitcodeFile &F); std::vector compile(); private: - std::unique_ptr ltoObj; - std::vector> buf; - std::vector> files; - std::unique_ptr indexFile; - llvm::DenseSet thinIndices; + std::unique_ptr LTOObj; + std::vector> Buf; + std::vector> Files; }; } } diff --git a/lld/COFF/MapFile.cpp b/lld/COFF/MapFile.cpp index 70017d34c8bcf9..aade7ad5229adc 100644 --- a/lld/COFF/MapFile.cpp +++ b/lld/COFF/MapFile.cpp @@ -35,90 +35,90 @@ using namespace lld::coff; using SymbolMapTy = DenseMap>; -static constexpr char indent8[] = " "; // 8 spaces -static constexpr char indent16[] = " "; // 16 spaces +static const std::string Indent8 = " "; // 8 spaces +static const std::string Indent16 = " "; // 16 spaces // Print out the first three columns of a line. -static void writeHeader(raw_ostream &os, uint64_t addr, uint64_t size, - uint64_t align) { - os << format("%08llx %08llx %5lld ", addr, size, align); +static void writeHeader(raw_ostream &OS, uint64_t Addr, uint64_t Size, + uint64_t Align) { + OS << format("%08llx %08llx %5lld ", Addr, Size, Align); } // Returns a list of all symbols that we want to print out. static std::vector getSymbols() { - std::vector v; - for (ObjFile *file : ObjFile::instances) - for (Symbol *b : file->getSymbols()) - if (auto *sym = dyn_cast_or_null(b)) - if (sym && !sym->getCOFFSymbol().isSectionDefinition()) - v.push_back(sym); - return v; + std::vector V; + for (ObjFile *File : ObjFile::Instances) + for (Symbol *B : File->getSymbols()) + if (auto *Sym = dyn_cast_or_null(B)) + if (Sym && !Sym->getCOFFSymbol().isSectionDefinition()) + V.push_back(Sym); + return V; } // Returns a map from sections to their symbols. -static SymbolMapTy getSectionSyms(ArrayRef syms) { - SymbolMapTy ret; - for (DefinedRegular *s : syms) - ret[s->getChunk()].push_back(s); +static SymbolMapTy getSectionSyms(ArrayRef Syms) { + SymbolMapTy Ret; + for (DefinedRegular *S : Syms) + Ret[S->getChunk()].push_back(S); // Sort symbols by address. - for (auto &it : ret) { - SmallVectorImpl &v = it.second; - std::sort(v.begin(), v.end(), [](DefinedRegular *a, DefinedRegular *b) { - return a->getRVA() < b->getRVA(); + for (auto &It : Ret) { + SmallVectorImpl &V = It.second; + std::sort(V.begin(), V.end(), [](DefinedRegular *A, DefinedRegular *B) { + return A->getRVA() < B->getRVA(); }); } - return ret; + return Ret; } // Construct a map from symbols to their stringified representations. static DenseMap -getSymbolStrings(ArrayRef syms) { - std::vector str(syms.size()); - parallelForEachN((size_t)0, syms.size(), [&](size_t i) { - raw_string_ostream os(str[i]); - writeHeader(os, syms[i]->getRVA(), 0, 0); - os << indent16 << toString(*syms[i]); +getSymbolStrings(ArrayRef Syms) { + std::vector Str(Syms.size()); + parallelForEachN((size_t)0, Syms.size(), [&](size_t I) { + raw_string_ostream OS(Str[I]); + writeHeader(OS, Syms[I]->getRVA(), 0, 0); + OS << Indent16 << toString(*Syms[I]); }); - DenseMap ret; - for (size_t i = 0, e = syms.size(); i < e; ++i) - ret[syms[i]] = std::move(str[i]); - return ret; + DenseMap Ret; + for (size_t I = 0, E = Syms.size(); I < E; ++I) + Ret[Syms[I]] = std::move(Str[I]); + return Ret; } -void coff::writeMapFile(ArrayRef outputSections) { - if (config->mapFile.empty()) +void coff::writeMapFile(ArrayRef OutputSections) { + if (Config->MapFile.empty()) return; - std::error_code ec; - raw_fd_ostream os(config->mapFile, ec, sys::fs::OF_None); - if (ec) - fatal("cannot open " + config->mapFile + ": " + ec.message()); + std::error_code EC; + raw_fd_ostream OS(Config->MapFile, EC, sys::fs::F_None); + if (EC) + fatal("cannot open " + Config->MapFile + ": " + EC.message()); // Collect symbol info that we want to print out. - std::vector syms = getSymbols(); - SymbolMapTy sectionSyms = getSectionSyms(syms); - DenseMap symStr = getSymbolStrings(syms); + std::vector Syms = getSymbols(); + SymbolMapTy SectionSyms = getSectionSyms(Syms); + DenseMap SymStr = getSymbolStrings(Syms); // Print out the header line. - os << "Address Size Align Out In Symbol\n"; + OS << "Address Size Align Out In Symbol\n"; // Print out file contents. - for (OutputSection *sec : outputSections) { - writeHeader(os, sec->getRVA(), sec->getVirtualSize(), /*align=*/pageSize); - os << sec->name << '\n'; + for (OutputSection *Sec : OutputSections) { + writeHeader(OS, Sec->getRVA(), Sec->getVirtualSize(), /*Align=*/PageSize); + OS << Sec->Name << '\n'; - for (Chunk *c : sec->chunks) { - auto *sc = dyn_cast(c); - if (!sc) + for (Chunk *C : Sec->Chunks) { + auto *SC = dyn_cast(C); + if (!SC) continue; - writeHeader(os, sc->getRVA(), sc->getSize(), sc->getAlignment()); - os << indent8 << sc->file->getName() << ":(" << sc->getSectionName() + writeHeader(OS, SC->getRVA(), SC->getSize(), SC->getAlignment()); + OS << Indent8 << SC->File->getName() << ":(" << SC->getSectionName() << ")\n"; - for (DefinedRegular *sym : sectionSyms[sc]) - os << symStr[sym] << '\n'; + for (DefinedRegular *Sym : SectionSyms[SC]) + OS << SymStr[Sym] << '\n'; } } } diff --git a/lld/COFF/MapFile.h b/lld/COFF/MapFile.h index 2bf01bd072856b..f702dc6686d3e2 100644 --- a/lld/COFF/MapFile.h +++ b/lld/COFF/MapFile.h @@ -14,7 +14,7 @@ namespace lld { namespace coff { class OutputSection; -void writeMapFile(llvm::ArrayRef outputSections); +void writeMapFile(llvm::ArrayRef OutputSections); } } diff --git a/lld/COFF/MarkLive.cpp b/lld/COFF/MarkLive.cpp index 6d34cb864e3c3f..50e41ba1506ede 100644 --- a/lld/COFF/MarkLive.cpp +++ b/lld/COFF/MarkLive.cpp @@ -15,57 +15,57 @@ namespace lld { namespace coff { -static Timer gctimer("GC", Timer::root()); +static Timer GCTimer("GC", Timer::root()); // Set live bit on for each reachable chunk. Unmarked (unreachable) // COMDAT chunks will be ignored by Writer, so they will be excluded // from the final output. -void markLive(ArrayRef chunks) { - ScopedTimer t(gctimer); +void markLive(ArrayRef Chunks) { + ScopedTimer T(GCTimer); // We build up a worklist of sections which have been marked as live. We only // push into the worklist when we discover an unmarked section, and we mark // as we push, so sections never appear twice in the list. - SmallVector worklist; + SmallVector Worklist; // COMDAT section chunks are dead by default. Add non-COMDAT chunks. - for (Chunk *c : chunks) - if (auto *sc = dyn_cast(c)) - if (sc->live) - worklist.push_back(sc); + for (Chunk *C : Chunks) + if (auto *SC = dyn_cast(C)) + if (SC->Live) + Worklist.push_back(SC); - auto enqueue = [&](SectionChunk *c) { - if (c->live) + auto Enqueue = [&](SectionChunk *C) { + if (C->Live) return; - c->live = true; - worklist.push_back(c); + C->Live = true; + Worklist.push_back(C); }; - auto addSym = [&](Symbol *b) { - if (auto *sym = dyn_cast(b)) - enqueue(sym->getChunk()); - else if (auto *sym = dyn_cast(b)) - sym->file->live = true; - else if (auto *sym = dyn_cast(b)) - sym->wrappedSym->file->live = sym->wrappedSym->file->thunkLive = true; + auto AddSym = [&](Symbol *B) { + if (auto *Sym = dyn_cast(B)) + Enqueue(Sym->getChunk()); + else if (auto *Sym = dyn_cast(B)) + Sym->File->Live = true; + else if (auto *Sym = dyn_cast(B)) + Sym->WrappedSym->File->Live = Sym->WrappedSym->File->ThunkLive = true; }; // Add GC root chunks. - for (Symbol *b : config->gcroot) - addSym(b); + for (Symbol *B : Config->GCRoot) + AddSym(B); - while (!worklist.empty()) { - SectionChunk *sc = worklist.pop_back_val(); - assert(sc->live && "We mark as live when pushing onto the worklist!"); + while (!Worklist.empty()) { + SectionChunk *SC = Worklist.pop_back_val(); + assert(SC->Live && "We mark as live when pushing onto the worklist!"); // Mark all symbols listed in the relocation table for this section. - for (Symbol *b : sc->symbols()) - if (b) - addSym(b); + for (Symbol *B : SC->symbols()) + if (B) + AddSym(B); // Mark associative sections if any. - for (SectionChunk &c : sc->children()) - enqueue(&c); + for (SectionChunk &C : SC->children()) + Enqueue(&C); } } diff --git a/lld/COFF/MarkLive.h b/lld/COFF/MarkLive.h index e4e4c31c7c796a..9c584dc19e2bb9 100644 --- a/lld/COFF/MarkLive.h +++ b/lld/COFF/MarkLive.h @@ -17,7 +17,7 @@ namespace coff { class Chunk; -void markLive(ArrayRef chunks); +void markLive(ArrayRef Chunks); } // namespace coff } // namespace lld diff --git a/lld/COFF/MinGW.cpp b/lld/COFF/MinGW.cpp index a22e609148a0df..9d3815d2e6e9de 100644 --- a/lld/COFF/MinGW.cpp +++ b/lld/COFF/MinGW.cpp @@ -19,7 +19,7 @@ using namespace llvm; using namespace llvm::COFF; AutoExporter::AutoExporter() { - excludeLibs = { + ExcludeLibs = { "libgcc", "libgcc_s", "libstdc++", @@ -41,12 +41,12 @@ AutoExporter::AutoExporter() { "libucrtbase", }; - excludeObjects = { + ExcludeObjects = { "crt0.o", "crt1.o", "crt1u.o", "crt2.o", "crt2u.o", "dllcrt1.o", "dllcrt2.o", "gcrt0.o", "gcrt1.o", "gcrt2.o", "crtbegin.o", "crtend.o", }; - excludeSymbolPrefixes = { + ExcludeSymbolPrefixes = { // Import symbols "__imp_", "__IMPORT_DESCRIPTOR_", @@ -59,13 +59,13 @@ AutoExporter::AutoExporter() { ".", }; - excludeSymbolSuffixes = { + ExcludeSymbolSuffixes = { "_iname", "_NULL_THUNK_DATA", }; - if (config->machine == I386) { - excludeSymbols = { + if (Config->Machine == I386) { + ExcludeSymbols = { "__NULL_IMPORT_DESCRIPTOR", "__pei386_runtime_relocator", "_do_pseudo_reloc", @@ -80,9 +80,9 @@ AutoExporter::AutoExporter() { "_DllEntryPoint@12", "_DllMainCRTStartup@12", }; - excludeSymbolPrefixes.insert("__head_"); + ExcludeSymbolPrefixes.insert("__head_"); } else { - excludeSymbols = { + ExcludeSymbols = { "__NULL_IMPORT_DESCRIPTOR", "_pei386_runtime_relocator", "do_pseudo_reloc", @@ -97,70 +97,70 @@ AutoExporter::AutoExporter() { "DllEntryPoint", "DllMainCRTStartup", }; - excludeSymbolPrefixes.insert("_head_"); + ExcludeSymbolPrefixes.insert("_head_"); } } -void AutoExporter::addWholeArchive(StringRef path) { - StringRef libName = sys::path::filename(path); +void AutoExporter::addWholeArchive(StringRef Path) { + StringRef LibName = sys::path::filename(Path); // Drop the file extension, to match the processing below. - libName = libName.substr(0, libName.rfind('.')); - excludeLibs.erase(libName); + LibName = LibName.substr(0, LibName.rfind('.')); + ExcludeLibs.erase(LibName); } -bool AutoExporter::shouldExport(Defined *sym) const { - if (!sym || !sym->isLive() || !sym->getChunk()) +bool AutoExporter::shouldExport(Defined *Sym) const { + if (!Sym || !Sym->isLive() || !Sym->getChunk()) return false; // Only allow the symbol kinds that make sense to export; in particular, // disallow import symbols. - if (!isa(sym) && !isa(sym)) + if (!isa(Sym) && !isa(Sym)) return false; - if (excludeSymbols.count(sym->getName())) + if (ExcludeSymbols.count(Sym->getName())) return false; - for (StringRef prefix : excludeSymbolPrefixes.keys()) - if (sym->getName().startswith(prefix)) + for (StringRef Prefix : ExcludeSymbolPrefixes.keys()) + if (Sym->getName().startswith(Prefix)) return false; - for (StringRef suffix : excludeSymbolSuffixes.keys()) - if (sym->getName().endswith(suffix)) + for (StringRef Suffix : ExcludeSymbolSuffixes.keys()) + if (Sym->getName().endswith(Suffix)) return false; // If a corresponding __imp_ symbol exists and is defined, don't export it. - if (symtab->find(("__imp_" + sym->getName()).str())) + if (Symtab->find(("__imp_" + Sym->getName()).str())) return false; // Check that file is non-null before dereferencing it, symbols not // originating in regular object files probably shouldn't be exported. - if (!sym->getFile()) + if (!Sym->getFile()) return false; - StringRef libName = sys::path::filename(sym->getFile()->parentName); + StringRef LibName = sys::path::filename(Sym->getFile()->ParentName); // Drop the file extension. - libName = libName.substr(0, libName.rfind('.')); - if (!libName.empty()) - return !excludeLibs.count(libName); + LibName = LibName.substr(0, LibName.rfind('.')); + if (!LibName.empty()) + return !ExcludeLibs.count(LibName); - StringRef fileName = sys::path::filename(sym->getFile()->getName()); - return !excludeObjects.count(fileName); + StringRef FileName = sys::path::filename(Sym->getFile()->getName()); + return !ExcludeObjects.count(FileName); } -void coff::writeDefFile(StringRef name) { - std::error_code ec; - raw_fd_ostream os(name, ec, sys::fs::OF_None); - if (ec) - fatal("cannot open " + name + ": " + ec.message()); - - os << "EXPORTS\n"; - for (Export &e : config->exports) { - os << " " << e.exportName << " " - << "@" << e.ordinal; - if (auto *def = dyn_cast_or_null(e.sym)) { - if (def && def->getChunk() && - !(def->getChunk()->getOutputCharacteristics() & IMAGE_SCN_MEM_EXECUTE)) - os << " DATA"; +void coff::writeDefFile(StringRef Name) { + std::error_code EC; + raw_fd_ostream OS(Name, EC, sys::fs::F_None); + if (EC) + fatal("cannot open " + Name + ": " + EC.message()); + + OS << "EXPORTS\n"; + for (Export &E : Config->Exports) { + OS << " " << E.ExportName << " " + << "@" << E.Ordinal; + if (auto *Def = dyn_cast_or_null(E.Sym)) { + if (Def && Def->getChunk() && + !(Def->getChunk()->getOutputCharacteristics() & IMAGE_SCN_MEM_EXECUTE)) + OS << " DATA"; } - os << "\n"; + OS << "\n"; } } diff --git a/lld/COFF/MinGW.h b/lld/COFF/MinGW.h index 578a277561ad99..fde9eeb939272b 100644 --- a/lld/COFF/MinGW.h +++ b/lld/COFF/MinGW.h @@ -22,18 +22,18 @@ class AutoExporter { public: AutoExporter(); - void addWholeArchive(StringRef path); + void addWholeArchive(StringRef Path); - llvm::StringSet<> excludeSymbols; - llvm::StringSet<> excludeSymbolPrefixes; - llvm::StringSet<> excludeSymbolSuffixes; - llvm::StringSet<> excludeLibs; - llvm::StringSet<> excludeObjects; + llvm::StringSet<> ExcludeSymbols; + llvm::StringSet<> ExcludeSymbolPrefixes; + llvm::StringSet<> ExcludeSymbolSuffixes; + llvm::StringSet<> ExcludeLibs; + llvm::StringSet<> ExcludeObjects; - bool shouldExport(Defined *sym) const; + bool shouldExport(Defined *Sym) const; }; -void writeDefFile(StringRef name); +void writeDefFile(StringRef Name); } // namespace coff } // namespace lld diff --git a/lld/COFF/Options.td b/lld/COFF/Options.td index 59e69ea5439495..00698c4800d7ae 100644 --- a/lld/COFF/Options.td +++ b/lld/COFF/Options.td @@ -162,8 +162,6 @@ def help : F<"help">; def help_q : Flag<["/??", "-??", "/?", "-?"], "">, Alias; // LLD extensions -def end_lib : F<"end-lib">, - HelpText<"End a grouping of objects that should be treated as if they were together in an archive">; def exclude_all_symbols : F<"exclude-all-symbols">; def export_all_symbols : F<"export-all-symbols">; defm demangle : B<"demangle", @@ -178,26 +176,6 @@ def pdb_source_path : P<"pdbsourcepath", "Base path used to make relative source file path absolute in PDB">; def rsp_quoting : Joined<["--"], "rsp-quoting=">, HelpText<"Quoting style for response files, 'windows' (default) or 'posix'">; -def start_lib : F<"start-lib">, - HelpText<"Start a grouping of objects that should be treated as if they were together in an archive">; -def thinlto_emit_imports_files : - F<"thinlto-emit-imports-files">, - HelpText<"Emit .imports files with -thinlto-index-only">; -def thinlto_index_only : - F<"thinlto-index-only">, - HelpText<"Instead of linking, emit ThinLTO index files">; -def thinlto_index_only_arg : P< - "thinlto-index-only", - "-thinlto-index-only and also write native module names to file">; -def thinlto_object_suffix_replace : P< - "thinlto-object-suffix-replace", - "'old;new' replace old suffix with new suffix in ThinLTO index">; -def thinlto_prefix_replace: P< - "thinlto-prefix-replace", - "'old;new' replace old prefix with new prefix in ThinLTO outputs">; -def lto_obj_path : P< - "lto-obj-path", - "output native object for merged LTO unit to this path">; def dash_dash_version : Flag<["--"], "version">, HelpText<"Print version information">; defm threads: B<"threads", diff --git a/lld/COFF/PDB.cpp b/lld/COFF/PDB.cpp index 25952b59234abe..6d3bf641682952 100644 --- a/lld/COFF/PDB.cpp +++ b/lld/COFF/PDB.cpp @@ -66,16 +66,16 @@ using namespace llvm::codeview; using llvm::object::coff_section; -static ExitOnError exitOnErr; +static ExitOnError ExitOnErr; -static Timer totalPdbLinkTimer("PDB Emission (Cumulative)", Timer::root()); +static Timer TotalPdbLinkTimer("PDB Emission (Cumulative)", Timer::root()); -static Timer addObjectsTimer("Add Objects", totalPdbLinkTimer); -static Timer typeMergingTimer("Type Merging", addObjectsTimer); -static Timer symbolMergingTimer("Symbol Merging", addObjectsTimer); -static Timer globalsLayoutTimer("Globals Stream Layout", totalPdbLinkTimer); -static Timer tpiStreamLayoutTimer("TPI Stream Layout", totalPdbLinkTimer); -static Timer diskCommitTimer("Commit to Disk", totalPdbLinkTimer); +static Timer AddObjectsTimer("Add Objects", TotalPdbLinkTimer); +static Timer TypeMergingTimer("Type Merging", AddObjectsTimer); +static Timer SymbolMergingTimer("Symbol Merging", AddObjectsTimer); +static Timer GlobalsLayoutTimer("Globals Stream Layout", TotalPdbLinkTimer); +static Timer TpiStreamLayoutTimer("TPI Stream Layout", TotalPdbLinkTimer); +static Timer DiskCommitTimer("Commit to Disk", TotalPdbLinkTimer); namespace { class DebugSHandler; @@ -84,16 +84,16 @@ class PDBLinker { friend DebugSHandler; public: - PDBLinker(SymbolTable *symtab) - : alloc(), symtab(symtab), builder(alloc), tMerger(alloc) { + PDBLinker(SymbolTable *Symtab) + : Alloc(), Symtab(Symtab), Builder(Alloc), TMerger(Alloc) { // This isn't strictly necessary, but link.exe usually puts an empty string // as the first "valid" string in the string table, so we do the same in // order to maintain as much byte-for-byte compatibility as possible. - pdbStrTab.insert(""); + PDBStrTab.insert(""); } /// Emit the basic PDB structure: initial streams, headers, etc. - void initialize(llvm::codeview::DebugInfo *buildId); + void initialize(llvm::codeview::DebugInfo *BuildId); /// Add natvis files specified on the command line. void addNatvisFiles(); @@ -102,12 +102,12 @@ class PDBLinker { void addObjectsToPDB(); /// Link info for each import file in the symbol table into the PDB. - void addImportFilesToPDB(ArrayRef outputSections); + void addImportFilesToPDB(ArrayRef OutputSections); /// Link CodeView from a single object file into the target (output) PDB. /// When a precompiled headers object is linked, its TPI map might be provided /// externally. - void addObjFile(ObjFile *file, CVIndexMap *externIndexMap = nullptr); + void addObjFile(ObjFile *File, CVIndexMap *ExternIndexMap = nullptr); /// Produce a mapping from the type and item indices used in the object /// file to those in the destination PDB. @@ -119,17 +119,17 @@ class PDBLinker { /// /// If the object does not use a type server PDB (compiled with /Z7), we merge /// all the type and item records from the .debug$S stream and fill in the - /// caller-provided objectIndexMap. - Expected mergeDebugT(ObjFile *file, - CVIndexMap *objectIndexMap); + /// caller-provided ObjectIndexMap. + Expected mergeDebugT(ObjFile *File, + CVIndexMap *ObjectIndexMap); /// Reads and makes available a PDB. - Expected maybeMergeTypeServerPDB(ObjFile *file); + Expected maybeMergeTypeServerPDB(ObjFile *File); /// Merges a precompiled headers TPI map into the current TPI map. The /// precompiled headers object will also be loaded and remapped in the /// process. - Error mergeInPrecompHeaderObj(ObjFile *file, CVIndexMap *objectIndexMap); + Error mergeInPrecompHeaderObj(ObjFile *File, CVIndexMap *ObjectIndexMap); /// Reads and makes available a precompiled headers object. /// @@ -140,87 +140,87 @@ class PDBLinker { /// /// If the precompiled headers object was already loaded, this function will /// simply return its (remapped) TPI map. - Expected aquirePrecompObj(ObjFile *file); + Expected aquirePrecompObj(ObjFile *File); /// Adds a precompiled headers object signature -> TPI mapping. std::pair - registerPrecompiledHeaders(uint32_t signature); + registerPrecompiledHeaders(uint32_t Signature); - void mergeSymbolRecords(ObjFile *file, const CVIndexMap &indexMap, - std::vector &stringTableRefs, - BinaryStreamRef symData); + void mergeSymbolRecords(ObjFile *File, const CVIndexMap &IndexMap, + std::vector &StringTableRefs, + BinaryStreamRef SymData); /// Add the section map and section contributions to the PDB. - void addSections(ArrayRef outputSections, - ArrayRef sectionTable); + void addSections(ArrayRef OutputSections, + ArrayRef SectionTable); /// Write the PDB to disk and store the Guid generated for it in *Guid. - void commit(codeview::GUID *guid); + void commit(codeview::GUID *Guid); // Print statistics regarding the final PDB void printStats(); private: - BumpPtrAllocator alloc; + BumpPtrAllocator Alloc; - SymbolTable *symtab; + SymbolTable *Symtab; - pdb::PDBFileBuilder builder; + pdb::PDBFileBuilder Builder; - TypeMerger tMerger; + TypeMerger TMerger; /// PDBs use a single global string table for filenames in the file checksum /// table. - DebugStringTableSubsection pdbStrTab; + DebugStringTableSubsection PDBStrTab; - llvm::SmallString<128> nativePath; + llvm::SmallString<128> NativePath; - std::vector sectionMap; + std::vector SectionMap; /// Type index mappings of type server PDBs that we've loaded so far. - std::map typeServerIndexMappings; + std::map TypeServerIndexMappings; /// Type index mappings of precompiled objects type map that we've loaded so /// far. - std::map precompTypeIndexMappings; + std::map PrecompTypeIndexMappings; // For statistics - uint64_t globalSymbols = 0; - uint64_t moduleSymbols = 0; - uint64_t publicSymbols = 0; + uint64_t GlobalSymbols = 0; + uint64_t ModuleSymbols = 0; + uint64_t PublicSymbols = 0; }; class DebugSHandler { - PDBLinker &linker; + PDBLinker &Linker; /// The object file whose .debug$S sections we're processing. - ObjFile &file; + ObjFile &File; /// The result of merging type indices. - const CVIndexMap &indexMap; + const CVIndexMap &IndexMap; /// The DEBUG_S_STRINGTABLE subsection. These strings are referred to by /// index from other records in the .debug$S section. All of these strings /// need to be added to the global PDB string table, and all references to /// these strings need to have their indices re-written to refer to the /// global PDB string table. - DebugStringTableSubsectionRef cVStrTab; + DebugStringTableSubsectionRef CVStrTab; /// The DEBUG_S_FILECHKSMS subsection. As above, these are referred to /// by other records in the .debug$S section and need to be merged into the /// PDB. - DebugChecksumsSubsectionRef checksums; + DebugChecksumsSubsectionRef Checksums; /// The DEBUG_S_INLINEELINES subsection. There can be only one of these per /// object file. - DebugInlineeLinesSubsectionRef inlineeLines; + DebugInlineeLinesSubsectionRef InlineeLines; /// The DEBUG_S_FRAMEDATA subsection(s). There can be more than one of /// these and they need not appear in any specific order. However, they /// contain string table references which need to be re-written, so we /// collect them all here and re-write them after all subsections have been /// discovered and processed. - std::vector newFpoFrames; + std::vector NewFpoFrames; /// Pointers to raw memory that we determine have string table references /// that need to be re-written. We first process all .debug$S subsections @@ -228,16 +228,16 @@ class DebugSHandler { /// up this list as we go. At the end, we use the string table (which must /// have been discovered by now else it is an error) to re-write these /// references. - std::vector stringTableReferences; + std::vector StringTableReferences; public: - DebugSHandler(PDBLinker &linker, ObjFile &file, const CVIndexMap &indexMap) - : linker(linker), file(file), indexMap(indexMap) {} + DebugSHandler(PDBLinker &Linker, ObjFile &File, const CVIndexMap &IndexMap) + : Linker(Linker), File(File), IndexMap(IndexMap) {} - void handleDebugS(lld::coff::SectionChunk &debugS); + void handleDebugS(lld::coff::SectionChunk &DebugS); std::shared_ptr - mergeInlineeLines(DebugChecksumsSubsection *newChecksums); + mergeInlineeLines(DebugChecksumsSubsection *NewChecksums); void finish(); }; @@ -246,7 +246,7 @@ class DebugSHandler { // Visual Studio's debugger requires absolute paths in various places in the // PDB to work without additional configuration: // https://docs.microsoft.com/en-us/visualstudio/debugger/debug-source-files-common-properties-solution-property-pages-dialog-box -static void pdbMakeAbsolute(SmallVectorImpl &fileName) { +static void pdbMakeAbsolute(SmallVectorImpl &FileName) { // The default behavior is to produce paths that are valid within the context // of the machine that you perform the link on. If the linker is running on // a POSIX system, we will output absolute POSIX paths. If the linker is @@ -254,16 +254,16 @@ static void pdbMakeAbsolute(SmallVectorImpl &fileName) { // user desires any other kind of behavior, they should explicitly pass // /pdbsourcepath, in which case we will treat the exact string the user // passed in as the gospel and not normalize, canonicalize it. - if (sys::path::is_absolute(fileName, sys::path::Style::windows) || - sys::path::is_absolute(fileName, sys::path::Style::posix)) + if (sys::path::is_absolute(FileName, sys::path::Style::windows) || + sys::path::is_absolute(FileName, sys::path::Style::posix)) return; // It's not absolute in any path syntax. Relative paths necessarily refer to // the local file system, so we can make it native without ending up with a // nonsensical path. - if (config->pdbSourcePath.empty()) { - sys::path::native(fileName); - sys::fs::make_absolute(fileName); + if (Config->PDBSourcePath.empty()) { + sys::path::native(FileName); + sys::fs::make_absolute(FileName); return; } @@ -271,238 +271,238 @@ static void pdbMakeAbsolute(SmallVectorImpl &fileName) { // Since PDB's are more of a Windows thing, we make this conservative and only // decide that it's a unix path if we're fairly certain. Specifically, if // it starts with a forward slash. - SmallString<128> absoluteFileName = config->pdbSourcePath; - sys::path::Style guessedStyle = absoluteFileName.startswith("/") + SmallString<128> AbsoluteFileName = Config->PDBSourcePath; + sys::path::Style GuessedStyle = AbsoluteFileName.startswith("/") ? sys::path::Style::posix : sys::path::Style::windows; - sys::path::append(absoluteFileName, guessedStyle, fileName); - sys::path::native(absoluteFileName, guessedStyle); - sys::path::remove_dots(absoluteFileName, true, guessedStyle); + sys::path::append(AbsoluteFileName, GuessedStyle, FileName); + sys::path::native(AbsoluteFileName, GuessedStyle); + sys::path::remove_dots(AbsoluteFileName, true, GuessedStyle); - fileName = std::move(absoluteFileName); + FileName = std::move(AbsoluteFileName); } // A COFF .debug$H section is currently a clang extension. This function checks // if a .debug$H section is in a format that we expect / understand, so that we // can ignore any sections which are coincidentally also named .debug$H but do // not contain a format we recognize. -static bool canUseDebugH(ArrayRef debugH) { - if (debugH.size() < sizeof(object::debug_h_header)) +static bool canUseDebugH(ArrayRef DebugH) { + if (DebugH.size() < sizeof(object::debug_h_header)) return false; - auto *header = - reinterpret_cast(debugH.data()); - debugH = debugH.drop_front(sizeof(object::debug_h_header)); - return header->Magic == COFF::DEBUG_HASHES_SECTION_MAGIC && - header->Version == 0 && - header->HashAlgorithm == uint16_t(GlobalTypeHashAlg::SHA1_8) && - (debugH.size() % 8 == 0); + auto *Header = + reinterpret_cast(DebugH.data()); + DebugH = DebugH.drop_front(sizeof(object::debug_h_header)); + return Header->Magic == COFF::DEBUG_HASHES_SECTION_MAGIC && + Header->Version == 0 && + Header->HashAlgorithm == uint16_t(GlobalTypeHashAlg::SHA1_8) && + (DebugH.size() % 8 == 0); } -static Optional> getDebugH(ObjFile *file) { - SectionChunk *sec = - SectionChunk::findByName(file->getDebugChunks(), ".debug$H"); - if (!sec) +static Optional> getDebugH(ObjFile *File) { + SectionChunk *Sec = + SectionChunk::findByName(File->getDebugChunks(), ".debug$H"); + if (!Sec) return llvm::None; - ArrayRef contents = sec->getContents(); - if (!canUseDebugH(contents)) + ArrayRef Contents = Sec->getContents(); + if (!canUseDebugH(Contents)) return None; - return contents; + return Contents; } static ArrayRef -getHashesFromDebugH(ArrayRef debugH) { - assert(canUseDebugH(debugH)); +getHashesFromDebugH(ArrayRef DebugH) { + assert(canUseDebugH(DebugH)); - debugH = debugH.drop_front(sizeof(object::debug_h_header)); - uint32_t count = debugH.size() / sizeof(GloballyHashedType); - return {reinterpret_cast(debugH.data()), count}; + DebugH = DebugH.drop_front(sizeof(object::debug_h_header)); + uint32_t Count = DebugH.size() / sizeof(GloballyHashedType); + return {reinterpret_cast(DebugH.data()), Count}; } -static void addTypeInfo(pdb::TpiStreamBuilder &tpiBuilder, - TypeCollection &typeTable) { +static void addTypeInfo(pdb::TpiStreamBuilder &TpiBuilder, + TypeCollection &TypeTable) { // Start the TPI or IPI stream header. - tpiBuilder.setVersionHeader(pdb::PdbTpiV80); + TpiBuilder.setVersionHeader(pdb::PdbTpiV80); // Flatten the in memory type table and hash each type. - typeTable.ForEachRecord([&](TypeIndex ti, const CVType &type) { - auto hash = pdb::hashTypeRecord(type); - if (auto e = hash.takeError()) + TypeTable.ForEachRecord([&](TypeIndex TI, const CVType &Type) { + auto Hash = pdb::hashTypeRecord(Type); + if (auto E = Hash.takeError()) fatal("type hashing error"); - tpiBuilder.addTypeRecord(type.RecordData, *hash); + TpiBuilder.addTypeRecord(Type.RecordData, *Hash); }); } Expected -PDBLinker::mergeDebugT(ObjFile *file, CVIndexMap *objectIndexMap) { - ScopedTimer t(typeMergingTimer); +PDBLinker::mergeDebugT(ObjFile *File, CVIndexMap *ObjectIndexMap) { + ScopedTimer T(TypeMergingTimer); - if (!file->debugTypesObj) - return *objectIndexMap; // no Types stream + if (!File->DebugTypesObj) + return *ObjectIndexMap; // no Types stream // Precompiled headers objects need to save the index map for further // reference by other objects which use the precompiled headers. - if (file->debugTypesObj->kind == TpiSource::PCH) { - uint32_t pchSignature = file->pchSignature.getValueOr(0); - if (pchSignature == 0) + if (File->DebugTypesObj->Kind == TpiSource::PCH) { + uint32_t PCHSignature = File->PCHSignature.getValueOr(0); + if (PCHSignature == 0) fatal("No signature found for the precompiled headers OBJ (" + - file->getName() + ")"); + File->getName() + ")"); // When a precompiled headers object comes first on the command-line, we // update the mapping here. Otherwise, if an object referencing the // precompiled headers object comes first, the mapping is created in // aquirePrecompObj(), thus we would skip this block. - if (!objectIndexMap->isPrecompiledTypeMap) { - auto r = registerPrecompiledHeaders(pchSignature); - if (r.second) + if (!ObjectIndexMap->IsPrecompiledTypeMap) { + auto R = registerPrecompiledHeaders(PCHSignature); + if (R.second) fatal( "A precompiled headers OBJ with the same signature was already " "provided! (" + - file->getName() + ")"); + File->getName() + ")"); - objectIndexMap = &r.first; + ObjectIndexMap = &R.first; } } - if (file->debugTypesObj->kind == TpiSource::UsingPDB) { + if (File->DebugTypesObj->Kind == TpiSource::UsingPDB) { // Look through type servers. If we've already seen this type server, // don't merge any type information. - return maybeMergeTypeServerPDB(file); + return maybeMergeTypeServerPDB(File); } - CVTypeArray &types = *file->debugTypes; + CVTypeArray &Types = *File->DebugTypes; - if (file->debugTypesObj->kind == TpiSource::UsingPCH) { + if (File->DebugTypesObj->Kind == TpiSource::UsingPCH) { // This object was compiled with /Yu, so process the corresponding // precompiled headers object (/Yc) first. Some type indices in the current // object are referencing data in the precompiled headers object, so we need // both to be loaded. - Error e = mergeInPrecompHeaderObj(file, objectIndexMap); - if (e) - return std::move(e); + Error E = mergeInPrecompHeaderObj(File, ObjectIndexMap); + if (E) + return std::move(E); // Drop LF_PRECOMP record from the input stream, as it has been replaced // with the precompiled headers Type stream in the mergeInPrecompHeaderObj() // call above. Note that we can't just call Types.drop_front(), as we // explicitly want to rebase the stream. - CVTypeArray::Iterator firstType = types.begin(); - types.setUnderlyingStream( - types.getUnderlyingStream().drop_front(firstType->RecordData.size())); + CVTypeArray::Iterator FirstType = Types.begin(); + Types.setUnderlyingStream( + Types.getUnderlyingStream().drop_front(FirstType->RecordData.size())); } // Fill in the temporary, caller-provided ObjectIndexMap. - if (config->debugGHashes) { - ArrayRef hashes; - std::vector ownedHashes; - if (Optional> debugH = getDebugH(file)) - hashes = getHashesFromDebugH(*debugH); + if (Config->DebugGHashes) { + ArrayRef Hashes; + std::vector OwnedHashes; + if (Optional> DebugH = getDebugH(File)) + Hashes = getHashesFromDebugH(*DebugH); else { - ownedHashes = GloballyHashedType::hashTypes(types); - hashes = ownedHashes; + OwnedHashes = GloballyHashedType::hashTypes(Types); + Hashes = OwnedHashes; } - if (auto err = mergeTypeAndIdRecords( - tMerger.globalIDTable, tMerger.globalTypeTable, - objectIndexMap->tpiMap, types, hashes, file->pchSignature)) + if (auto Err = mergeTypeAndIdRecords( + TMerger.GlobalIDTable, TMerger.GlobalTypeTable, + ObjectIndexMap->TPIMap, Types, Hashes, File->PCHSignature)) fatal("codeview::mergeTypeAndIdRecords failed: " + - toString(std::move(err))); + toString(std::move(Err))); } else { - if (auto err = mergeTypeAndIdRecords(tMerger.iDTable, tMerger.typeTable, - objectIndexMap->tpiMap, types, - file->pchSignature)) + if (auto Err = mergeTypeAndIdRecords(TMerger.IDTable, TMerger.TypeTable, + ObjectIndexMap->TPIMap, Types, + File->PCHSignature)) fatal("codeview::mergeTypeAndIdRecords failed: " + - toString(std::move(err))); + toString(std::move(Err))); } - return *objectIndexMap; + return *ObjectIndexMap; } -Expected PDBLinker::maybeMergeTypeServerPDB(ObjFile *file) { - Expected pdbSession = findTypeServerSource(file); - if (!pdbSession) - return pdbSession.takeError(); +Expected PDBLinker::maybeMergeTypeServerPDB(ObjFile *File) { + Expected PDBSession = findTypeServerSource(File); + if (!PDBSession) + return PDBSession.takeError(); - pdb::PDBFile &pdbFile = pdbSession.get()->getPDBFile(); - pdb::InfoStream &info = cantFail(pdbFile.getPDBInfoStream()); + pdb::PDBFile &PDBFile = PDBSession.get()->getPDBFile(); + pdb::InfoStream &Info = cantFail(PDBFile.getPDBInfoStream()); - auto it = typeServerIndexMappings.emplace(info.getGuid(), CVIndexMap()); - CVIndexMap &indexMap = it.first->second; - if (!it.second) - return indexMap; // already merged + auto It = TypeServerIndexMappings.emplace(Info.getGuid(), CVIndexMap()); + CVIndexMap &IndexMap = It.first->second; + if (!It.second) + return IndexMap; // already merged // Mark this map as a type server map. - indexMap.isTypeServerMap = true; - - Expected expectedTpi = pdbFile.getPDBTpiStream(); - if (auto e = expectedTpi.takeError()) - fatal("Type server does not have TPI stream: " + toString(std::move(e))); - pdb::TpiStream *maybeIpi = nullptr; - if (pdbFile.hasPDBIpiStream()) { - Expected expectedIpi = pdbFile.getPDBIpiStream(); - if (auto e = expectedIpi.takeError()) - fatal("Error getting type server IPI stream: " + toString(std::move(e))); - maybeIpi = &*expectedIpi; + IndexMap.IsTypeServerMap = true; + + Expected ExpectedTpi = PDBFile.getPDBTpiStream(); + if (auto E = ExpectedTpi.takeError()) + fatal("Type server does not have TPI stream: " + toString(std::move(E))); + pdb::TpiStream *MaybeIpi = nullptr; + if (PDBFile.hasPDBIpiStream()) { + Expected ExpectedIpi = PDBFile.getPDBIpiStream(); + if (auto E = ExpectedIpi.takeError()) + fatal("Error getting type server IPI stream: " + toString(std::move(E))); + MaybeIpi = &*ExpectedIpi; } - if (config->debugGHashes) { + if (Config->DebugGHashes) { // PDBs do not actually store global hashes, so when merging a type server // PDB we have to synthesize global hashes. To do this, we first synthesize // global hashes for the TPI stream, since it is independent, then we // synthesize hashes for the IPI stream, using the hashes for the TPI stream // as inputs. - auto tpiHashes = GloballyHashedType::hashTypes(expectedTpi->typeArray()); - Optional endPrecomp; + auto TpiHashes = GloballyHashedType::hashTypes(ExpectedTpi->typeArray()); + Optional EndPrecomp; // Merge TPI first, because the IPI stream will reference type indices. - if (auto err = - mergeTypeRecords(tMerger.globalTypeTable, indexMap.tpiMap, - expectedTpi->typeArray(), tpiHashes, endPrecomp)) - fatal("codeview::mergeTypeRecords failed: " + toString(std::move(err))); + if (auto Err = + mergeTypeRecords(TMerger.GlobalTypeTable, IndexMap.TPIMap, + ExpectedTpi->typeArray(), TpiHashes, EndPrecomp)) + fatal("codeview::mergeTypeRecords failed: " + toString(std::move(Err))); // Merge IPI. - if (maybeIpi) { - auto ipiHashes = - GloballyHashedType::hashIds(maybeIpi->typeArray(), tpiHashes); - if (auto err = - mergeIdRecords(tMerger.globalIDTable, indexMap.tpiMap, - indexMap.ipiMap, maybeIpi->typeArray(), ipiHashes)) - fatal("codeview::mergeIdRecords failed: " + toString(std::move(err))); + if (MaybeIpi) { + auto IpiHashes = + GloballyHashedType::hashIds(MaybeIpi->typeArray(), TpiHashes); + if (auto Err = + mergeIdRecords(TMerger.GlobalIDTable, IndexMap.TPIMap, + IndexMap.IPIMap, MaybeIpi->typeArray(), IpiHashes)) + fatal("codeview::mergeIdRecords failed: " + toString(std::move(Err))); } } else { // Merge TPI first, because the IPI stream will reference type indices. - if (auto err = mergeTypeRecords(tMerger.typeTable, indexMap.tpiMap, - expectedTpi->typeArray())) - fatal("codeview::mergeTypeRecords failed: " + toString(std::move(err))); + if (auto Err = mergeTypeRecords(TMerger.TypeTable, IndexMap.TPIMap, + ExpectedTpi->typeArray())) + fatal("codeview::mergeTypeRecords failed: " + toString(std::move(Err))); // Merge IPI. - if (maybeIpi) { - if (auto err = mergeIdRecords(tMerger.iDTable, indexMap.tpiMap, - indexMap.ipiMap, maybeIpi->typeArray())) - fatal("codeview::mergeIdRecords failed: " + toString(std::move(err))); + if (MaybeIpi) { + if (auto Err = mergeIdRecords(TMerger.IDTable, IndexMap.TPIMap, + IndexMap.IPIMap, MaybeIpi->typeArray())) + fatal("codeview::mergeIdRecords failed: " + toString(std::move(Err))); } } - return indexMap; + return IndexMap; } -Error PDBLinker::mergeInPrecompHeaderObj(ObjFile *file, - CVIndexMap *objectIndexMap) { - const PrecompRecord &precomp = - retrieveDependencyInfo(file->debugTypesObj); +Error PDBLinker::mergeInPrecompHeaderObj(ObjFile *File, + CVIndexMap *ObjectIndexMap) { + const PrecompRecord &Precomp = + retrieveDependencyInfo(File->DebugTypesObj); - Expected e = aquirePrecompObj(file); - if (!e) - return e.takeError(); + Expected E = aquirePrecompObj(File); + if (!E) + return E.takeError(); - const CVIndexMap &precompIndexMap = *e; - assert(precompIndexMap.isPrecompiledTypeMap); + const CVIndexMap &PrecompIndexMap = *E; + assert(PrecompIndexMap.IsPrecompiledTypeMap); - if (precompIndexMap.tpiMap.empty()) + if (PrecompIndexMap.TPIMap.empty()) return Error::success(); - assert(precomp.getStartTypeIndex() == TypeIndex::FirstNonSimpleIndex); - assert(precomp.getTypesCount() <= precompIndexMap.tpiMap.size()); + assert(Precomp.getStartTypeIndex() == TypeIndex::FirstNonSimpleIndex); + assert(Precomp.getTypesCount() <= PrecompIndexMap.TPIMap.size()); // Use the previously remapped index map from the precompiled headers. - objectIndexMap->tpiMap.append(precompIndexMap.tpiMap.begin(), - precompIndexMap.tpiMap.begin() + - precomp.getTypesCount()); + ObjectIndexMap->TPIMap.append(PrecompIndexMap.TPIMap.begin(), + PrecompIndexMap.TPIMap.begin() + + Precomp.getTypesCount()); return Error::success(); } @@ -515,103 +515,103 @@ static bool equals_path(StringRef path1, StringRef path2) { } // Find by name an OBJ provided on the command line -static ObjFile *findObjByName(StringRef fileNameOnly) { - SmallString<128> currentPath; +static ObjFile *findObjByName(StringRef FileNameOnly) { + SmallString<128> CurrentPath; - for (ObjFile *f : ObjFile::instances) { - StringRef currentFileName = sys::path::filename(f->getName()); + for (ObjFile *F : ObjFile::Instances) { + StringRef CurrentFileName = sys::path::filename(F->getName()); // Compare based solely on the file name (link.exe behavior) - if (equals_path(currentFileName, fileNameOnly)) - return f; + if (equals_path(CurrentFileName, FileNameOnly)) + return F; } return nullptr; } std::pair -PDBLinker::registerPrecompiledHeaders(uint32_t signature) { - auto insertion = precompTypeIndexMappings.insert({signature, CVIndexMap()}); - CVIndexMap &indexMap = insertion.first->second; - if (!insertion.second) - return {indexMap, true}; +PDBLinker::registerPrecompiledHeaders(uint32_t Signature) { + auto Insertion = PrecompTypeIndexMappings.insert({Signature, CVIndexMap()}); + CVIndexMap &IndexMap = Insertion.first->second; + if (!Insertion.second) + return {IndexMap, true}; // Mark this map as a precompiled types map. - indexMap.isPrecompiledTypeMap = true; - return {indexMap, false}; + IndexMap.IsPrecompiledTypeMap = true; + return {IndexMap, false}; } -Expected PDBLinker::aquirePrecompObj(ObjFile *file) { - const PrecompRecord &precomp = - retrieveDependencyInfo(file->debugTypesObj); +Expected PDBLinker::aquirePrecompObj(ObjFile *File) { + const PrecompRecord &Precomp = + retrieveDependencyInfo(File->DebugTypesObj); // First, check if we already loaded the precompiled headers object with this // signature. Return the type index mapping if we've already seen it. - auto r = registerPrecompiledHeaders(precomp.getSignature()); - if (r.second) - return r.first; + auto R = registerPrecompiledHeaders(Precomp.getSignature()); + if (R.second) + return R.first; - CVIndexMap &indexMap = r.first; + CVIndexMap &IndexMap = R.first; // Cross-compile warning: given that Clang doesn't generate LF_PRECOMP // records, we assume the OBJ comes from a Windows build of cl.exe. Thusly, // the paths embedded in the OBJs are in the Windows format. - SmallString<128> precompFileName = sys::path::filename( - precomp.getPrecompFilePath(), sys::path::Style::windows); + SmallString<128> PrecompFileName = sys::path::filename( + Precomp.getPrecompFilePath(), sys::path::Style::windows); // link.exe requires that a precompiled headers object must always be provided // on the command-line, even if that's not necessary. - auto precompFile = findObjByName(precompFileName); - if (!precompFile) + auto PrecompFile = findObjByName(PrecompFileName); + if (!PrecompFile) return createFileError( - precompFileName.str(), + PrecompFileName.str(), make_error(pdb::pdb_error_code::external_cmdline_ref)); - addObjFile(precompFile, &indexMap); + addObjFile(PrecompFile, &IndexMap); - if (!precompFile->pchSignature) - fatal(precompFile->getName() + " is not a precompiled headers object"); + if (!PrecompFile->PCHSignature) + fatal(PrecompFile->getName() + " is not a precompiled headers object"); - if (precomp.getSignature() != precompFile->pchSignature.getValueOr(0)) + if (Precomp.getSignature() != PrecompFile->PCHSignature.getValueOr(0)) return createFileError( - precomp.getPrecompFilePath().str(), + Precomp.getPrecompFilePath().str(), make_error(pdb::pdb_error_code::signature_out_of_date)); - return indexMap; + return IndexMap; } -static bool remapTypeIndex(TypeIndex &ti, ArrayRef typeIndexMap) { - if (ti.isSimple()) +static bool remapTypeIndex(TypeIndex &TI, ArrayRef TypeIndexMap) { + if (TI.isSimple()) return true; - if (ti.toArrayIndex() >= typeIndexMap.size()) + if (TI.toArrayIndex() >= TypeIndexMap.size()) return false; - ti = typeIndexMap[ti.toArrayIndex()]; + TI = TypeIndexMap[TI.toArrayIndex()]; return true; } -static void remapTypesInSymbolRecord(ObjFile *file, SymbolKind symKind, - MutableArrayRef recordBytes, - const CVIndexMap &indexMap, - ArrayRef typeRefs) { - MutableArrayRef contents = - recordBytes.drop_front(sizeof(RecordPrefix)); - for (const TiReference &ref : typeRefs) { - unsigned byteSize = ref.Count * sizeof(TypeIndex); - if (contents.size() < ref.Offset + byteSize) +static void remapTypesInSymbolRecord(ObjFile *File, SymbolKind SymKind, + MutableArrayRef RecordBytes, + const CVIndexMap &IndexMap, + ArrayRef TypeRefs) { + MutableArrayRef Contents = + RecordBytes.drop_front(sizeof(RecordPrefix)); + for (const TiReference &Ref : TypeRefs) { + unsigned ByteSize = Ref.Count * sizeof(TypeIndex); + if (Contents.size() < Ref.Offset + ByteSize) fatal("symbol record too short"); // This can be an item index or a type index. Choose the appropriate map. - ArrayRef typeOrItemMap = indexMap.tpiMap; - bool isItemIndex = ref.Kind == TiRefKind::IndexRef; - if (isItemIndex && indexMap.isTypeServerMap) - typeOrItemMap = indexMap.ipiMap; - - MutableArrayRef tIs( - reinterpret_cast(contents.data() + ref.Offset), ref.Count); - for (TypeIndex &ti : tIs) { - if (!remapTypeIndex(ti, typeOrItemMap)) { - log("ignoring symbol record of kind 0x" + utohexstr(symKind) + " in " + - file->getName() + " with bad " + (isItemIndex ? "item" : "type") + - " index 0x" + utohexstr(ti.getIndex())); - ti = TypeIndex(SimpleTypeKind::NotTranslated); + ArrayRef TypeOrItemMap = IndexMap.TPIMap; + bool IsItemIndex = Ref.Kind == TiRefKind::IndexRef; + if (IsItemIndex && IndexMap.IsTypeServerMap) + TypeOrItemMap = IndexMap.IPIMap; + + MutableArrayRef TIs( + reinterpret_cast(Contents.data() + Ref.Offset), Ref.Count); + for (TypeIndex &TI : TIs) { + if (!remapTypeIndex(TI, TypeOrItemMap)) { + log("ignoring symbol record of kind 0x" + utohexstr(SymKind) + " in " + + File->getName() + " with bad " + (IsItemIndex ? "item" : "type") + + " index 0x" + utohexstr(TI.getIndex())); + TI = TypeIndex(SimpleTypeKind::NotTranslated); continue; } } @@ -619,26 +619,26 @@ static void remapTypesInSymbolRecord(ObjFile *file, SymbolKind symKind, } static void -recordStringTableReferenceAtOffset(MutableArrayRef contents, - uint32_t offset, - std::vector &strTableRefs) { - contents = - contents.drop_front(offset).take_front(sizeof(support::ulittle32_t)); - ulittle32_t *index = reinterpret_cast(contents.data()); - strTableRefs.push_back(index); +recordStringTableReferenceAtOffset(MutableArrayRef Contents, + uint32_t Offset, + std::vector &StrTableRefs) { + Contents = + Contents.drop_front(Offset).take_front(sizeof(support::ulittle32_t)); + ulittle32_t *Index = reinterpret_cast(Contents.data()); + StrTableRefs.push_back(Index); } static void -recordStringTableReferences(SymbolKind kind, MutableArrayRef contents, - std::vector &strTableRefs) { +recordStringTableReferences(SymbolKind Kind, MutableArrayRef Contents, + std::vector &StrTableRefs) { // For now we only handle S_FILESTATIC, but we may need the same logic for // S_DEFRANGE and S_DEFRANGE_SUBFIELD. However, I cannot seem to generate any // PDBs that contain these types of records, so because of the uncertainty // they are omitted here until we can prove that it's necessary. - switch (kind) { + switch (Kind) { case SymbolKind::S_FILESTATIC: // FileStaticSym::ModFileOffset - recordStringTableReferenceAtOffset(contents, 8, strTableRefs); + recordStringTableReferenceAtOffset(Contents, 8, StrTableRefs); break; case SymbolKind::S_DEFRANGE: case SymbolKind::S_DEFRANGE_SUBFIELD: @@ -650,21 +650,21 @@ recordStringTableReferences(SymbolKind kind, MutableArrayRef contents, } } -static SymbolKind symbolKind(ArrayRef recordData) { - const RecordPrefix *prefix = - reinterpret_cast(recordData.data()); - return static_cast(uint16_t(prefix->RecordKind)); +static SymbolKind symbolKind(ArrayRef RecordData) { + const RecordPrefix *Prefix = + reinterpret_cast(RecordData.data()); + return static_cast(uint16_t(Prefix->RecordKind)); } /// MSVC translates S_PROC_ID_END to S_END, and S_[LG]PROC32_ID to S_[LG]PROC32 -static void translateIdSymbols(MutableArrayRef &recordData, - TypeCollection &iDTable) { - RecordPrefix *prefix = reinterpret_cast(recordData.data()); +static void translateIdSymbols(MutableArrayRef &RecordData, + TypeCollection &IDTable) { + RecordPrefix *Prefix = reinterpret_cast(RecordData.data()); - SymbolKind kind = symbolKind(recordData); + SymbolKind Kind = symbolKind(RecordData); - if (kind == SymbolKind::S_PROC_ID_END) { - prefix->RecordKind = SymbolKind::S_END; + if (Kind == SymbolKind::S_PROC_ID_END) { + Prefix->RecordKind = SymbolKind::S_END; return; } @@ -673,89 +673,89 @@ static void translateIdSymbols(MutableArrayRef &recordData, // to the PDB file's ID stream index space, but we need to convert this to a // symbol that refers to the type stream index space. So we remap again from // ID index space to type index space. - if (kind == SymbolKind::S_GPROC32_ID || kind == SymbolKind::S_LPROC32_ID) { - SmallVector refs; - auto content = recordData.drop_front(sizeof(RecordPrefix)); - CVSymbol sym(recordData); - discoverTypeIndicesInSymbol(sym, refs); - assert(refs.size() == 1); - assert(refs.front().Count == 1); - - TypeIndex *ti = - reinterpret_cast(content.data() + refs[0].Offset); - // `ti` is the index of a FuncIdRecord or MemberFuncIdRecord which lives in + if (Kind == SymbolKind::S_GPROC32_ID || Kind == SymbolKind::S_LPROC32_ID) { + SmallVector Refs; + auto Content = RecordData.drop_front(sizeof(RecordPrefix)); + CVSymbol Sym(RecordData); + discoverTypeIndicesInSymbol(Sym, Refs); + assert(Refs.size() == 1); + assert(Refs.front().Count == 1); + + TypeIndex *TI = + reinterpret_cast(Content.data() + Refs[0].Offset); + // `TI` is the index of a FuncIdRecord or MemberFuncIdRecord which lives in // the IPI stream, whose `FunctionType` member refers to the TPI stream. // Note that LF_FUNC_ID and LF_MEMFUNC_ID have the same record layout, and // in both cases we just need the second type index. - if (!ti->isSimple() && !ti->isNoneType()) { - CVType funcIdData = iDTable.getType(*ti); - SmallVector indices; - discoverTypeIndices(funcIdData, indices); - assert(indices.size() == 2); - *ti = indices[1]; + if (!TI->isSimple() && !TI->isNoneType()) { + CVType FuncIdData = IDTable.getType(*TI); + SmallVector Indices; + discoverTypeIndices(FuncIdData, Indices); + assert(Indices.size() == 2); + *TI = Indices[1]; } - kind = (kind == SymbolKind::S_GPROC32_ID) ? SymbolKind::S_GPROC32 + Kind = (Kind == SymbolKind::S_GPROC32_ID) ? SymbolKind::S_GPROC32 : SymbolKind::S_LPROC32; - prefix->RecordKind = uint16_t(kind); + Prefix->RecordKind = uint16_t(Kind); } } /// Copy the symbol record. In a PDB, symbol records must be 4 byte aligned. /// The object file may not be aligned. static MutableArrayRef -copyAndAlignSymbol(const CVSymbol &sym, MutableArrayRef &alignedMem) { - size_t size = alignTo(sym.length(), alignOf(CodeViewContainer::Pdb)); - assert(size >= 4 && "record too short"); - assert(size <= MaxRecordLength && "record too long"); - assert(alignedMem.size() >= size && "didn't preallocate enough"); +copyAndAlignSymbol(const CVSymbol &Sym, MutableArrayRef &AlignedMem) { + size_t Size = alignTo(Sym.length(), alignOf(CodeViewContainer::Pdb)); + assert(Size >= 4 && "record too short"); + assert(Size <= MaxRecordLength && "record too long"); + assert(AlignedMem.size() >= Size && "didn't preallocate enough"); // Copy the symbol record and zero out any padding bytes. - MutableArrayRef newData = alignedMem.take_front(size); - alignedMem = alignedMem.drop_front(size); - memcpy(newData.data(), sym.data().data(), sym.length()); - memset(newData.data() + sym.length(), 0, size - sym.length()); + MutableArrayRef NewData = AlignedMem.take_front(Size); + AlignedMem = AlignedMem.drop_front(Size); + memcpy(NewData.data(), Sym.data().data(), Sym.length()); + memset(NewData.data() + Sym.length(), 0, Size - Sym.length()); // Update the record prefix length. It should point to the beginning of the // next record. - auto *prefix = reinterpret_cast(newData.data()); - prefix->RecordLen = size - 2; - return newData; + auto *Prefix = reinterpret_cast(NewData.data()); + Prefix->RecordLen = Size - 2; + return NewData; } struct ScopeRecord { - ulittle32_t ptrParent; - ulittle32_t ptrEnd; + ulittle32_t PtrParent; + ulittle32_t PtrEnd; }; struct SymbolScope { - ScopeRecord *openingRecord; - uint32_t scopeOffset; + ScopeRecord *OpeningRecord; + uint32_t ScopeOffset; }; -static void scopeStackOpen(SmallVectorImpl &stack, - uint32_t curOffset, CVSymbol &sym) { - assert(symbolOpensScope(sym.kind())); - SymbolScope s; - s.scopeOffset = curOffset; - s.openingRecord = const_cast( - reinterpret_cast(sym.content().data())); - s.openingRecord->ptrParent = stack.empty() ? 0 : stack.back().scopeOffset; - stack.push_back(s); +static void scopeStackOpen(SmallVectorImpl &Stack, + uint32_t CurOffset, CVSymbol &Sym) { + assert(symbolOpensScope(Sym.kind())); + SymbolScope S; + S.ScopeOffset = CurOffset; + S.OpeningRecord = const_cast( + reinterpret_cast(Sym.content().data())); + S.OpeningRecord->PtrParent = Stack.empty() ? 0 : Stack.back().ScopeOffset; + Stack.push_back(S); } -static void scopeStackClose(SmallVectorImpl &stack, - uint32_t curOffset, InputFile *file) { - if (stack.empty()) { - warn("symbol scopes are not balanced in " + file->getName()); +static void scopeStackClose(SmallVectorImpl &Stack, + uint32_t CurOffset, InputFile *File) { + if (Stack.empty()) { + warn("symbol scopes are not balanced in " + File->getName()); return; } - SymbolScope s = stack.pop_back_val(); - s.openingRecord->ptrEnd = curOffset; + SymbolScope S = Stack.pop_back_val(); + S.OpeningRecord->PtrEnd = CurOffset; } -static bool symbolGoesInModuleStream(const CVSymbol &sym, bool isGlobalScope) { - switch (sym.kind()) { +static bool symbolGoesInModuleStream(const CVSymbol &Sym, bool IsGlobalScope) { + switch (Sym.kind()) { case SymbolKind::S_GDATA32: case SymbolKind::S_CONSTANT: // We really should not be seeing S_PROCREF and S_LPROCREF in the first place @@ -767,7 +767,7 @@ static bool symbolGoesInModuleStream(const CVSymbol &sym, bool isGlobalScope) { return false; // S_UDT records go in the module stream if it is not a global S_UDT. case SymbolKind::S_UDT: - return !isGlobalScope; + return !IsGlobalScope; // S_GDATA32 does not go in the module stream, but S_LDATA32 does. case SymbolKind::S_LDATA32: default: @@ -775,8 +775,8 @@ static bool symbolGoesInModuleStream(const CVSymbol &sym, bool isGlobalScope) { } } -static bool symbolGoesInGlobalsStream(const CVSymbol &sym, bool isGlobalScope) { - switch (sym.kind()) { +static bool symbolGoesInGlobalsStream(const CVSymbol &Sym, bool IsGlobalScope) { + switch (Sym.kind()) { case SymbolKind::S_CONSTANT: case SymbolKind::S_GDATA32: // S_LDATA32 goes in both the module stream and the globals stream. @@ -791,36 +791,36 @@ static bool symbolGoesInGlobalsStream(const CVSymbol &sym, bool isGlobalScope) { return true; // S_UDT records go in the globals stream if it is a global S_UDT. case SymbolKind::S_UDT: - return isGlobalScope; + return IsGlobalScope; default: return false; } } -static void addGlobalSymbol(pdb::GSIStreamBuilder &builder, uint16_t modIndex, - unsigned symOffset, const CVSymbol &sym) { - switch (sym.kind()) { +static void addGlobalSymbol(pdb::GSIStreamBuilder &Builder, uint16_t ModIndex, + unsigned SymOffset, const CVSymbol &Sym) { + switch (Sym.kind()) { case SymbolKind::S_CONSTANT: case SymbolKind::S_UDT: case SymbolKind::S_GDATA32: case SymbolKind::S_LDATA32: case SymbolKind::S_PROCREF: case SymbolKind::S_LPROCREF: - builder.addGlobalSymbol(sym); + Builder.addGlobalSymbol(Sym); break; case SymbolKind::S_GPROC32: case SymbolKind::S_LPROC32: { - SymbolRecordKind k = SymbolRecordKind::ProcRefSym; - if (sym.kind() == SymbolKind::S_LPROC32) - k = SymbolRecordKind::LocalProcRef; - ProcRefSym ps(k); - ps.Module = modIndex; + SymbolRecordKind K = SymbolRecordKind::ProcRefSym; + if (Sym.kind() == SymbolKind::S_LPROC32) + K = SymbolRecordKind::LocalProcRef; + ProcRefSym PS(K); + PS.Module = ModIndex; // For some reason, MSVC seems to add one to this value. - ++ps.Module; - ps.Name = getSymbolName(sym); - ps.SumName = 0; - ps.SymOffset = symOffset; - builder.addGlobalSymbol(ps); + ++PS.Module; + PS.Name = getSymbolName(Sym); + PS.SumName = 0; + PS.SymOffset = SymOffset; + Builder.addGlobalSymbol(PS); break; } default: @@ -828,219 +828,219 @@ static void addGlobalSymbol(pdb::GSIStreamBuilder &builder, uint16_t modIndex, } } -void PDBLinker::mergeSymbolRecords(ObjFile *file, const CVIndexMap &indexMap, - std::vector &stringTableRefs, - BinaryStreamRef symData) { - ArrayRef symsBuffer; - cantFail(symData.readBytes(0, symData.getLength(), symsBuffer)); - SmallVector scopes; +void PDBLinker::mergeSymbolRecords(ObjFile *File, const CVIndexMap &IndexMap, + std::vector &StringTableRefs, + BinaryStreamRef SymData) { + ArrayRef SymsBuffer; + cantFail(SymData.readBytes(0, SymData.getLength(), SymsBuffer)); + SmallVector Scopes; // Iterate every symbol to check if any need to be realigned, and if so, how // much space we need to allocate for them. - bool needsRealignment = false; - unsigned totalRealignedSize = 0; - auto ec = forEachCodeViewRecord( - symsBuffer, [&](CVSymbol sym) -> llvm::Error { - unsigned realignedSize = - alignTo(sym.length(), alignOf(CodeViewContainer::Pdb)); - needsRealignment |= realignedSize != sym.length(); - totalRealignedSize += realignedSize; + bool NeedsRealignment = false; + unsigned TotalRealignedSize = 0; + auto EC = forEachCodeViewRecord( + SymsBuffer, [&](CVSymbol Sym) -> llvm::Error { + unsigned RealignedSize = + alignTo(Sym.length(), alignOf(CodeViewContainer::Pdb)); + NeedsRealignment |= RealignedSize != Sym.length(); + TotalRealignedSize += RealignedSize; return Error::success(); }); // If any of the symbol record lengths was corrupt, ignore them all, warn // about it, and move on. - if (ec) { - warn("corrupt symbol records in " + file->getName()); - consumeError(std::move(ec)); + if (EC) { + warn("corrupt symbol records in " + File->getName()); + consumeError(std::move(EC)); return; } // If any symbol needed realignment, allocate enough contiguous memory for // them all. Typically symbol subsections are small enough that this will not // cause fragmentation. - MutableArrayRef alignedSymbolMem; - if (needsRealignment) { - void *alignedData = - alloc.Allocate(totalRealignedSize, alignOf(CodeViewContainer::Pdb)); - alignedSymbolMem = makeMutableArrayRef( - reinterpret_cast(alignedData), totalRealignedSize); + MutableArrayRef AlignedSymbolMem; + if (NeedsRealignment) { + void *AlignedData = + Alloc.Allocate(TotalRealignedSize, alignOf(CodeViewContainer::Pdb)); + AlignedSymbolMem = makeMutableArrayRef( + reinterpret_cast(AlignedData), TotalRealignedSize); } // Iterate again, this time doing the real work. - unsigned curSymOffset = file->moduleDBI->getNextSymbolOffset(); - ArrayRef bulkSymbols; + unsigned CurSymOffset = File->ModuleDBI->getNextSymbolOffset(); + ArrayRef BulkSymbols; cantFail(forEachCodeViewRecord( - symsBuffer, [&](CVSymbol sym) -> llvm::Error { + SymsBuffer, [&](CVSymbol Sym) -> llvm::Error { // Align the record if required. - MutableArrayRef recordBytes; - if (needsRealignment) { - recordBytes = copyAndAlignSymbol(sym, alignedSymbolMem); - sym = CVSymbol(recordBytes); + MutableArrayRef RecordBytes; + if (NeedsRealignment) { + RecordBytes = copyAndAlignSymbol(Sym, AlignedSymbolMem); + Sym = CVSymbol(RecordBytes); } else { // Otherwise, we can actually mutate the symbol directly, since we // copied it to apply relocations. - recordBytes = makeMutableArrayRef( - const_cast(sym.data().data()), sym.length()); + RecordBytes = makeMutableArrayRef( + const_cast(Sym.data().data()), Sym.length()); } // Discover type index references in the record. Skip it if we don't // know where they are. - SmallVector typeRefs; - if (!discoverTypeIndicesInSymbol(sym, typeRefs)) { + SmallVector TypeRefs; + if (!discoverTypeIndicesInSymbol(Sym, TypeRefs)) { log("ignoring unknown symbol record with kind 0x" + - utohexstr(sym.kind())); + utohexstr(Sym.kind())); return Error::success(); } // Re-map all the type index references. - remapTypesInSymbolRecord(file, sym.kind(), recordBytes, indexMap, - typeRefs); + remapTypesInSymbolRecord(File, Sym.kind(), RecordBytes, IndexMap, + TypeRefs); // An object file may have S_xxx_ID symbols, but these get converted to // "real" symbols in a PDB. - translateIdSymbols(recordBytes, tMerger.getIDTable()); - sym = CVSymbol(recordBytes); + translateIdSymbols(RecordBytes, TMerger.getIDTable()); + Sym = CVSymbol(RecordBytes); // If this record refers to an offset in the object file's string table, // add that item to the global PDB string table and re-write the index. - recordStringTableReferences(sym.kind(), recordBytes, stringTableRefs); + recordStringTableReferences(Sym.kind(), RecordBytes, StringTableRefs); // Fill in "Parent" and "End" fields by maintaining a stack of scopes. - if (symbolOpensScope(sym.kind())) - scopeStackOpen(scopes, curSymOffset, sym); - else if (symbolEndsScope(sym.kind())) - scopeStackClose(scopes, curSymOffset, file); + if (symbolOpensScope(Sym.kind())) + scopeStackOpen(Scopes, CurSymOffset, Sym); + else if (symbolEndsScope(Sym.kind())) + scopeStackClose(Scopes, CurSymOffset, File); // Add the symbol to the globals stream if necessary. Do this before // adding the symbol to the module since we may need to get the next // symbol offset, and writing to the module's symbol stream will update // that offset. - if (symbolGoesInGlobalsStream(sym, scopes.empty())) { - addGlobalSymbol(builder.getGsiBuilder(), - file->moduleDBI->getModuleIndex(), curSymOffset, sym); - ++globalSymbols; + if (symbolGoesInGlobalsStream(Sym, Scopes.empty())) { + addGlobalSymbol(Builder.getGsiBuilder(), + File->ModuleDBI->getModuleIndex(), CurSymOffset, Sym); + ++GlobalSymbols; } - if (symbolGoesInModuleStream(sym, scopes.empty())) { + if (symbolGoesInModuleStream(Sym, Scopes.empty())) { // Add symbols to the module in bulk. If this symbol is contiguous // with the previous run of symbols to add, combine the ranges. If // not, close the previous range of symbols and start a new one. - if (sym.data().data() == bulkSymbols.end()) { - bulkSymbols = makeArrayRef(bulkSymbols.data(), - bulkSymbols.size() + sym.length()); + if (Sym.data().data() == BulkSymbols.end()) { + BulkSymbols = makeArrayRef(BulkSymbols.data(), + BulkSymbols.size() + Sym.length()); } else { - file->moduleDBI->addSymbolsInBulk(bulkSymbols); - bulkSymbols = recordBytes; + File->ModuleDBI->addSymbolsInBulk(BulkSymbols); + BulkSymbols = RecordBytes; } - curSymOffset += sym.length(); - ++moduleSymbols; + CurSymOffset += Sym.length(); + ++ModuleSymbols; } return Error::success(); })); // Add any remaining symbols we've accumulated. - file->moduleDBI->addSymbolsInBulk(bulkSymbols); + File->ModuleDBI->addSymbolsInBulk(BulkSymbols); } // Allocate memory for a .debug$S / .debug$F section and relocate it. -static ArrayRef relocateDebugChunk(BumpPtrAllocator &alloc, - SectionChunk &debugChunk) { - uint8_t *buffer = alloc.Allocate(debugChunk.getSize()); - assert(debugChunk.getOutputSectionIdx() == 0 && +static ArrayRef relocateDebugChunk(BumpPtrAllocator &Alloc, + SectionChunk &DebugChunk) { + uint8_t *Buffer = Alloc.Allocate(DebugChunk.getSize()); + assert(DebugChunk.getOutputSectionIdx() == 0 && "debug sections should not be in output sections"); - debugChunk.writeTo(buffer); - return makeArrayRef(buffer, debugChunk.getSize()); + DebugChunk.writeTo(Buffer); + return makeArrayRef(Buffer, DebugChunk.getSize()); } -static pdb::SectionContrib createSectionContrib(const Chunk *c, uint32_t modi) { - OutputSection *os = c ? c->getOutputSection() : nullptr; - pdb::SectionContrib sc; - memset(&sc, 0, sizeof(sc)); - sc.ISect = os ? os->sectionIndex : llvm::pdb::kInvalidStreamIndex; - sc.Off = c && os ? c->getRVA() - os->getRVA() : 0; - sc.Size = c ? c->getSize() : -1; - if (auto *secChunk = dyn_cast_or_null(c)) { - sc.Characteristics = secChunk->header->Characteristics; - sc.Imod = secChunk->file->moduleDBI->getModuleIndex(); - ArrayRef contents = secChunk->getContents(); - JamCRC crc(0); - ArrayRef charContents = makeArrayRef( - reinterpret_cast(contents.data()), contents.size()); - crc.update(charContents); - sc.DataCrc = crc.getCRC(); +static pdb::SectionContrib createSectionContrib(const Chunk *C, uint32_t Modi) { + OutputSection *OS = C ? C->getOutputSection() : nullptr; + pdb::SectionContrib SC; + memset(&SC, 0, sizeof(SC)); + SC.ISect = OS ? OS->SectionIndex : llvm::pdb::kInvalidStreamIndex; + SC.Off = C && OS ? C->getRVA() - OS->getRVA() : 0; + SC.Size = C ? C->getSize() : -1; + if (auto *SecChunk = dyn_cast_or_null(C)) { + SC.Characteristics = SecChunk->Header->Characteristics; + SC.Imod = SecChunk->File->ModuleDBI->getModuleIndex(); + ArrayRef Contents = SecChunk->getContents(); + JamCRC CRC(0); + ArrayRef CharContents = makeArrayRef( + reinterpret_cast(Contents.data()), Contents.size()); + CRC.update(CharContents); + SC.DataCrc = CRC.getCRC(); } else { - sc.Characteristics = os ? os->header.Characteristics : 0; - sc.Imod = modi; + SC.Characteristics = OS ? OS->Header.Characteristics : 0; + SC.Imod = Modi; } - sc.RelocCrc = 0; // FIXME + SC.RelocCrc = 0; // FIXME - return sc; + return SC; } static uint32_t -translateStringTableIndex(uint32_t objIndex, - const DebugStringTableSubsectionRef &objStrTable, - DebugStringTableSubsection &pdbStrTable) { - auto expectedString = objStrTable.getString(objIndex); - if (!expectedString) { +translateStringTableIndex(uint32_t ObjIndex, + const DebugStringTableSubsectionRef &ObjStrTable, + DebugStringTableSubsection &PdbStrTable) { + auto ExpectedString = ObjStrTable.getString(ObjIndex); + if (!ExpectedString) { warn("Invalid string table reference"); - consumeError(expectedString.takeError()); + consumeError(ExpectedString.takeError()); return 0; } - return pdbStrTable.insert(*expectedString); + return PdbStrTable.insert(*ExpectedString); } -void DebugSHandler::handleDebugS(lld::coff::SectionChunk &debugS) { - DebugSubsectionArray subsections; +void DebugSHandler::handleDebugS(lld::coff::SectionChunk &DebugS) { + DebugSubsectionArray Subsections; - ArrayRef relocatedDebugContents = SectionChunk::consumeDebugMagic( - relocateDebugChunk(linker.alloc, debugS), debugS.getSectionName()); + ArrayRef RelocatedDebugContents = SectionChunk::consumeDebugMagic( + relocateDebugChunk(Linker.Alloc, DebugS), DebugS.getSectionName()); - BinaryStreamReader reader(relocatedDebugContents, support::little); - exitOnErr(reader.readArray(subsections, relocatedDebugContents.size())); + BinaryStreamReader Reader(RelocatedDebugContents, support::little); + ExitOnErr(Reader.readArray(Subsections, RelocatedDebugContents.size())); - for (const DebugSubsectionRecord &ss : subsections) { + for (const DebugSubsectionRecord &SS : Subsections) { // Ignore subsections with the 'ignore' bit. Some versions of the Visual C++ // runtime have subsections with this bit set. - if (uint32_t(ss.kind()) & codeview::SubsectionIgnoreFlag) + if (uint32_t(SS.kind()) & codeview::SubsectionIgnoreFlag) continue; - switch (ss.kind()) { + switch (SS.kind()) { case DebugSubsectionKind::StringTable: { - assert(!cVStrTab.valid() && + assert(!CVStrTab.valid() && "Encountered multiple string table subsections!"); - exitOnErr(cVStrTab.initialize(ss.getRecordData())); + ExitOnErr(CVStrTab.initialize(SS.getRecordData())); break; } case DebugSubsectionKind::FileChecksums: - assert(!checksums.valid() && + assert(!Checksums.valid() && "Encountered multiple checksum subsections!"); - exitOnErr(checksums.initialize(ss.getRecordData())); + ExitOnErr(Checksums.initialize(SS.getRecordData())); break; case DebugSubsectionKind::Lines: // We can add the relocated line table directly to the PDB without // modification because the file checksum offsets will stay the same. - file.moduleDBI->addDebugSubsection(ss); + File.ModuleDBI->addDebugSubsection(SS); break; case DebugSubsectionKind::InlineeLines: - assert(!inlineeLines.valid() && + assert(!InlineeLines.valid() && "Encountered multiple inlinee lines subsections!"); - exitOnErr(inlineeLines.initialize(ss.getRecordData())); + ExitOnErr(InlineeLines.initialize(SS.getRecordData())); break; case DebugSubsectionKind::FrameData: { // We need to re-write string table indices here, so save off all // frame data subsections until we've processed the entire list of // subsections so that we can be sure we have the string table. - DebugFrameDataSubsectionRef fds; - exitOnErr(fds.initialize(ss.getRecordData())); - newFpoFrames.push_back(std::move(fds)); + DebugFrameDataSubsectionRef FDS; + ExitOnErr(FDS.initialize(SS.getRecordData())); + NewFpoFrames.push_back(std::move(FDS)); break; } case DebugSubsectionKind::Symbols: { - linker.mergeSymbolRecords(&file, indexMap, stringTableReferences, - ss.getRecordData()); + Linker.mergeSymbolRecords(&File, IndexMap, StringTableReferences, + SS.getRecordData()); break; } @@ -1063,69 +1063,69 @@ void DebugSHandler::handleDebugS(lld::coff::SectionChunk &debugS) { default: warn("ignoring unknown debug$S subsection kind 0x" + - utohexstr(uint32_t(ss.kind())) + " in file " + toString(&file)); + utohexstr(uint32_t(SS.kind())) + " in file " + toString(&File)); break; } } } static Expected -getFileName(const DebugStringTableSubsectionRef &strings, - const DebugChecksumsSubsectionRef &checksums, uint32_t fileID) { - auto iter = checksums.getArray().at(fileID); - if (iter == checksums.getArray().end()) +getFileName(const DebugStringTableSubsectionRef &Strings, + const DebugChecksumsSubsectionRef &Checksums, uint32_t FileID) { + auto Iter = Checksums.getArray().at(FileID); + if (Iter == Checksums.getArray().end()) return make_error(cv_error_code::no_records); - uint32_t offset = iter->FileNameOffset; - return strings.getString(offset); + uint32_t Offset = Iter->FileNameOffset; + return Strings.getString(Offset); } std::shared_ptr -DebugSHandler::mergeInlineeLines(DebugChecksumsSubsection *newChecksums) { - auto newInlineeLines = std::make_shared( - *newChecksums, inlineeLines.hasExtraFiles()); - - for (const InlineeSourceLine &line : inlineeLines) { - TypeIndex inlinee = line.Header->Inlinee; - uint32_t fileID = line.Header->FileID; - uint32_t sourceLine = line.Header->SourceLineNum; - - ArrayRef typeOrItemMap = - indexMap.isTypeServerMap ? indexMap.ipiMap : indexMap.tpiMap; - if (!remapTypeIndex(inlinee, typeOrItemMap)) { - log("ignoring inlinee line record in " + file.getName() + - " with bad inlinee index 0x" + utohexstr(inlinee.getIndex())); +DebugSHandler::mergeInlineeLines(DebugChecksumsSubsection *NewChecksums) { + auto NewInlineeLines = std::make_shared( + *NewChecksums, InlineeLines.hasExtraFiles()); + + for (const InlineeSourceLine &Line : InlineeLines) { + TypeIndex Inlinee = Line.Header->Inlinee; + uint32_t FileID = Line.Header->FileID; + uint32_t SourceLine = Line.Header->SourceLineNum; + + ArrayRef TypeOrItemMap = + IndexMap.IsTypeServerMap ? IndexMap.IPIMap : IndexMap.TPIMap; + if (!remapTypeIndex(Inlinee, TypeOrItemMap)) { + log("ignoring inlinee line record in " + File.getName() + + " with bad inlinee index 0x" + utohexstr(Inlinee.getIndex())); continue; } - SmallString<128> filename = - exitOnErr(getFileName(cVStrTab, checksums, fileID)); - pdbMakeAbsolute(filename); - newInlineeLines->addInlineSite(inlinee, filename, sourceLine); + SmallString<128> Filename = + ExitOnErr(getFileName(CVStrTab, Checksums, FileID)); + pdbMakeAbsolute(Filename); + NewInlineeLines->addInlineSite(Inlinee, Filename, SourceLine); - if (inlineeLines.hasExtraFiles()) { - for (uint32_t extraFileId : line.ExtraFiles) { - filename = exitOnErr(getFileName(cVStrTab, checksums, extraFileId)); - pdbMakeAbsolute(filename); - newInlineeLines->addExtraFile(filename); + if (InlineeLines.hasExtraFiles()) { + for (uint32_t ExtraFileId : Line.ExtraFiles) { + Filename = ExitOnErr(getFileName(CVStrTab, Checksums, ExtraFileId)); + pdbMakeAbsolute(Filename); + NewInlineeLines->addExtraFile(Filename); } } } - return newInlineeLines; + return NewInlineeLines; } void DebugSHandler::finish() { - pdb::DbiStreamBuilder &dbiBuilder = linker.builder.getDbiBuilder(); + pdb::DbiStreamBuilder &DbiBuilder = Linker.Builder.getDbiBuilder(); // We should have seen all debug subsections across the entire object file now // which means that if a StringTable subsection and Checksums subsection were // present, now is the time to handle them. - if (!cVStrTab.valid()) { - if (checksums.valid()) + if (!CVStrTab.valid()) { + if (Checksums.valid()) fatal(".debug$S sections with a checksums subsection must also contain a " "string table subsection"); - if (!stringTableReferences.empty()) + if (!StringTableReferences.empty()) warn("No StringTable subsection was encountered, but there are string " "table references"); return; @@ -1133,231 +1133,231 @@ void DebugSHandler::finish() { // Rewrite string table indices in the Fpo Data and symbol records to refer to // the global PDB string table instead of the object file string table. - for (DebugFrameDataSubsectionRef &fds : newFpoFrames) { - const ulittle32_t *reloc = fds.getRelocPtr(); - for (codeview::FrameData fd : fds) { - fd.RvaStart += *reloc; - fd.FrameFunc = - translateStringTableIndex(fd.FrameFunc, cVStrTab, linker.pdbStrTab); - dbiBuilder.addNewFpoData(fd); + for (DebugFrameDataSubsectionRef &FDS : NewFpoFrames) { + const ulittle32_t *Reloc = FDS.getRelocPtr(); + for (codeview::FrameData FD : FDS) { + FD.RvaStart += *Reloc; + FD.FrameFunc = + translateStringTableIndex(FD.FrameFunc, CVStrTab, Linker.PDBStrTab); + DbiBuilder.addNewFpoData(FD); } } - for (ulittle32_t *ref : stringTableReferences) - *ref = translateStringTableIndex(*ref, cVStrTab, linker.pdbStrTab); + for (ulittle32_t *Ref : StringTableReferences) + *Ref = translateStringTableIndex(*Ref, CVStrTab, Linker.PDBStrTab); // Make a new file checksum table that refers to offsets in the PDB-wide // string table. Generally the string table subsection appears after the // checksum table, so we have to do this after looping over all the // subsections. - auto newChecksums = std::make_unique(linker.pdbStrTab); - for (FileChecksumEntry &fc : checksums) { - SmallString<128> filename = - exitOnErr(cVStrTab.getString(fc.FileNameOffset)); - pdbMakeAbsolute(filename); - exitOnErr(dbiBuilder.addModuleSourceFile(*file.moduleDBI, filename)); - newChecksums->addChecksum(filename, fc.Kind, fc.Checksum); + auto NewChecksums = make_unique(Linker.PDBStrTab); + for (FileChecksumEntry &FC : Checksums) { + SmallString<128> Filename = + ExitOnErr(CVStrTab.getString(FC.FileNameOffset)); + pdbMakeAbsolute(Filename); + ExitOnErr(DbiBuilder.addModuleSourceFile(*File.ModuleDBI, Filename)); + NewChecksums->addChecksum(Filename, FC.Kind, FC.Checksum); } // Rewrite inlinee item indices if present. - if (inlineeLines.valid()) - file.moduleDBI->addDebugSubsection(mergeInlineeLines(newChecksums.get())); + if (InlineeLines.valid()) + File.ModuleDBI->addDebugSubsection(mergeInlineeLines(NewChecksums.get())); - file.moduleDBI->addDebugSubsection(std::move(newChecksums)); + File.ModuleDBI->addDebugSubsection(std::move(NewChecksums)); } -void PDBLinker::addObjFile(ObjFile *file, CVIndexMap *externIndexMap) { - if (file->mergedIntoPDB) +void PDBLinker::addObjFile(ObjFile *File, CVIndexMap *ExternIndexMap) { + if (File->MergedIntoPDB) return; - file->mergedIntoPDB = true; + File->MergedIntoPDB = true; // Before we can process symbol substreams from .debug$S, we need to process // type information, file checksums, and the string table. Add type info to // the PDB first, so that we can get the map from object file type and item // indices to PDB type and item indices. - CVIndexMap objectIndexMap; - auto indexMapResult = - mergeDebugT(file, externIndexMap ? externIndexMap : &objectIndexMap); + CVIndexMap ObjectIndexMap; + auto IndexMapResult = + mergeDebugT(File, ExternIndexMap ? ExternIndexMap : &ObjectIndexMap); // If the .debug$T sections fail to merge, assume there is no debug info. - if (!indexMapResult) { - if (!config->warnDebugInfoUnusable) { - consumeError(indexMapResult.takeError()); + if (!IndexMapResult) { + if (!Config->WarnDebugInfoUnusable) { + consumeError(IndexMapResult.takeError()); return; } - warn("Cannot use debug info for '" + toString(file) + "' [LNK4099]\n" + + warn("Cannot use debug info for '" + toString(File) + "' [LNK4099]\n" + ">>> failed to load reference " + - StringRef(toString(indexMapResult.takeError()))); + StringRef(toString(IndexMapResult.takeError()))); return; } - ScopedTimer t(symbolMergingTimer); + ScopedTimer T(SymbolMergingTimer); - pdb::DbiStreamBuilder &dbiBuilder = builder.getDbiBuilder(); - DebugSHandler dsh(*this, *file, *indexMapResult); + pdb::DbiStreamBuilder &DbiBuilder = Builder.getDbiBuilder(); + DebugSHandler DSH(*this, *File, *IndexMapResult); // Now do all live .debug$S and .debug$F sections. - for (SectionChunk *debugChunk : file->getDebugChunks()) { - if (!debugChunk->live || debugChunk->getSize() == 0) + for (SectionChunk *DebugChunk : File->getDebugChunks()) { + if (!DebugChunk->Live || DebugChunk->getSize() == 0) continue; - if (debugChunk->getSectionName() == ".debug$S") { - dsh.handleDebugS(*debugChunk); + if (DebugChunk->getSectionName() == ".debug$S") { + DSH.handleDebugS(*DebugChunk); continue; } - if (debugChunk->getSectionName() == ".debug$F") { - ArrayRef relocatedDebugContents = - relocateDebugChunk(alloc, *debugChunk); + if (DebugChunk->getSectionName() == ".debug$F") { + ArrayRef RelocatedDebugContents = + relocateDebugChunk(Alloc, *DebugChunk); - FixedStreamArray fpoRecords; - BinaryStreamReader reader(relocatedDebugContents, support::little); - uint32_t count = relocatedDebugContents.size() / sizeof(object::FpoData); - exitOnErr(reader.readArray(fpoRecords, count)); + FixedStreamArray FpoRecords; + BinaryStreamReader Reader(RelocatedDebugContents, support::little); + uint32_t Count = RelocatedDebugContents.size() / sizeof(object::FpoData); + ExitOnErr(Reader.readArray(FpoRecords, Count)); // These are already relocated and don't refer to the string table, so we // can just copy it. - for (const object::FpoData &fd : fpoRecords) - dbiBuilder.addOldFpoData(fd); + for (const object::FpoData &FD : FpoRecords) + DbiBuilder.addOldFpoData(FD); continue; } } // Do any post-processing now that all .debug$S sections have been processed. - dsh.finish(); + DSH.finish(); } // Add a module descriptor for every object file. We need to put an absolute // path to the object into the PDB. If this is a plain object, we make its // path absolute. If it's an object in an archive, we make the archive path // absolute. -static void createModuleDBI(pdb::PDBFileBuilder &builder) { - pdb::DbiStreamBuilder &dbiBuilder = builder.getDbiBuilder(); - SmallString<128> objName; +static void createModuleDBI(pdb::PDBFileBuilder &Builder) { + pdb::DbiStreamBuilder &DbiBuilder = Builder.getDbiBuilder(); + SmallString<128> ObjName; - for (ObjFile *file : ObjFile::instances) { + for (ObjFile *File : ObjFile::Instances) { - bool inArchive = !file->parentName.empty(); - objName = inArchive ? file->parentName : file->getName(); - pdbMakeAbsolute(objName); - StringRef modName = inArchive ? file->getName() : StringRef(objName); + bool InArchive = !File->ParentName.empty(); + ObjName = InArchive ? File->ParentName : File->getName(); + pdbMakeAbsolute(ObjName); + StringRef ModName = InArchive ? File->getName() : StringRef(ObjName); - file->moduleDBI = &exitOnErr(dbiBuilder.addModuleInfo(modName)); - file->moduleDBI->setObjFileName(objName); + File->ModuleDBI = &ExitOnErr(DbiBuilder.addModuleInfo(ModName)); + File->ModuleDBI->setObjFileName(ObjName); - ArrayRef chunks = file->getChunks(); - uint32_t modi = file->moduleDBI->getModuleIndex(); + ArrayRef Chunks = File->getChunks(); + uint32_t Modi = File->ModuleDBI->getModuleIndex(); - for (Chunk *c : chunks) { - auto *secChunk = dyn_cast(c); - if (!secChunk || !secChunk->live) + for (Chunk *C : Chunks) { + auto *SecChunk = dyn_cast(C); + if (!SecChunk || !SecChunk->Live) continue; - pdb::SectionContrib sc = createSectionContrib(secChunk, modi); - file->moduleDBI->setFirstSectionContrib(sc); + pdb::SectionContrib SC = createSectionContrib(SecChunk, Modi); + File->ModuleDBI->setFirstSectionContrib(SC); break; } } } -static PublicSym32 createPublic(Defined *def) { - PublicSym32 pub(SymbolKind::S_PUB32); - pub.Name = def->getName(); - if (auto *d = dyn_cast(def)) { - if (d->getCOFFSymbol().isFunctionDefinition()) - pub.Flags = PublicSymFlags::Function; - } else if (isa(def)) { - pub.Flags = PublicSymFlags::Function; +static PublicSym32 createPublic(Defined *Def) { + PublicSym32 Pub(SymbolKind::S_PUB32); + Pub.Name = Def->getName(); + if (auto *D = dyn_cast(Def)) { + if (D->getCOFFSymbol().isFunctionDefinition()) + Pub.Flags = PublicSymFlags::Function; + } else if (isa(Def)) { + Pub.Flags = PublicSymFlags::Function; } - OutputSection *os = def->getChunk()->getOutputSection(); - assert(os && "all publics should be in final image"); - pub.Offset = def->getRVA() - os->getRVA(); - pub.Segment = os->sectionIndex; - return pub; + OutputSection *OS = Def->getChunk()->getOutputSection(); + assert(OS && "all publics should be in final image"); + Pub.Offset = Def->getRVA() - OS->getRVA(); + Pub.Segment = OS->SectionIndex; + return Pub; } // Add all object files to the PDB. Merge .debug$T sections into IpiData and // TpiData. void PDBLinker::addObjectsToPDB() { - ScopedTimer t1(addObjectsTimer); + ScopedTimer T1(AddObjectsTimer); - createModuleDBI(builder); + createModuleDBI(Builder); - for (ObjFile *file : ObjFile::instances) - addObjFile(file); + for (ObjFile *File : ObjFile::Instances) + addObjFile(File); - builder.getStringTableBuilder().setStrings(pdbStrTab); - t1.stop(); + Builder.getStringTableBuilder().setStrings(PDBStrTab); + T1.stop(); // Construct TPI and IPI stream contents. - ScopedTimer t2(tpiStreamLayoutTimer); - addTypeInfo(builder.getTpiBuilder(), tMerger.getTypeTable()); - addTypeInfo(builder.getIpiBuilder(), tMerger.getIDTable()); - t2.stop(); + ScopedTimer T2(TpiStreamLayoutTimer); + addTypeInfo(Builder.getTpiBuilder(), TMerger.getTypeTable()); + addTypeInfo(Builder.getIpiBuilder(), TMerger.getIDTable()); + T2.stop(); - ScopedTimer t3(globalsLayoutTimer); + ScopedTimer T3(GlobalsLayoutTimer); // Compute the public and global symbols. - auto &gsiBuilder = builder.getGsiBuilder(); - std::vector publics; - symtab->forEachSymbol([&publics](Symbol *s) { + auto &GsiBuilder = Builder.getGsiBuilder(); + std::vector Publics; + Symtab->forEachSymbol([&Publics](Symbol *S) { // Only emit defined, live symbols that have a chunk. - auto *def = dyn_cast(s); - if (def && def->isLive() && def->getChunk()) - publics.push_back(createPublic(def)); + auto *Def = dyn_cast(S); + if (Def && Def->isLive() && Def->getChunk()) + Publics.push_back(createPublic(Def)); }); - if (!publics.empty()) { - publicSymbols = publics.size(); + if (!Publics.empty()) { + PublicSymbols = Publics.size(); // Sort the public symbols and add them to the stream. - parallelSort(publics, [](const PublicSym32 &l, const PublicSym32 &r) { - return l.Name < r.Name; + parallelSort(Publics, [](const PublicSym32 &L, const PublicSym32 &R) { + return L.Name < R.Name; }); - for (const PublicSym32 &pub : publics) - gsiBuilder.addPublicSymbol(pub); + for (const PublicSym32 &Pub : Publics) + GsiBuilder.addPublicSymbol(Pub); } } void PDBLinker::printStats() { - if (!config->showSummary) + if (!Config->ShowSummary) return; - SmallString<256> buffer; - raw_svector_ostream stream(buffer); + SmallString<256> Buffer; + raw_svector_ostream Stream(Buffer); - stream << center_justify("Summary", 80) << '\n' + Stream << center_justify("Summary", 80) << '\n' << std::string(80, '-') << '\n'; - auto print = [&](uint64_t v, StringRef s) { - stream << format_decimal(v, 15) << " " << s << '\n'; + auto Print = [&](uint64_t V, StringRef S) { + Stream << format_decimal(V, 15) << " " << S << '\n'; }; - print(ObjFile::instances.size(), + Print(ObjFile::Instances.size(), "Input OBJ files (expanded from all cmd-line inputs)"); - print(typeServerIndexMappings.size(), "PDB type server dependencies"); - print(precompTypeIndexMappings.size(), "Precomp OBJ dependencies"); - print(tMerger.getTypeTable().size() + tMerger.getIDTable().size(), + Print(TypeServerIndexMappings.size(), "PDB type server dependencies"); + Print(PrecompTypeIndexMappings.size(), "Precomp OBJ dependencies"); + Print(TMerger.getTypeTable().size() + TMerger.getIDTable().size(), "Merged TPI records"); - print(pdbStrTab.size(), "Output PDB strings"); - print(globalSymbols, "Global symbol records"); - print(moduleSymbols, "Module symbol records"); - print(publicSymbols, "Public symbol records"); + Print(PDBStrTab.size(), "Output PDB strings"); + Print(GlobalSymbols, "Global symbol records"); + Print(ModuleSymbols, "Module symbol records"); + Print(PublicSymbols, "Public symbol records"); - message(buffer); + message(Buffer); } void PDBLinker::addNatvisFiles() { - for (StringRef file : config->natvisFiles) { - ErrorOr> dataOrErr = - MemoryBuffer::getFile(file); - if (!dataOrErr) { - warn("Cannot open input file: " + file); + for (StringRef File : Config->NatvisFiles) { + ErrorOr> DataOrErr = + MemoryBuffer::getFile(File); + if (!DataOrErr) { + warn("Cannot open input file: " + File); continue; } - builder.addInjectedSource(file, std::move(*dataOrErr)); + Builder.addInjectedSource(File, std::move(*DataOrErr)); } } -static codeview::CPUType toCodeViewMachine(COFF::MachineTypes machine) { - switch (machine) { +static codeview::CPUType toCodeViewMachine(COFF::MachineTypes Machine) { + switch (Machine) { case COFF::IMAGE_FILE_MACHINE_AMD64: return codeview::CPUType::X64; case COFF::IMAGE_FILE_MACHINE_ARM: @@ -1376,330 +1376,329 @@ static codeview::CPUType toCodeViewMachine(COFF::MachineTypes machine) { // Mimic MSVC which surrounds arguments containing whitespace with quotes. // Double double-quotes are handled, so that the resulting string can be // executed again on the cmd-line. -static std::string quote(ArrayRef args) { - std::string r; - r.reserve(256); - for (StringRef a : args) { - if (!r.empty()) - r.push_back(' '); - bool hasWS = a.find(' ') != StringRef::npos; - bool hasQ = a.find('"') != StringRef::npos; - if (hasWS || hasQ) - r.push_back('"'); - if (hasQ) { - SmallVector s; - a.split(s, '"'); - r.append(join(s, "\"\"")); +static std::string quote(ArrayRef Args) { + std::string R; + R.reserve(256); + for (StringRef A : Args) { + if (!R.empty()) + R.push_back(' '); + bool HasWS = A.find(' ') != StringRef::npos; + bool HasQ = A.find('"') != StringRef::npos; + if (HasWS || HasQ) + R.push_back('"'); + if (HasQ) { + SmallVector S; + A.split(S, '"'); + R.append(join(S, "\"\"")); } else { - r.append(a); + R.append(A); } - if (hasWS || hasQ) - r.push_back('"'); + if (HasWS || HasQ) + R.push_back('"'); } - return r; + return R; } -static void fillLinkerVerRecord(Compile3Sym &cs) { - cs.Machine = toCodeViewMachine(config->machine); +static void fillLinkerVerRecord(Compile3Sym &CS) { + CS.Machine = toCodeViewMachine(Config->Machine); // Interestingly, if we set the string to 0.0.0.0, then when trying to view // local variables WinDbg emits an error that private symbols are not present. // By setting this to a valid MSVC linker version string, local variables are // displayed properly. As such, even though it is not representative of // LLVM's version information, we need this for compatibility. - cs.Flags = CompileSym3Flags::None; - cs.VersionBackendBuild = 25019; - cs.VersionBackendMajor = 14; - cs.VersionBackendMinor = 10; - cs.VersionBackendQFE = 0; + CS.Flags = CompileSym3Flags::None; + CS.VersionBackendBuild = 25019; + CS.VersionBackendMajor = 14; + CS.VersionBackendMinor = 10; + CS.VersionBackendQFE = 0; // MSVC also sets the frontend to 0.0.0.0 since this is specifically for the // linker module (which is by definition a backend), so we don't need to do // anything here. Also, it seems we can use "LLVM Linker" for the linker name // without any problems. Only the backend version has to be hardcoded to a // magic number. - cs.VersionFrontendBuild = 0; - cs.VersionFrontendMajor = 0; - cs.VersionFrontendMinor = 0; - cs.VersionFrontendQFE = 0; - cs.Version = "LLVM Linker"; - cs.setLanguage(SourceLanguage::Link); + CS.VersionFrontendBuild = 0; + CS.VersionFrontendMajor = 0; + CS.VersionFrontendMinor = 0; + CS.VersionFrontendQFE = 0; + CS.Version = "LLVM Linker"; + CS.setLanguage(SourceLanguage::Link); } -static void addCommonLinkerModuleSymbols(StringRef path, - pdb::DbiModuleDescriptorBuilder &mod, - BumpPtrAllocator &allocator) { - ObjNameSym ons(SymbolRecordKind::ObjNameSym); - EnvBlockSym ebs(SymbolRecordKind::EnvBlockSym); - Compile3Sym cs(SymbolRecordKind::Compile3Sym); - fillLinkerVerRecord(cs); +static void addCommonLinkerModuleSymbols(StringRef Path, + pdb::DbiModuleDescriptorBuilder &Mod, + BumpPtrAllocator &Allocator) { + ObjNameSym ONS(SymbolRecordKind::ObjNameSym); + EnvBlockSym EBS(SymbolRecordKind::EnvBlockSym); + Compile3Sym CS(SymbolRecordKind::Compile3Sym); + fillLinkerVerRecord(CS); - ons.Name = "* Linker *"; - ons.Signature = 0; + ONS.Name = "* Linker *"; + ONS.Signature = 0; - ArrayRef args = makeArrayRef(config->argv).drop_front(); - std::string argStr = quote(args); - ebs.Fields.push_back("cwd"); + ArrayRef Args = makeArrayRef(Config->Argv).drop_front(); + std::string ArgStr = quote(Args); + EBS.Fields.push_back("cwd"); SmallString<64> cwd; - if (config->pdbSourcePath.empty()) + if (Config->PDBSourcePath.empty()) sys::fs::current_path(cwd); else - cwd = config->pdbSourcePath; - ebs.Fields.push_back(cwd); - ebs.Fields.push_back("exe"); - SmallString<64> exe = config->argv[0]; + cwd = Config->PDBSourcePath; + EBS.Fields.push_back(cwd); + EBS.Fields.push_back("exe"); + SmallString<64> exe = Config->Argv[0]; pdbMakeAbsolute(exe); - ebs.Fields.push_back(exe); - ebs.Fields.push_back("pdb"); - ebs.Fields.push_back(path); - ebs.Fields.push_back("cmd"); - ebs.Fields.push_back(argStr); - mod.addSymbol(codeview::SymbolSerializer::writeOneSymbol( - ons, allocator, CodeViewContainer::Pdb)); - mod.addSymbol(codeview::SymbolSerializer::writeOneSymbol( - cs, allocator, CodeViewContainer::Pdb)); - mod.addSymbol(codeview::SymbolSerializer::writeOneSymbol( - ebs, allocator, CodeViewContainer::Pdb)); + EBS.Fields.push_back(exe); + EBS.Fields.push_back("pdb"); + EBS.Fields.push_back(Path); + EBS.Fields.push_back("cmd"); + EBS.Fields.push_back(ArgStr); + Mod.addSymbol(codeview::SymbolSerializer::writeOneSymbol( + ONS, Allocator, CodeViewContainer::Pdb)); + Mod.addSymbol(codeview::SymbolSerializer::writeOneSymbol( + CS, Allocator, CodeViewContainer::Pdb)); + Mod.addSymbol(codeview::SymbolSerializer::writeOneSymbol( + EBS, Allocator, CodeViewContainer::Pdb)); } -static void addLinkerModuleCoffGroup(PartialSection *sec, - pdb::DbiModuleDescriptorBuilder &mod, - OutputSection &os, - BumpPtrAllocator &allocator) { +static void addLinkerModuleCoffGroup(PartialSection *Sec, + pdb::DbiModuleDescriptorBuilder &Mod, + OutputSection &OS, + BumpPtrAllocator &Allocator) { // If there's a section, there's at least one chunk - assert(!sec->chunks.empty()); - const Chunk *firstChunk = *sec->chunks.begin(); - const Chunk *lastChunk = *sec->chunks.rbegin(); + assert(!Sec->Chunks.empty()); + const Chunk *firstChunk = *Sec->Chunks.begin(); + const Chunk *lastChunk = *Sec->Chunks.rbegin(); // Emit COFF group - CoffGroupSym cgs(SymbolRecordKind::CoffGroupSym); - cgs.Name = sec->name; - cgs.Segment = os.sectionIndex; - cgs.Offset = firstChunk->getRVA() - os.getRVA(); - cgs.Size = lastChunk->getRVA() + lastChunk->getSize() - firstChunk->getRVA(); - cgs.Characteristics = sec->characteristics; + CoffGroupSym CGS(SymbolRecordKind::CoffGroupSym); + CGS.Name = Sec->Name; + CGS.Segment = OS.SectionIndex; + CGS.Offset = firstChunk->getRVA() - OS.getRVA(); + CGS.Size = lastChunk->getRVA() + lastChunk->getSize() - firstChunk->getRVA(); + CGS.Characteristics = Sec->Characteristics; // Somehow .idata sections & sections groups in the debug symbol stream have // the "write" flag set. However the section header for the corresponding // .idata section doesn't have it. - if (cgs.Name.startswith(".idata")) - cgs.Characteristics |= llvm::COFF::IMAGE_SCN_MEM_WRITE; + if (CGS.Name.startswith(".idata")) + CGS.Characteristics |= llvm::COFF::IMAGE_SCN_MEM_WRITE; - mod.addSymbol(codeview::SymbolSerializer::writeOneSymbol( - cgs, allocator, CodeViewContainer::Pdb)); + Mod.addSymbol(codeview::SymbolSerializer::writeOneSymbol( + CGS, Allocator, CodeViewContainer::Pdb)); } -static void addLinkerModuleSectionSymbol(pdb::DbiModuleDescriptorBuilder &mod, - OutputSection &os, - BumpPtrAllocator &allocator) { - SectionSym sym(SymbolRecordKind::SectionSym); - sym.Alignment = 12; // 2^12 = 4KB - sym.Characteristics = os.header.Characteristics; - sym.Length = os.getVirtualSize(); - sym.Name = os.name; - sym.Rva = os.getRVA(); - sym.SectionNumber = os.sectionIndex; - mod.addSymbol(codeview::SymbolSerializer::writeOneSymbol( - sym, allocator, CodeViewContainer::Pdb)); +static void addLinkerModuleSectionSymbol(pdb::DbiModuleDescriptorBuilder &Mod, + OutputSection &OS, + BumpPtrAllocator &Allocator) { + SectionSym Sym(SymbolRecordKind::SectionSym); + Sym.Alignment = 12; // 2^12 = 4KB + Sym.Characteristics = OS.Header.Characteristics; + Sym.Length = OS.getVirtualSize(); + Sym.Name = OS.Name; + Sym.Rva = OS.getRVA(); + Sym.SectionNumber = OS.SectionIndex; + Mod.addSymbol(codeview::SymbolSerializer::writeOneSymbol( + Sym, Allocator, CodeViewContainer::Pdb)); // Skip COFF groups in MinGW because it adds a significant footprint to the // PDB, due to each function being in its own section - if (config->mingw) + if (Config->MinGW) return; // Output COFF groups for individual chunks of this section. - for (PartialSection *sec : os.contribSections) { - addLinkerModuleCoffGroup(sec, mod, os, allocator); + for (PartialSection *Sec : OS.ContribSections) { + addLinkerModuleCoffGroup(Sec, Mod, OS, Allocator); } } // Add all import files as modules to the PDB. -void PDBLinker::addImportFilesToPDB(ArrayRef outputSections) { - if (ImportFile::instances.empty()) +void PDBLinker::addImportFilesToPDB(ArrayRef OutputSections) { + if (ImportFile::Instances.empty()) return; - std::map dllToModuleDbi; + std::map DllToModuleDbi; - for (ImportFile *file : ImportFile::instances) { - if (!file->live) + for (ImportFile *File : ImportFile::Instances) { + if (!File->Live) continue; - if (!file->thunkSym) + if (!File->ThunkSym) continue; - if (!file->thunkLive) + if (!File->ThunkLive) continue; - std::string dll = StringRef(file->dllName).lower(); - llvm::pdb::DbiModuleDescriptorBuilder *&mod = dllToModuleDbi[dll]; - if (!mod) { - pdb::DbiStreamBuilder &dbiBuilder = builder.getDbiBuilder(); - SmallString<128> libPath = file->parentName; - pdbMakeAbsolute(libPath); - sys::path::native(libPath); + std::string DLL = StringRef(File->DLLName).lower(); + llvm::pdb::DbiModuleDescriptorBuilder *&Mod = DllToModuleDbi[DLL]; + if (!Mod) { + pdb::DbiStreamBuilder &DbiBuilder = Builder.getDbiBuilder(); + SmallString<128> LibPath = File->ParentName; + pdbMakeAbsolute(LibPath); + sys::path::native(LibPath); // Name modules similar to MSVC's link.exe. // The first module is the simple dll filename - llvm::pdb::DbiModuleDescriptorBuilder &firstMod = - exitOnErr(dbiBuilder.addModuleInfo(file->dllName)); - firstMod.setObjFileName(libPath); - pdb::SectionContrib sc = + llvm::pdb::DbiModuleDescriptorBuilder &FirstMod = + ExitOnErr(DbiBuilder.addModuleInfo(File->DLLName)); + FirstMod.setObjFileName(LibPath); + pdb::SectionContrib SC = createSectionContrib(nullptr, llvm::pdb::kInvalidStreamIndex); - firstMod.setFirstSectionContrib(sc); + FirstMod.setFirstSectionContrib(SC); // The second module is where the import stream goes. - mod = &exitOnErr(dbiBuilder.addModuleInfo("Import:" + file->dllName)); - mod->setObjFileName(libPath); + Mod = &ExitOnErr(DbiBuilder.addModuleInfo("Import:" + File->DLLName)); + Mod->setObjFileName(LibPath); } - DefinedImportThunk *thunk = cast(file->thunkSym); - Chunk *thunkChunk = thunk->getChunk(); - OutputSection *thunkOS = thunkChunk->getOutputSection(); + DefinedImportThunk *Thunk = cast(File->ThunkSym); + Chunk *ThunkChunk = Thunk->getChunk(); + OutputSection *ThunkOS = ThunkChunk->getOutputSection(); - ObjNameSym ons(SymbolRecordKind::ObjNameSym); - Compile3Sym cs(SymbolRecordKind::Compile3Sym); - Thunk32Sym ts(SymbolRecordKind::Thunk32Sym); - ScopeEndSym es(SymbolRecordKind::ScopeEndSym); + ObjNameSym ONS(SymbolRecordKind::ObjNameSym); + Compile3Sym CS(SymbolRecordKind::Compile3Sym); + Thunk32Sym TS(SymbolRecordKind::Thunk32Sym); + ScopeEndSym ES(SymbolRecordKind::ScopeEndSym); - ons.Name = file->dllName; - ons.Signature = 0; + ONS.Name = File->DLLName; + ONS.Signature = 0; - fillLinkerVerRecord(cs); + fillLinkerVerRecord(CS); - ts.Name = thunk->getName(); - ts.Parent = 0; - ts.End = 0; - ts.Next = 0; - ts.Thunk = ThunkOrdinal::Standard; - ts.Length = thunkChunk->getSize(); - ts.Segment = thunkOS->sectionIndex; - ts.Offset = thunkChunk->getRVA() - thunkOS->getRVA(); + TS.Name = Thunk->getName(); + TS.Parent = 0; + TS.End = 0; + TS.Next = 0; + TS.Thunk = ThunkOrdinal::Standard; + TS.Length = ThunkChunk->getSize(); + TS.Segment = ThunkOS->SectionIndex; + TS.Offset = ThunkChunk->getRVA() - ThunkOS->getRVA(); - mod->addSymbol(codeview::SymbolSerializer::writeOneSymbol( - ons, alloc, CodeViewContainer::Pdb)); - mod->addSymbol(codeview::SymbolSerializer::writeOneSymbol( - cs, alloc, CodeViewContainer::Pdb)); + Mod->addSymbol(codeview::SymbolSerializer::writeOneSymbol( + ONS, Alloc, CodeViewContainer::Pdb)); + Mod->addSymbol(codeview::SymbolSerializer::writeOneSymbol( + CS, Alloc, CodeViewContainer::Pdb)); - SmallVector scopes; - CVSymbol newSym = codeview::SymbolSerializer::writeOneSymbol( - ts, alloc, CodeViewContainer::Pdb); - scopeStackOpen(scopes, mod->getNextSymbolOffset(), newSym); + SmallVector Scopes; + CVSymbol NewSym = codeview::SymbolSerializer::writeOneSymbol( + TS, Alloc, CodeViewContainer::Pdb); + scopeStackOpen(Scopes, Mod->getNextSymbolOffset(), NewSym); - mod->addSymbol(newSym); + Mod->addSymbol(NewSym); - newSym = codeview::SymbolSerializer::writeOneSymbol(es, alloc, + NewSym = codeview::SymbolSerializer::writeOneSymbol(ES, Alloc, CodeViewContainer::Pdb); - scopeStackClose(scopes, mod->getNextSymbolOffset(), file); + scopeStackClose(Scopes, Mod->getNextSymbolOffset(), File); - mod->addSymbol(newSym); + Mod->addSymbol(NewSym); - pdb::SectionContrib sc = - createSectionContrib(thunk->getChunk(), mod->getModuleIndex()); - mod->setFirstSectionContrib(sc); + pdb::SectionContrib SC = + createSectionContrib(Thunk->getChunk(), Mod->getModuleIndex()); + Mod->setFirstSectionContrib(SC); } } // Creates a PDB file. -void coff::createPDB(SymbolTable *symtab, - ArrayRef outputSections, - ArrayRef sectionTable, - llvm::codeview::DebugInfo *buildId) { - ScopedTimer t1(totalPdbLinkTimer); - PDBLinker pdb(symtab); - - pdb.initialize(buildId); - pdb.addObjectsToPDB(); - pdb.addImportFilesToPDB(outputSections); - pdb.addSections(outputSections, sectionTable); - pdb.addNatvisFiles(); - - ScopedTimer t2(diskCommitTimer); - codeview::GUID guid; - pdb.commit(&guid); - memcpy(&buildId->PDB70.Signature, &guid, 16); - - t2.stop(); - t1.stop(); - pdb.printStats(); +void coff::createPDB(SymbolTable *Symtab, + ArrayRef OutputSections, + ArrayRef SectionTable, + llvm::codeview::DebugInfo *BuildId) { + ScopedTimer T1(TotalPdbLinkTimer); + PDBLinker PDB(Symtab); + + PDB.initialize(BuildId); + PDB.addObjectsToPDB(); + PDB.addImportFilesToPDB(OutputSections); + PDB.addSections(OutputSections, SectionTable); + PDB.addNatvisFiles(); + + ScopedTimer T2(DiskCommitTimer); + codeview::GUID Guid; + PDB.commit(&Guid); + memcpy(&BuildId->PDB70.Signature, &Guid, 16); + + T2.stop(); + T1.stop(); + PDB.printStats(); } -void PDBLinker::initialize(llvm::codeview::DebugInfo *buildId) { - exitOnErr(builder.initialize(4096)); // 4096 is blocksize +void PDBLinker::initialize(llvm::codeview::DebugInfo *BuildId) { + ExitOnErr(Builder.initialize(4096)); // 4096 is blocksize - buildId->Signature.CVSignature = OMF::Signature::PDB70; + BuildId->Signature.CVSignature = OMF::Signature::PDB70; // Signature is set to a hash of the PDB contents when the PDB is done. - memset(buildId->PDB70.Signature, 0, 16); - buildId->PDB70.Age = 1; + memset(BuildId->PDB70.Signature, 0, 16); + BuildId->PDB70.Age = 1; // Create streams in MSF for predefined streams, namely // PDB, TPI, DBI and IPI. - for (int i = 0; i < (int)pdb::kSpecialStreamCount; ++i) - exitOnErr(builder.getMsfBuilder().addStream(0)); + for (int I = 0; I < (int)pdb::kSpecialStreamCount; ++I) + ExitOnErr(Builder.getMsfBuilder().addStream(0)); // Add an Info stream. - auto &infoBuilder = builder.getInfoBuilder(); - infoBuilder.setVersion(pdb::PdbRaw_ImplVer::PdbImplVC70); - infoBuilder.setHashPDBContentsToGUID(true); + auto &InfoBuilder = Builder.getInfoBuilder(); + InfoBuilder.setVersion(pdb::PdbRaw_ImplVer::PdbImplVC70); + InfoBuilder.setHashPDBContentsToGUID(true); // Add an empty DBI stream. - pdb::DbiStreamBuilder &dbiBuilder = builder.getDbiBuilder(); - dbiBuilder.setAge(buildId->PDB70.Age); - dbiBuilder.setVersionHeader(pdb::PdbDbiV70); - dbiBuilder.setMachineType(config->machine); + pdb::DbiStreamBuilder &DbiBuilder = Builder.getDbiBuilder(); + DbiBuilder.setAge(BuildId->PDB70.Age); + DbiBuilder.setVersionHeader(pdb::PdbDbiV70); + DbiBuilder.setMachineType(Config->Machine); // Technically we are not link.exe 14.11, but there are known cases where // debugging tools on Windows expect Microsoft-specific version numbers or // they fail to work at all. Since we know we produce PDBs that are // compatible with LINK 14.11, we set that version number here. - dbiBuilder.setBuildNumber(14, 11); + DbiBuilder.setBuildNumber(14, 11); } -void PDBLinker::addSections(ArrayRef outputSections, - ArrayRef sectionTable) { +void PDBLinker::addSections(ArrayRef OutputSections, + ArrayRef SectionTable) { // It's not entirely clear what this is, but the * Linker * module uses it. - pdb::DbiStreamBuilder &dbiBuilder = builder.getDbiBuilder(); - nativePath = config->pdbPath; - pdbMakeAbsolute(nativePath); - uint32_t pdbFilePathNI = dbiBuilder.addECName(nativePath); - auto &linkerModule = exitOnErr(dbiBuilder.addModuleInfo("* Linker *")); - linkerModule.setPdbFilePathNI(pdbFilePathNI); - addCommonLinkerModuleSymbols(nativePath, linkerModule, alloc); + pdb::DbiStreamBuilder &DbiBuilder = Builder.getDbiBuilder(); + NativePath = Config->PDBPath; + pdbMakeAbsolute(NativePath); + uint32_t PdbFilePathNI = DbiBuilder.addECName(NativePath); + auto &LinkerModule = ExitOnErr(DbiBuilder.addModuleInfo("* Linker *")); + LinkerModule.setPdbFilePathNI(PdbFilePathNI); + addCommonLinkerModuleSymbols(NativePath, LinkerModule, Alloc); // Add section contributions. They must be ordered by ascending RVA. - for (OutputSection *os : outputSections) { - addLinkerModuleSectionSymbol(linkerModule, *os, alloc); - for (Chunk *c : os->chunks) { - pdb::SectionContrib sc = - createSectionContrib(c, linkerModule.getModuleIndex()); - builder.getDbiBuilder().addSectionContrib(sc); + for (OutputSection *OS : OutputSections) { + addLinkerModuleSectionSymbol(LinkerModule, *OS, Alloc); + for (Chunk *C : OS->Chunks) { + pdb::SectionContrib SC = + createSectionContrib(C, LinkerModule.getModuleIndex()); + Builder.getDbiBuilder().addSectionContrib(SC); } } // The * Linker * first section contrib is only used along with /INCREMENTAL, // to provide trampolines thunks for incremental function patching. Set this // as "unused" because LLD doesn't support /INCREMENTAL link. - pdb::SectionContrib sc = + pdb::SectionContrib SC = createSectionContrib(nullptr, llvm::pdb::kInvalidStreamIndex); - linkerModule.setFirstSectionContrib(sc); + LinkerModule.setFirstSectionContrib(SC); // Add Section Map stream. - ArrayRef sections = { - (const object::coff_section *)sectionTable.data(), - sectionTable.size() / sizeof(object::coff_section)}; - sectionMap = pdb::DbiStreamBuilder::createSectionMap(sections); - dbiBuilder.setSectionMap(sectionMap); + ArrayRef Sections = { + (const object::coff_section *)SectionTable.data(), + SectionTable.size() / sizeof(object::coff_section)}; + SectionMap = pdb::DbiStreamBuilder::createSectionMap(Sections); + DbiBuilder.setSectionMap(SectionMap); // Add COFF section header stream. - exitOnErr( - dbiBuilder.addDbgStream(pdb::DbgHeaderType::SectionHdr, sectionTable)); + ExitOnErr( + DbiBuilder.addDbgStream(pdb::DbgHeaderType::SectionHdr, SectionTable)); } -void PDBLinker::commit(codeview::GUID *guid) { - ExitOnError exitOnErr((config->pdbPath + ": ").str()); +void PDBLinker::commit(codeview::GUID *Guid) { // Write to a file. - exitOnErr(builder.commit(config->pdbPath, guid)); + ExitOnErr(Builder.commit(Config->PDBPath, Guid)); } static uint32_t getSecrelReloc() { - switch (config->machine) { + switch (Config->Machine) { case AMD64: return COFF::IMAGE_REL_AMD64_SECREL; case I386: @@ -1718,78 +1717,78 @@ static uint32_t getSecrelReloc() { // that are used to interpret the line table, and the offset of Addr in the line // table are stored in the output arguments. Returns whether a line table was // found. -static bool findLineTable(const SectionChunk *c, uint32_t addr, - DebugStringTableSubsectionRef &cVStrTab, - DebugChecksumsSubsectionRef &checksums, - DebugLinesSubsectionRef &lines, - uint32_t &offsetInLinetable) { - ExitOnError exitOnErr; - uint32_t secrelReloc = getSecrelReloc(); - - for (SectionChunk *dbgC : c->file->getDebugChunks()) { - if (dbgC->getSectionName() != ".debug$S") +static bool findLineTable(const SectionChunk *C, uint32_t Addr, + DebugStringTableSubsectionRef &CVStrTab, + DebugChecksumsSubsectionRef &Checksums, + DebugLinesSubsectionRef &Lines, + uint32_t &OffsetInLinetable) { + ExitOnError ExitOnErr; + uint32_t SecrelReloc = getSecrelReloc(); + + for (SectionChunk *DbgC : C->File->getDebugChunks()) { + if (DbgC->getSectionName() != ".debug$S") continue; - // Build a mapping of SECREL relocations in dbgC that refer to `c`. - DenseMap secrels; - for (const coff_relocation &r : dbgC->getRelocs()) { - if (r.Type != secrelReloc) + // Build a mapping of SECREL relocations in DbgC that refer to C. + DenseMap Secrels; + for (const coff_relocation &R : DbgC->getRelocs()) { + if (R.Type != SecrelReloc) continue; - if (auto *s = dyn_cast_or_null( - c->file->getSymbols()[r.SymbolTableIndex])) - if (s->getChunk() == c) - secrels[r.VirtualAddress] = s->getValue(); + if (auto *S = dyn_cast_or_null( + C->File->getSymbols()[R.SymbolTableIndex])) + if (S->getChunk() == C) + Secrels[R.VirtualAddress] = S->getValue(); } - ArrayRef contents = - SectionChunk::consumeDebugMagic(dbgC->getContents(), ".debug$S"); - DebugSubsectionArray subsections; - BinaryStreamReader reader(contents, support::little); - exitOnErr(reader.readArray(subsections, contents.size())); + ArrayRef Contents = + SectionChunk::consumeDebugMagic(DbgC->getContents(), ".debug$S"); + DebugSubsectionArray Subsections; + BinaryStreamReader Reader(Contents, support::little); + ExitOnErr(Reader.readArray(Subsections, Contents.size())); - for (const DebugSubsectionRecord &ss : subsections) { - switch (ss.kind()) { + for (const DebugSubsectionRecord &SS : Subsections) { + switch (SS.kind()) { case DebugSubsectionKind::StringTable: { - assert(!cVStrTab.valid() && + assert(!CVStrTab.valid() && "Encountered multiple string table subsections!"); - exitOnErr(cVStrTab.initialize(ss.getRecordData())); + ExitOnErr(CVStrTab.initialize(SS.getRecordData())); break; } case DebugSubsectionKind::FileChecksums: - assert(!checksums.valid() && + assert(!Checksums.valid() && "Encountered multiple checksum subsections!"); - exitOnErr(checksums.initialize(ss.getRecordData())); + ExitOnErr(Checksums.initialize(SS.getRecordData())); break; case DebugSubsectionKind::Lines: { - ArrayRef bytes; - auto ref = ss.getRecordData(); - exitOnErr(ref.readLongestContiguousChunk(0, bytes)); - size_t offsetInDbgC = bytes.data() - dbgC->getContents().data(); + ArrayRef Bytes; + auto Ref = SS.getRecordData(); + ExitOnErr(Ref.readLongestContiguousChunk(0, Bytes)); + size_t OffsetInDbgC = Bytes.data() - DbgC->getContents().data(); // Check whether this line table refers to C. - auto i = secrels.find(offsetInDbgC); - if (i == secrels.end()) + auto I = Secrels.find(OffsetInDbgC); + if (I == Secrels.end()) break; // Check whether this line table covers Addr in C. - DebugLinesSubsectionRef linesTmp; - exitOnErr(linesTmp.initialize(BinaryStreamReader(ref))); - uint32_t offsetInC = i->second + linesTmp.header()->RelocOffset; - if (addr < offsetInC || addr >= offsetInC + linesTmp.header()->CodeSize) + DebugLinesSubsectionRef LinesTmp; + ExitOnErr(LinesTmp.initialize(BinaryStreamReader(Ref))); + uint32_t OffsetInC = I->second + LinesTmp.header()->RelocOffset; + if (Addr < OffsetInC || Addr >= OffsetInC + LinesTmp.header()->CodeSize) break; - assert(!lines.header() && + assert(!Lines.header() && "Encountered multiple line tables for function!"); - exitOnErr(lines.initialize(BinaryStreamReader(ref))); - offsetInLinetable = addr - offsetInC; + ExitOnErr(Lines.initialize(BinaryStreamReader(Ref))); + OffsetInLinetable = Addr - OffsetInC; break; } default: break; } - if (cVStrTab.valid() && checksums.valid() && lines.header()) + if (CVStrTab.valid() && Checksums.valid() && Lines.header()) return true; } } @@ -1800,38 +1799,38 @@ static bool findLineTable(const SectionChunk *c, uint32_t addr, // Use CodeView line tables to resolve a file and line number for the given // offset into the given chunk and return them, or {"", 0} if a line table was // not found. -std::pair coff::getFileLine(const SectionChunk *c, - uint32_t addr) { - ExitOnError exitOnErr; +std::pair coff::getFileLine(const SectionChunk *C, + uint32_t Addr) { + ExitOnError ExitOnErr; - DebugStringTableSubsectionRef cVStrTab; - DebugChecksumsSubsectionRef checksums; - DebugLinesSubsectionRef lines; - uint32_t offsetInLinetable; + DebugStringTableSubsectionRef CVStrTab; + DebugChecksumsSubsectionRef Checksums; + DebugLinesSubsectionRef Lines; + uint32_t OffsetInLinetable; - if (!findLineTable(c, addr, cVStrTab, checksums, lines, offsetInLinetable)) + if (!findLineTable(C, Addr, CVStrTab, Checksums, Lines, OffsetInLinetable)) return {"", 0}; - Optional nameIndex; - Optional lineNumber; - for (LineColumnEntry &entry : lines) { - for (const LineNumberEntry &ln : entry.LineNumbers) { - LineInfo li(ln.Flags); - if (ln.Offset > offsetInLinetable) { - if (!nameIndex) { - nameIndex = entry.NameIndex; - lineNumber = li.getStartLine(); + Optional NameIndex; + Optional LineNumber; + for (LineColumnEntry &Entry : Lines) { + for (const LineNumberEntry &LN : Entry.LineNumbers) { + LineInfo LI(LN.Flags); + if (LN.Offset > OffsetInLinetable) { + if (!NameIndex) { + NameIndex = Entry.NameIndex; + LineNumber = LI.getStartLine(); } - StringRef filename = - exitOnErr(getFileName(cVStrTab, checksums, *nameIndex)); - return {filename, *lineNumber}; + StringRef Filename = + ExitOnErr(getFileName(CVStrTab, Checksums, *NameIndex)); + return {Filename, *LineNumber}; } - nameIndex = entry.NameIndex; - lineNumber = li.getStartLine(); + NameIndex = Entry.NameIndex; + LineNumber = LI.getStartLine(); } } - if (!nameIndex) + if (!NameIndex) return {"", 0}; - StringRef filename = exitOnErr(getFileName(cVStrTab, checksums, *nameIndex)); - return {filename, *lineNumber}; + StringRef Filename = ExitOnErr(getFileName(CVStrTab, Checksums, *NameIndex)); + return {Filename, *LineNumber}; } diff --git a/lld/COFF/PDB.h b/lld/COFF/PDB.h index 3ac1adc85c5d05..d954e09b535c46 100644 --- a/lld/COFF/PDB.h +++ b/lld/COFF/PDB.h @@ -24,13 +24,13 @@ class OutputSection; class SectionChunk; class SymbolTable; -void createPDB(SymbolTable *symtab, - llvm::ArrayRef outputSections, - llvm::ArrayRef sectionTable, - llvm::codeview::DebugInfo *buildId); +void createPDB(SymbolTable *Symtab, + llvm::ArrayRef OutputSections, + llvm::ArrayRef SectionTable, + llvm::codeview::DebugInfo *BuildId); -std::pair getFileLine(const SectionChunk *c, - uint32_t addr); +std::pair getFileLine(const SectionChunk *C, + uint32_t Addr); } } diff --git a/lld/COFF/SymbolTable.cpp b/lld/COFF/SymbolTable.cpp index 4b75d667bd4c40..529562d807dfcc 100644 --- a/lld/COFF/SymbolTable.cpp +++ b/lld/COFF/SymbolTable.cpp @@ -26,698 +26,576 @@ using namespace llvm; namespace lld { namespace coff { -static Timer ltoTimer("LTO", Timer::root()); +static Timer LTOTimer("LTO", Timer::root()); -SymbolTable *symtab; +SymbolTable *Symtab; -void SymbolTable::addFile(InputFile *file) { - log("Reading " + toString(file)); - file->parse(); +void SymbolTable::addFile(InputFile *File) { + log("Reading " + toString(File)); + File->parse(); - MachineTypes mt = file->getMachineType(); - if (config->machine == IMAGE_FILE_MACHINE_UNKNOWN) { - config->machine = mt; - } else if (mt != IMAGE_FILE_MACHINE_UNKNOWN && config->machine != mt) { - error(toString(file) + ": machine type " + machineToStr(mt) + - " conflicts with " + machineToStr(config->machine)); + MachineTypes MT = File->getMachineType(); + if (Config->Machine == IMAGE_FILE_MACHINE_UNKNOWN) { + Config->Machine = MT; + } else if (MT != IMAGE_FILE_MACHINE_UNKNOWN && Config->Machine != MT) { + error(toString(File) + ": machine type " + machineToStr(MT) + + " conflicts with " + machineToStr(Config->Machine)); return; } - if (auto *f = dyn_cast(file)) { - ObjFile::instances.push_back(f); - } else if (auto *f = dyn_cast(file)) { - BitcodeFile::instances.push_back(f); - } else if (auto *f = dyn_cast(file)) { - ImportFile::instances.push_back(f); + if (auto *F = dyn_cast(File)) { + ObjFile::Instances.push_back(F); + } else if (auto *F = dyn_cast(File)) { + BitcodeFile::Instances.push_back(F); + } else if (auto *F = dyn_cast(File)) { + ImportFile::Instances.push_back(F); } - driver->parseDirectives(file); + Driver->parseDirectives(File); } -static void errorOrWarn(const Twine &s) { - if (config->forceUnresolved) - warn(s); +static void errorOrWarn(const Twine &S) { + if (Config->ForceUnresolved) + warn(S); else - error(s); -} - -// Causes the file associated with a lazy symbol to be linked in. -static void forceLazy(Symbol *s) { - s->pendingArchiveLoad = true; - switch (s->kind()) { - case Symbol::Kind::LazyArchiveKind: { - auto *l = cast(s); - l->file->addMember(l->sym); - break; - } - case Symbol::Kind::LazyObjectKind: - cast(s)->file->fetch(); - break; - default: - llvm_unreachable( - "symbol passed to forceLazy is not a LazyArchive or LazyObject"); - } + error(S); } // Returns the symbol in SC whose value is <= Addr that is closest to Addr. // This is generally the global variable or function whose definition contains // Addr. -static Symbol *getSymbol(SectionChunk *sc, uint32_t addr) { - DefinedRegular *candidate = nullptr; - - for (Symbol *s : sc->file->getSymbols()) { - auto *d = dyn_cast_or_null(s); - if (!d || !d->data || d->file != sc->file || d->getChunk() != sc || - d->getValue() > addr || - (candidate && d->getValue() < candidate->getValue())) +static Symbol *getSymbol(SectionChunk *SC, uint32_t Addr) { + DefinedRegular *Candidate = nullptr; + + for (Symbol *S : SC->File->getSymbols()) { + auto *D = dyn_cast_or_null(S); + if (!D || D->getChunk() != SC || D->getValue() > Addr || + (Candidate && D->getValue() < Candidate->getValue())) continue; - candidate = d; + Candidate = D; } - return candidate; -} - -static std::vector getSymbolLocations(BitcodeFile *file) { - std::string res("\n>>> referenced by "); - StringRef source = file->obj->getSourceFileName(); - if (!source.empty()) - res += source.str() + "\n>>> "; - res += toString(file); - return {res}; + return Candidate; } // Given a file and the index of a symbol in that file, returns a description // of all references to that symbol from that file. If no debug information is // available, returns just the name of the file, else one string per actual // reference as described in the debug info. -std::vector getSymbolLocations(ObjFile *file, uint32_t symIndex) { +std::vector getSymbolLocations(ObjFile *File, uint32_t SymIndex) { struct Location { - Symbol *sym; - std::pair fileLine; + Symbol *Sym; + std::pair FileLine; }; - std::vector locations; + std::vector Locations; - for (Chunk *c : file->getChunks()) { - auto *sc = dyn_cast(c); - if (!sc) + for (Chunk *C : File->getChunks()) { + auto *SC = dyn_cast(C); + if (!SC) continue; - for (const coff_relocation &r : sc->getRelocs()) { - if (r.SymbolTableIndex != symIndex) + for (const coff_relocation &R : SC->getRelocs()) { + if (R.SymbolTableIndex != SymIndex) continue; - std::pair fileLine = - getFileLine(sc, r.VirtualAddress); - Symbol *sym = getSymbol(sc, r.VirtualAddress); - if (!fileLine.first.empty() || sym) - locations.push_back({sym, fileLine}); + std::pair FileLine = + getFileLine(SC, R.VirtualAddress); + Symbol *Sym = getSymbol(SC, R.VirtualAddress); + if (!FileLine.first.empty() || Sym) + Locations.push_back({Sym, FileLine}); } } - if (locations.empty()) - return std::vector({"\n>>> referenced by " + toString(file)}); + if (Locations.empty()) + return std::vector({"\n>>> referenced by " + toString(File)}); - std::vector symbolLocations(locations.size()); - size_t i = 0; - for (Location loc : locations) { - llvm::raw_string_ostream os(symbolLocations[i++]); - os << "\n>>> referenced by "; - if (!loc.fileLine.first.empty()) - os << loc.fileLine.first << ":" << loc.fileLine.second + std::vector SymbolLocations(Locations.size()); + size_t I = 0; + for (Location Loc : Locations) { + llvm::raw_string_ostream OS(SymbolLocations[I++]); + OS << "\n>>> referenced by "; + if (!Loc.FileLine.first.empty()) + OS << Loc.FileLine.first << ":" << Loc.FileLine.second << "\n>>> "; - os << toString(file); - if (loc.sym) - os << ":(" << toString(*loc.sym) << ')'; + OS << toString(File); + if (Loc.Sym) + OS << ":(" << toString(*Loc.Sym) << ')'; } - return symbolLocations; -} - -std::vector getSymbolLocations(InputFile *file, - uint32_t symIndex) { - if (auto *o = dyn_cast(file)) - return getSymbolLocations(o, symIndex); - if (auto *b = dyn_cast(file)) - return getSymbolLocations(b); - llvm_unreachable("unsupported file type passed to getSymbolLocations"); - return {}; + return SymbolLocations; } // For an undefined symbol, stores all files referencing it and the index of // the undefined symbol in each file. struct UndefinedDiag { - Symbol *sym; + Symbol *Sym; struct File { - InputFile *file; - uint32_t symIndex; + ObjFile *File; + uint64_t SymIndex; }; - std::vector files; + std::vector Files; }; -static void reportUndefinedSymbol(const UndefinedDiag &undefDiag) { - std::string out; - llvm::raw_string_ostream os(out); - os << "undefined symbol: " << toString(*undefDiag.sym); - - const size_t maxUndefReferences = 10; - size_t i = 0, numRefs = 0; - for (const UndefinedDiag::File &ref : undefDiag.files) { - std::vector symbolLocations = - getSymbolLocations(ref.file, ref.symIndex); - numRefs += symbolLocations.size(); - for (const std::string &s : symbolLocations) { - if (i >= maxUndefReferences) +static void reportUndefinedSymbol(const UndefinedDiag &UndefDiag) { + std::string Out; + llvm::raw_string_ostream OS(Out); + OS << "undefined symbol: " << toString(*UndefDiag.Sym); + + const size_t MaxUndefReferences = 10; + size_t I = 0, NumRefs = 0; + for (const UndefinedDiag::File &Ref : UndefDiag.Files) { + std::vector SymbolLocations = + getSymbolLocations(Ref.File, Ref.SymIndex); + NumRefs += SymbolLocations.size(); + for (const std::string &S : SymbolLocations) { + if (I >= MaxUndefReferences) break; - os << s; - i++; + OS << S; + I++; } } - if (i < numRefs) - os << "\n>>> referenced " << numRefs - i << " more times"; - errorOrWarn(os.str()); + if (I < NumRefs) + OS << "\n>>> referenced " << NumRefs - I << " more times"; + errorOrWarn(OS.str()); } void SymbolTable::loadMinGWAutomaticImports() { - for (auto &i : symMap) { - Symbol *sym = i.second; - auto *undef = dyn_cast(sym); - if (!undef) - continue; - if (!sym->isUsedInRegularObj) + for (auto &I : SymMap) { + Symbol *Sym = I.second; + auto *Undef = dyn_cast(Sym); + if (!Undef) continue; - if (undef->getWeakAlias()) + if (!Sym->IsUsedInRegularObj) continue; - StringRef name = undef->getName(); + StringRef Name = Undef->getName(); - if (name.startswith("__imp_")) + if (Name.startswith("__imp_")) continue; - // If we have an undefined symbol, but we have a lazy symbol we could - // load, load it. - Symbol *l = find(("__imp_" + name).str()); - if (!l || l->pendingArchiveLoad || !l->isLazy()) + // If we have an undefined symbol, but we have a Lazy representing a + // symbol we could load from file, make sure to load that. + Lazy *L = dyn_cast_or_null(find(("__imp_" + Name).str())); + if (!L || L->PendingArchiveLoad) continue; - log("Loading lazy " + l->getName() + " from " + l->getFile()->getName() + + log("Loading lazy " + L->getName() + " from " + L->File->getName() + " for automatic import"); - forceLazy(l); + L->PendingArchiveLoad = true; + L->File->addMember(&L->Sym); } } -Defined *SymbolTable::impSymbol(StringRef name) { - if (name.startswith("__imp_")) - return nullptr; - return dyn_cast_or_null(find(("__imp_" + name).str())); -} - -bool SymbolTable::handleMinGWAutomaticImport(Symbol *sym, StringRef name) { - Defined *imp = impSymbol(name); - if (!imp) +bool SymbolTable::handleMinGWAutomaticImport(Symbol *Sym, StringRef Name) { + if (Name.startswith("__imp_")) + return false; + Defined *Imp = dyn_cast_or_null(find(("__imp_" + Name).str())); + if (!Imp) return false; // Replace the reference directly to a variable with a reference // to the import address table instead. This obviously isn't right, - // but we mark the symbol as isRuntimePseudoReloc, and a later pass + // but we mark the symbol as IsRuntimePseudoReloc, and a later pass // will add runtime pseudo relocations for every relocation against // this Symbol. The runtime pseudo relocation framework expects the // reference itself to point at the IAT entry. - size_t impSize = 0; - if (isa(imp)) { - log("Automatically importing " + name + " from " + - cast(imp)->getDLLName()); - impSize = sizeof(DefinedImportData); - } else if (isa(imp)) { - log("Automatically importing " + name + " from " + - toString(cast(imp)->file)); - impSize = sizeof(DefinedRegular); + size_t ImpSize = 0; + if (isa(Imp)) { + log("Automatically importing " + Name + " from " + + cast(Imp)->getDLLName()); + ImpSize = sizeof(DefinedImportData); + } else if (isa(Imp)) { + log("Automatically importing " + Name + " from " + + toString(cast(Imp)->File)); + ImpSize = sizeof(DefinedRegular); } else { - warn("unable to automatically import " + name + " from " + imp->getName() + - " from " + toString(cast(imp)->file) + + warn("unable to automatically import " + Name + " from " + Imp->getName() + + " from " + toString(cast(Imp)->File) + "; unexpected symbol type"); return false; } - sym->replaceKeepingName(imp, impSize); - sym->isRuntimePseudoReloc = true; + Sym->replaceKeepingName(Imp, ImpSize); + Sym->IsRuntimePseudoReloc = true; // There may exist symbols named .refptr. which only consist // of a single pointer to . If it turns out is // automatically imported, we don't need to keep the .refptr. // pointer at all, but redirect all accesses to it to the IAT entry // for __imp_ instead, and drop the whole .refptr. chunk. - DefinedRegular *refptr = - dyn_cast_or_null(find((".refptr." + name).str())); - if (refptr && refptr->getChunk()->getSize() == config->wordsize) { - SectionChunk *sc = dyn_cast_or_null(refptr->getChunk()); - if (sc && sc->getRelocs().size() == 1 && *sc->symbols().begin() == sym) { - log("Replacing .refptr." + name + " with " + imp->getName()); - refptr->getChunk()->live = false; - refptr->replaceKeepingName(imp, impSize); + DefinedRegular *Refptr = + dyn_cast_or_null(find((".refptr." + Name).str())); + if (Refptr && Refptr->getChunk()->getSize() == Config->Wordsize) { + SectionChunk *SC = dyn_cast_or_null(Refptr->getChunk()); + if (SC && SC->getRelocs().size() == 1 && *SC->symbols().begin() == Sym) { + log("Replacing .refptr." + Name + " with " + Imp->getName()); + Refptr->getChunk()->Live = false; + Refptr->replaceKeepingName(Imp, ImpSize); } } return true; } -/// Helper function for reportUnresolvable and resolveRemainingUndefines. -/// This function emits an "undefined symbol" diagnostic for each symbol in -/// undefs. If localImports is not nullptr, it also emits a "locally -/// defined symbol imported" diagnostic for symbols in localImports. -/// objFiles and bitcodeFiles (if not nullptr) are used to report where -/// undefined symbols are referenced. -static void -reportProblemSymbols(const SmallPtrSetImpl &undefs, - const DenseMap *localImports, - const std::vector objFiles, - const std::vector *bitcodeFiles) { - - // Return early if there is nothing to report (which should be - // the common case). - if (undefs.empty() && (!localImports || localImports->empty())) - return; - - for (Symbol *b : config->gcroot) { - if (undefs.count(b)) - errorOrWarn(": undefined symbol: " + toString(*b)); - if (localImports) - if (Symbol *imp = localImports->lookup(b)) - warn(": locally defined symbol imported: " + toString(*imp) + - " (defined in " + toString(imp->getFile()) + ") [LNK4217]"); - } - - std::vector undefDiags; - DenseMap firstDiag; - - auto processFile = [&](InputFile *file, ArrayRef symbols) { - uint32_t symIndex = (uint32_t)-1; - for (Symbol *sym : symbols) { - ++symIndex; - if (!sym) - continue; - if (undefs.count(sym)) { - auto it = firstDiag.find(sym); - if (it == firstDiag.end()) { - firstDiag[sym] = undefDiags.size(); - undefDiags.push_back({sym, {{file, symIndex}}}); - } else { - undefDiags[it->second].files.push_back({file, symIndex}); - } - } - if (localImports) - if (Symbol *imp = localImports->lookup(sym)) - warn(toString(file) + - ": locally defined symbol imported: " + toString(*imp) + - " (defined in " + toString(imp->getFile()) + ") [LNK4217]"); - } - }; - - for (ObjFile *file : objFiles) - processFile(file, file->getSymbols()); - - if (bitcodeFiles) - for (BitcodeFile *file : *bitcodeFiles) - processFile(file, file->getSymbols()); - - for (const UndefinedDiag &undefDiag : undefDiags) - reportUndefinedSymbol(undefDiag); -} - -void SymbolTable::reportUnresolvable() { - SmallPtrSet undefs; - for (auto &i : symMap) { - Symbol *sym = i.second; - auto *undef = dyn_cast(sym); - if (!undef) - continue; - if (undef->getWeakAlias()) - continue; - StringRef name = undef->getName(); - if (name.startswith("__imp_")) { - Symbol *imp = find(name.substr(strlen("__imp_"))); - if (imp && isa(imp)) - continue; - } - if (name.contains("_PchSym_")) - continue; - if (config->mingw && impSymbol(name)) - continue; - undefs.insert(sym); - } - - reportProblemSymbols(undefs, - /* localImports */ nullptr, ObjFile::instances, - &BitcodeFile::instances); -} - -void SymbolTable::resolveRemainingUndefines() { - SmallPtrSet undefs; - DenseMap localImports; +void SymbolTable::reportRemainingUndefines() { + SmallPtrSet Undefs; + DenseMap LocalImports; - for (auto &i : symMap) { - Symbol *sym = i.second; - auto *undef = dyn_cast(sym); - if (!undef) + for (auto &I : SymMap) { + Symbol *Sym = I.second; + auto *Undef = dyn_cast(Sym); + if (!Undef) continue; - if (!sym->isUsedInRegularObj) + if (!Sym->IsUsedInRegularObj) continue; - StringRef name = undef->getName(); + StringRef Name = Undef->getName(); // A weak alias may have been resolved, so check for that. - if (Defined *d = undef->getWeakAlias()) { + if (Defined *D = Undef->getWeakAlias()) { // We want to replace Sym with D. However, we can't just blindly // copy sizeof(SymbolUnion) bytes from D to Sym because D may be an // internal symbol, and internal symbols are stored as "unparented" // Symbols. For that reason we need to check which type of symbol we // are dealing with and copy the correct number of bytes. - if (isa(d)) - memcpy(sym, d, sizeof(DefinedRegular)); - else if (isa(d)) - memcpy(sym, d, sizeof(DefinedAbsolute)); + if (isa(D)) + memcpy(Sym, D, sizeof(DefinedRegular)); + else if (isa(D)) + memcpy(Sym, D, sizeof(DefinedAbsolute)); else - memcpy(sym, d, sizeof(SymbolUnion)); + memcpy(Sym, D, sizeof(SymbolUnion)); continue; } // If we can resolve a symbol by removing __imp_ prefix, do that. // This odd rule is for compatibility with MSVC linker. - if (name.startswith("__imp_")) { - Symbol *imp = find(name.substr(strlen("__imp_"))); - if (imp && isa(imp)) { - auto *d = cast(imp); - replaceSymbol(sym, name, d); - localImportChunks.push_back(cast(sym)->getChunk()); - localImports[sym] = d; + if (Name.startswith("__imp_")) { + Symbol *Imp = find(Name.substr(strlen("__imp_"))); + if (Imp && isa(Imp)) { + auto *D = cast(Imp); + replaceSymbol(Sym, Name, D); + LocalImportChunks.push_back(cast(Sym)->getChunk()); + LocalImports[Sym] = D; continue; } } // We don't want to report missing Microsoft precompiled headers symbols. // A proper message will be emitted instead in PDBLinker::aquirePrecompObj - if (name.contains("_PchSym_")) + if (Name.contains("_PchSym_")) continue; - if (config->mingw && handleMinGWAutomaticImport(sym, name)) + if (Config->MinGW && handleMinGWAutomaticImport(Sym, Name)) continue; // Remaining undefined symbols are not fatal if /force is specified. // They are replaced with dummy defined symbols. - if (config->forceUnresolved) - replaceSymbol(sym, name, 0); - undefs.insert(sym); + if (Config->ForceUnresolved) + replaceSymbol(Sym, Name, 0); + Undefs.insert(Sym); } - reportProblemSymbols( - undefs, config->warnLocallyDefinedImported ? &localImports : nullptr, - ObjFile::instances, /* bitcode files no longer needed */ nullptr); -} + if (Undefs.empty() && LocalImports.empty()) + return; -std::pair SymbolTable::insert(StringRef name) { - bool inserted = false; - Symbol *&sym = symMap[CachedHashStringRef(name)]; - if (!sym) { - sym = reinterpret_cast(make()); - sym->isUsedInRegularObj = false; - sym->pendingArchiveLoad = false; - inserted = true; + for (Symbol *B : Config->GCRoot) { + if (Undefs.count(B)) + errorOrWarn(": undefined symbol: " + toString(*B)); + if (Config->WarnLocallyDefinedImported) + if (Symbol *Imp = LocalImports.lookup(B)) + warn(": locally defined symbol imported: " + toString(*Imp) + + " (defined in " + toString(Imp->getFile()) + ") [LNK4217]"); } - return {sym, inserted}; -} -std::pair SymbolTable::insert(StringRef name, InputFile *file) { - std::pair result = insert(name); - if (!file || !isa(file)) - result.first->isUsedInRegularObj = true; - return result; -} + std::vector UndefDiags; + DenseMap FirstDiag; -Symbol *SymbolTable::addUndefined(StringRef name, InputFile *f, - bool isWeakAlias) { - Symbol *s; - bool wasInserted; - std::tie(s, wasInserted) = insert(name, f); - if (wasInserted || (s->isLazy() && isWeakAlias)) { - replaceSymbol(s, name); - return s; + for (ObjFile *File : ObjFile::Instances) { + size_t SymIndex = (size_t)-1; + for (Symbol *Sym : File->getSymbols()) { + ++SymIndex; + if (!Sym) + continue; + if (Undefs.count(Sym)) { + auto it = FirstDiag.find(Sym); + if (it == FirstDiag.end()) { + FirstDiag[Sym] = UndefDiags.size(); + UndefDiags.push_back({Sym, {{File, SymIndex}}}); + } else { + UndefDiags[it->second].Files.push_back({File, SymIndex}); + } + } + if (Config->WarnLocallyDefinedImported) + if (Symbol *Imp = LocalImports.lookup(Sym)) + warn(toString(File) + + ": locally defined symbol imported: " + toString(*Imp) + + " (defined in " + toString(Imp->getFile()) + ") [LNK4217]"); + } } - if (s->isLazy()) - forceLazy(s); - return s; -} -void SymbolTable::addLazyArchive(ArchiveFile *f, const Archive::Symbol &sym) { - StringRef name = sym.getName(); - Symbol *s; - bool wasInserted; - std::tie(s, wasInserted) = insert(name); - if (wasInserted) { - replaceSymbol(s, f, sym); - return; - } - auto *u = dyn_cast(s); - if (!u || u->weakAlias || s->pendingArchiveLoad) - return; - s->pendingArchiveLoad = true; - f->addMember(sym); + for (const UndefinedDiag& UndefDiag : UndefDiags) + reportUndefinedSymbol(UndefDiag); } -void SymbolTable::addLazyObject(LazyObjFile *f, StringRef n) { - Symbol *s; - bool wasInserted; - std::tie(s, wasInserted) = insert(n, f); - if (wasInserted) { - replaceSymbol(s, f, n); - return; +std::pair SymbolTable::insert(StringRef Name) { + bool Inserted = false; + Symbol *&Sym = SymMap[CachedHashStringRef(Name)]; + if (!Sym) { + Sym = reinterpret_cast(make()); + Sym->IsUsedInRegularObj = false; + Sym->PendingArchiveLoad = false; + Inserted = true; } - auto *u = dyn_cast(s); - if (!u || u->weakAlias || s->pendingArchiveLoad) - return; - s->pendingArchiveLoad = true; - f->fetch(); + return {Sym, Inserted}; } -void SymbolTable::reportDuplicate(Symbol *existing, InputFile *newFile) { - std::string msg = "duplicate symbol: " + toString(*existing) + " in " + - toString(existing->getFile()) + " and in " + - toString(newFile); - - if (config->forceMultiple) - warn(msg); - else - error(msg); +std::pair SymbolTable::insert(StringRef Name, InputFile *File) { + std::pair Result = insert(Name); + if (!File || !isa(File)) + Result.first->IsUsedInRegularObj = true; + return Result; } -Symbol *SymbolTable::addAbsolute(StringRef n, COFFSymbolRef sym) { - Symbol *s; - bool wasInserted; - std::tie(s, wasInserted) = insert(n, nullptr); - s->isUsedInRegularObj = true; - if (wasInserted || isa(s) || s->isLazy()) - replaceSymbol(s, n, sym); - else if (!isa(s)) - reportDuplicate(s, nullptr); - return s; +Symbol *SymbolTable::addUndefined(StringRef Name, InputFile *F, + bool IsWeakAlias) { + Symbol *S; + bool WasInserted; + std::tie(S, WasInserted) = insert(Name, F); + if (WasInserted || (isa(S) && IsWeakAlias)) { + replaceSymbol(S, Name); + return S; + } + if (auto *L = dyn_cast(S)) { + if (!S->PendingArchiveLoad) { + S->PendingArchiveLoad = true; + L->File->addMember(&L->Sym); + } + } + return S; } -Symbol *SymbolTable::addAbsolute(StringRef n, uint64_t va) { - Symbol *s; - bool wasInserted; - std::tie(s, wasInserted) = insert(n, nullptr); - s->isUsedInRegularObj = true; - if (wasInserted || isa(s) || s->isLazy()) - replaceSymbol(s, n, va); - else if (!isa(s)) - reportDuplicate(s, nullptr); - return s; +void SymbolTable::addLazy(ArchiveFile *F, const Archive::Symbol Sym) { + StringRef Name = Sym.getName(); + Symbol *S; + bool WasInserted; + std::tie(S, WasInserted) = insert(Name); + if (WasInserted) { + replaceSymbol(S, F, Sym); + return; + } + auto *U = dyn_cast(S); + if (!U || U->WeakAlias || S->PendingArchiveLoad) + return; + S->PendingArchiveLoad = true; + F->addMember(&Sym); } -Symbol *SymbolTable::addSynthetic(StringRef n, Chunk *c) { - Symbol *s; - bool wasInserted; - std::tie(s, wasInserted) = insert(n, nullptr); - s->isUsedInRegularObj = true; - if (wasInserted || isa(s) || s->isLazy()) - replaceSymbol(s, n, c); - else if (!isa(s)) - reportDuplicate(s, nullptr); - return s; -} +void SymbolTable::reportDuplicate(Symbol *Existing, InputFile *NewFile) { + std::string Msg = "duplicate symbol: " + toString(*Existing) + " in " + + toString(Existing->getFile()) + " and in " + + toString(NewFile); -Symbol *SymbolTable::addRegular(InputFile *f, StringRef n, - const coff_symbol_generic *sym, - SectionChunk *c) { - Symbol *s; - bool wasInserted; - std::tie(s, wasInserted) = insert(n, f); - if (wasInserted || !isa(s)) - replaceSymbol(s, f, n, /*IsCOMDAT*/ false, - /*IsExternal*/ true, sym, c); + if (Config->ForceMultiple) + warn(Msg); + else + error(Msg); +} + +Symbol *SymbolTable::addAbsolute(StringRef N, COFFSymbolRef Sym) { + Symbol *S; + bool WasInserted; + std::tie(S, WasInserted) = insert(N, nullptr); + S->IsUsedInRegularObj = true; + if (WasInserted || isa(S) || isa(S)) + replaceSymbol(S, N, Sym); + else if (!isa(S)) + reportDuplicate(S, nullptr); + return S; +} + +Symbol *SymbolTable::addAbsolute(StringRef N, uint64_t VA) { + Symbol *S; + bool WasInserted; + std::tie(S, WasInserted) = insert(N, nullptr); + S->IsUsedInRegularObj = true; + if (WasInserted || isa(S) || isa(S)) + replaceSymbol(S, N, VA); + else if (!isa(S)) + reportDuplicate(S, nullptr); + return S; +} + +Symbol *SymbolTable::addSynthetic(StringRef N, Chunk *C) { + Symbol *S; + bool WasInserted; + std::tie(S, WasInserted) = insert(N, nullptr); + S->IsUsedInRegularObj = true; + if (WasInserted || isa(S) || isa(S)) + replaceSymbol(S, N, C); + else if (!isa(S)) + reportDuplicate(S, nullptr); + return S; +} + +Symbol *SymbolTable::addRegular(InputFile *F, StringRef N, + const coff_symbol_generic *Sym, + SectionChunk *C) { + Symbol *S; + bool WasInserted; + std::tie(S, WasInserted) = insert(N, F); + if (WasInserted || !isa(S)) + replaceSymbol(S, F, N, /*IsCOMDAT*/ false, + /*IsExternal*/ true, Sym, C); else - reportDuplicate(s, f); - return s; + reportDuplicate(S, F); + return S; } std::pair -SymbolTable::addComdat(InputFile *f, StringRef n, - const coff_symbol_generic *sym) { - Symbol *s; - bool wasInserted; - std::tie(s, wasInserted) = insert(n, f); - if (wasInserted || !isa(s)) { - replaceSymbol(s, f, n, /*IsCOMDAT*/ true, - /*IsExternal*/ true, sym, nullptr); - return {cast(s), true}; +SymbolTable::addComdat(InputFile *F, StringRef N, + const coff_symbol_generic *Sym) { + Symbol *S; + bool WasInserted; + std::tie(S, WasInserted) = insert(N, F); + if (WasInserted || !isa(S)) { + replaceSymbol(S, F, N, /*IsCOMDAT*/ true, + /*IsExternal*/ true, Sym, nullptr); + return {cast(S), true}; } - auto *existingSymbol = cast(s); - if (!existingSymbol->isCOMDAT) - reportDuplicate(s, f); - return {existingSymbol, false}; -} - -Symbol *SymbolTable::addCommon(InputFile *f, StringRef n, uint64_t size, - const coff_symbol_generic *sym, CommonChunk *c) { - Symbol *s; - bool wasInserted; - std::tie(s, wasInserted) = insert(n, f); - if (wasInserted || !isa(s)) - replaceSymbol(s, f, n, size, sym, c); - else if (auto *dc = dyn_cast(s)) - if (size > dc->getSize()) - replaceSymbol(s, f, n, size, sym, c); - return s; -} - -Symbol *SymbolTable::addImportData(StringRef n, ImportFile *f) { - Symbol *s; - bool wasInserted; - std::tie(s, wasInserted) = insert(n, nullptr); - s->isUsedInRegularObj = true; - if (wasInserted || isa(s) || s->isLazy()) { - replaceSymbol(s, n, f); - return s; + auto *ExistingSymbol = cast(S); + if (!ExistingSymbol->isCOMDAT()) + reportDuplicate(S, F); + return {ExistingSymbol, false}; +} + +Symbol *SymbolTable::addCommon(InputFile *F, StringRef N, uint64_t Size, + const coff_symbol_generic *Sym, CommonChunk *C) { + Symbol *S; + bool WasInserted; + std::tie(S, WasInserted) = insert(N, F); + if (WasInserted || !isa(S)) + replaceSymbol(S, F, N, Size, Sym, C); + else if (auto *DC = dyn_cast(S)) + if (Size > DC->getSize()) + replaceSymbol(S, F, N, Size, Sym, C); + return S; +} + +Symbol *SymbolTable::addImportData(StringRef N, ImportFile *F) { + Symbol *S; + bool WasInserted; + std::tie(S, WasInserted) = insert(N, nullptr); + S->IsUsedInRegularObj = true; + if (WasInserted || isa(S) || isa(S)) { + replaceSymbol(S, N, F); + return S; } - reportDuplicate(s, f); + reportDuplicate(S, F); return nullptr; } -Symbol *SymbolTable::addImportThunk(StringRef name, DefinedImportData *id, - uint16_t machine) { - Symbol *s; - bool wasInserted; - std::tie(s, wasInserted) = insert(name, nullptr); - s->isUsedInRegularObj = true; - if (wasInserted || isa(s) || s->isLazy()) { - replaceSymbol(s, name, id, machine); - return s; +Symbol *SymbolTable::addImportThunk(StringRef Name, DefinedImportData *ID, + uint16_t Machine) { + Symbol *S; + bool WasInserted; + std::tie(S, WasInserted) = insert(Name, nullptr); + S->IsUsedInRegularObj = true; + if (WasInserted || isa(S) || isa(S)) { + replaceSymbol(S, Name, ID, Machine); + return S; } - reportDuplicate(s, id->file); + reportDuplicate(S, ID->File); return nullptr; } -void SymbolTable::addLibcall(StringRef name) { - Symbol *sym = findUnderscore(name); - if (!sym) - return; - - if (auto *l = dyn_cast(sym)) { - MemoryBufferRef mb = l->getMemberBuffer(); - if (isBitcode(mb)) - addUndefined(sym->getName()); - } else if (LazyObject *o = dyn_cast(sym)) { - if (isBitcode(o->file->mb)) - addUndefined(sym->getName()); - } -} - std::vector SymbolTable::getChunks() { - std::vector res; - for (ObjFile *file : ObjFile::instances) { - ArrayRef v = file->getChunks(); - res.insert(res.end(), v.begin(), v.end()); + std::vector Res; + for (ObjFile *File : ObjFile::Instances) { + ArrayRef V = File->getChunks(); + Res.insert(Res.end(), V.begin(), V.end()); } - return res; + return Res; } -Symbol *SymbolTable::find(StringRef name) { - return symMap.lookup(CachedHashStringRef(name)); +Symbol *SymbolTable::find(StringRef Name) { + return SymMap.lookup(CachedHashStringRef(Name)); } -Symbol *SymbolTable::findUnderscore(StringRef name) { - if (config->machine == I386) - return find(("_" + name).str()); - return find(name); +Symbol *SymbolTable::findUnderscore(StringRef Name) { + if (Config->Machine == I386) + return find(("_" + Name).str()); + return find(Name); } // Return all symbols that start with Prefix, possibly ignoring the first // character of Prefix or the first character symbol. -std::vector SymbolTable::getSymsWithPrefix(StringRef prefix) { - std::vector syms; - for (auto pair : symMap) { - StringRef name = pair.first.val(); - if (name.startswith(prefix) || name.startswith(prefix.drop_front()) || - name.drop_front().startswith(prefix) || - name.drop_front().startswith(prefix.drop_front())) { - syms.push_back(pair.second); +std::vector SymbolTable::getSymsWithPrefix(StringRef Prefix) { + std::vector Syms; + for (auto Pair : SymMap) { + StringRef Name = Pair.first.val(); + if (Name.startswith(Prefix) || Name.startswith(Prefix.drop_front()) || + Name.drop_front().startswith(Prefix) || + Name.drop_front().startswith(Prefix.drop_front())) { + Syms.push_back(Pair.second); } } - return syms; + return Syms; } -Symbol *SymbolTable::findMangle(StringRef name) { - if (Symbol *sym = find(name)) - if (!isa(sym)) - return sym; +Symbol *SymbolTable::findMangle(StringRef Name) { + if (Symbol *Sym = find(Name)) + if (!isa(Sym)) + return Sym; // Efficient fuzzy string lookup is impossible with a hash table, so iterate // the symbol table once and collect all possibly matching symbols into this // vector. Then compare each possibly matching symbol with each possible // mangling. - std::vector syms = getSymsWithPrefix(name); - auto findByPrefix = [&syms](const Twine &t) -> Symbol * { - std::string prefix = t.str(); - for (auto *s : syms) - if (s->getName().startswith(prefix)) - return s; + std::vector Syms = getSymsWithPrefix(Name); + auto FindByPrefix = [&Syms](const Twine &T) -> Symbol * { + std::string Prefix = T.str(); + for (auto *S : Syms) + if (S->getName().startswith(Prefix)) + return S; return nullptr; }; // For non-x86, just look for C++ functions. - if (config->machine != I386) - return findByPrefix("?" + name + "@@Y"); + if (Config->Machine != I386) + return FindByPrefix("?" + Name + "@@Y"); - if (!name.startswith("_")) + if (!Name.startswith("_")) return nullptr; // Search for x86 stdcall function. - if (Symbol *s = findByPrefix(name + "@")) - return s; + if (Symbol *S = FindByPrefix(Name + "@")) + return S; // Search for x86 fastcall function. - if (Symbol *s = findByPrefix("@" + name.substr(1) + "@")) - return s; + if (Symbol *S = FindByPrefix("@" + Name.substr(1) + "@")) + return S; // Search for x86 vectorcall function. - if (Symbol *s = findByPrefix(name.substr(1) + "@@")) - return s; + if (Symbol *S = FindByPrefix(Name.substr(1) + "@@")) + return S; // Search for x86 C++ non-member function. - return findByPrefix("?" + name.substr(1) + "@@Y"); + return FindByPrefix("?" + Name.substr(1) + "@@Y"); } -Symbol *SymbolTable::addUndefined(StringRef name) { - return addUndefined(name, nullptr, false); +Symbol *SymbolTable::addUndefined(StringRef Name) { + return addUndefined(Name, nullptr, false); } std::vector SymbolTable::compileBitcodeFiles() { - lto.reset(new BitcodeCompiler); - for (BitcodeFile *f : BitcodeFile::instances) - lto->add(*f); - return lto->compile(); + LTO.reset(new BitcodeCompiler); + for (BitcodeFile *F : BitcodeFile::Instances) + LTO->add(*F); + return LTO->compile(); } void SymbolTable::addCombinedLTOObjects() { - if (BitcodeFile::instances.empty()) + if (BitcodeFile::Instances.empty()) return; - ScopedTimer t(ltoTimer); - for (StringRef object : compileBitcodeFiles()) { - auto *obj = make(MemoryBufferRef(object, "lto.tmp")); - obj->parse(); - ObjFile::instances.push_back(obj); + ScopedTimer T(LTOTimer); + for (StringRef Object : compileBitcodeFiles()) { + auto *Obj = make(MemoryBufferRef(Object, "lto.tmp")); + Obj->parse(); + ObjFile::Instances.push_back(Obj); } } diff --git a/lld/COFF/SymbolTable.h b/lld/COFF/SymbolTable.h index 4ae818ef292ebb..05417cfefeac37 100644 --- a/lld/COFF/SymbolTable.h +++ b/lld/COFF/SymbolTable.h @@ -29,7 +29,7 @@ class Defined; class DefinedAbsolute; class DefinedRegular; class DefinedRelative; -class LazyArchive; +class Lazy; class SectionChunk; class Symbol; @@ -47,31 +47,28 @@ class Symbol; // There is one add* function per symbol type. class SymbolTable { public: - void addFile(InputFile *file); - - // Emit errors for symbols that cannot be resolved. - void reportUnresolvable(); + void addFile(InputFile *File); // Try to resolve any undefined symbols and update the symbol table // accordingly, then print an error message for any remaining undefined - // symbols and warn about imported local symbols. - void resolveRemainingUndefines(); + // symbols. + void reportRemainingUndefines(); void loadMinGWAutomaticImports(); - bool handleMinGWAutomaticImport(Symbol *sym, StringRef name); + bool handleMinGWAutomaticImport(Symbol *Sym, StringRef Name); // Returns a list of chunks of selected symbols. std::vector getChunks(); // Returns a symbol for a given name. Returns a nullptr if not found. - Symbol *find(StringRef name); - Symbol *findUnderscore(StringRef name); + Symbol *find(StringRef Name); + Symbol *findUnderscore(StringRef Name); // Occasionally we have to resolve an undefined symbol to its // mangled symbol. This function tries to find a mangled name // for U from the symbol table, and if found, set the symbol as // a weak alias for U. - Symbol *findMangle(StringRef name); + Symbol *findMangle(StringRef Name); // Build a set of COFF objects representing the combined contents of // BitcodeFiles and add them to the symbol table. Called after all files are @@ -80,58 +77,53 @@ class SymbolTable { std::vector compileBitcodeFiles(); // Creates an Undefined symbol for a given name. - Symbol *addUndefined(StringRef name); - - Symbol *addSynthetic(StringRef n, Chunk *c); - Symbol *addAbsolute(StringRef n, uint64_t va); - - Symbol *addUndefined(StringRef name, InputFile *f, bool isWeakAlias); - void addLazyArchive(ArchiveFile *f, const Archive::Symbol &sym); - void addLazyObject(LazyObjFile *f, StringRef n); - Symbol *addAbsolute(StringRef n, COFFSymbolRef s); - Symbol *addRegular(InputFile *f, StringRef n, - const llvm::object::coff_symbol_generic *s = nullptr, - SectionChunk *c = nullptr); + Symbol *addUndefined(StringRef Name); + + Symbol *addSynthetic(StringRef N, Chunk *C); + Symbol *addAbsolute(StringRef N, uint64_t VA); + + Symbol *addUndefined(StringRef Name, InputFile *F, bool IsWeakAlias); + void addLazy(ArchiveFile *F, const Archive::Symbol Sym); + Symbol *addAbsolute(StringRef N, COFFSymbolRef S); + Symbol *addRegular(InputFile *F, StringRef N, + const llvm::object::coff_symbol_generic *S = nullptr, + SectionChunk *C = nullptr); std::pair - addComdat(InputFile *f, StringRef n, - const llvm::object::coff_symbol_generic *s = nullptr); - Symbol *addCommon(InputFile *f, StringRef n, uint64_t size, - const llvm::object::coff_symbol_generic *s = nullptr, - CommonChunk *c = nullptr); - Symbol *addImportData(StringRef n, ImportFile *f); - Symbol *addImportThunk(StringRef name, DefinedImportData *s, - uint16_t machine); - void addLibcall(StringRef name); - - void reportDuplicate(Symbol *existing, InputFile *newFile); + addComdat(InputFile *F, StringRef N, + const llvm::object::coff_symbol_generic *S = nullptr); + Symbol *addCommon(InputFile *F, StringRef N, uint64_t Size, + const llvm::object::coff_symbol_generic *S = nullptr, + CommonChunk *C = nullptr); + Symbol *addImportData(StringRef N, ImportFile *F); + Symbol *addImportThunk(StringRef Name, DefinedImportData *S, + uint16_t Machine); + + void reportDuplicate(Symbol *Existing, InputFile *NewFile); // A list of chunks which to be added to .rdata. - std::vector localImportChunks; + std::vector LocalImportChunks; // Iterates symbols in non-determinstic hash table order. - template void forEachSymbol(T callback) { - for (auto &pair : symMap) - callback(pair.second); + template void forEachSymbol(T Callback) { + for (auto &Pair : SymMap) + Callback(Pair.second); } private: - /// Given a name without "__imp_" prefix, returns a defined symbol - /// with the "__imp_" prefix, if it exists. - Defined *impSymbol(StringRef name); /// Inserts symbol if not already present. - std::pair insert(StringRef name); - /// Same as insert(Name), but also sets isUsedInRegularObj. - std::pair insert(StringRef name, InputFile *f); + std::pair insert(StringRef Name); + /// Same as insert(Name), but also sets IsUsedInRegularObj. + std::pair insert(StringRef Name, InputFile *F); - std::vector getSymsWithPrefix(StringRef prefix); + std::vector getSymsWithPrefix(StringRef Prefix); - llvm::DenseMap symMap; - std::unique_ptr lto; + llvm::DenseMap SymMap; + std::unique_ptr LTO; }; -extern SymbolTable *symtab; +extern SymbolTable *Symtab; -std::vector getSymbolLocations(ObjFile *file, uint32_t symIndex); +std::vector getSymbolLocations(ObjFile *File, uint32_t SymIndex); } // namespace coff } // namespace lld diff --git a/lld/COFF/Symbols.cpp b/lld/COFF/Symbols.cpp index 0b89fc65f789f1..a23429ef8354d1 100644 --- a/lld/COFF/Symbols.cpp +++ b/lld/COFF/Symbols.cpp @@ -20,34 +20,18 @@ using namespace llvm::object; using namespace lld::coff; -namespace lld { - static_assert(sizeof(SymbolUnion) <= 48, "symbols should be optimized for memory usage"); // Returns a symbol name for an error message. -static std::string demangle(StringRef symName) { - if (config->demangle) { - if (Optional s = demangleMSVC(symName)) - return *s; - if (config->mingw) { - StringRef demangleInput = symName; - std::string prefix; - if (demangleInput.consume_front("__imp_")) - prefix = "__declspec(dllimport) "; - if (config->machine == I386) - demangleInput.consume_front("_"); - if (Optional s = demangleItanium(demangleInput)) - return prefix + *s; - } - } - return symName; -} -std::string toString(coff::Symbol &b) { return demangle(b.getName()); } -std::string toCOFFString(const Archive::Symbol &b) { - return demangle(b.getName()); +std::string lld::toString(coff::Symbol &B) { + if (Config->Demangle) + if (Optional S = lld::demangleMSVC(B.getName())) + return *S; + return B.getName(); } +namespace lld { namespace coff { StringRef Symbol::getName() { @@ -58,87 +42,76 @@ StringRef Symbol::getName() { // name. Object files contain lots of non-external symbols, and creating // StringRefs for them (which involves lots of strlen() on the string table) // is a waste of time. - if (nameData == nullptr) { - auto *d = cast(this); - StringRef nameStr; - cast(d->file)->getCOFFObj()->getSymbolName(d->sym, nameStr); - nameData = nameStr.data(); - nameSize = nameStr.size(); - assert(nameSize == nameStr.size() && "name length truncated"); + if (NameData == nullptr) { + auto *D = cast(this); + StringRef NameStr; + cast(D->File)->getCOFFObj()->getSymbolName(D->Sym, NameStr); + NameData = NameStr.data(); + NameSize = NameStr.size(); + assert(NameSize == NameStr.size() && "name length truncated"); } - return StringRef(nameData, nameSize); + return StringRef(NameData, NameSize); } InputFile *Symbol::getFile() { - if (auto *sym = dyn_cast(this)) - return sym->file; - if (auto *sym = dyn_cast(this)) - return sym->file; - if (auto *sym = dyn_cast(this)) - return sym->file; + if (auto *Sym = dyn_cast(this)) + return Sym->File; + if (auto *Sym = dyn_cast(this)) + return Sym->File; return nullptr; } bool Symbol::isLive() const { - if (auto *r = dyn_cast(this)) - return r->getChunk()->live; - if (auto *imp = dyn_cast(this)) - return imp->file->live; - if (auto *imp = dyn_cast(this)) - return imp->wrappedSym->file->thunkLive; + if (auto *R = dyn_cast(this)) + return R->getChunk()->Live; + if (auto *Imp = dyn_cast(this)) + return Imp->File->Live; + if (auto *Imp = dyn_cast(this)) + return Imp->WrappedSym->File->ThunkLive; // Assume any other kind of symbol is live. return true; } // MinGW specific. -void Symbol::replaceKeepingName(Symbol *other, size_t size) { - StringRef origName = getName(); - memcpy(this, other, size); - nameData = origName.data(); - nameSize = origName.size(); +void Symbol::replaceKeepingName(Symbol *Other, size_t Size) { + StringRef OrigName = getName(); + memcpy(this, Other, Size); + NameData = OrigName.data(); + NameSize = OrigName.size(); } COFFSymbolRef DefinedCOFF::getCOFFSymbol() { - size_t symSize = cast(file)->getCOFFObj()->getSymbolTableEntrySize(); - if (symSize == sizeof(coff_symbol16)) - return COFFSymbolRef(reinterpret_cast(sym)); - assert(symSize == sizeof(coff_symbol32)); - return COFFSymbolRef(reinterpret_cast(sym)); + size_t SymSize = cast(File)->getCOFFObj()->getSymbolTableEntrySize(); + if (SymSize == sizeof(coff_symbol16)) + return COFFSymbolRef(reinterpret_cast(Sym)); + assert(SymSize == sizeof(coff_symbol32)); + return COFFSymbolRef(reinterpret_cast(Sym)); } -uint16_t DefinedAbsolute::numOutputSections; - -static Chunk *makeImportThunk(DefinedImportData *s, uint16_t machine) { - if (machine == AMD64) - return make(s); - if (machine == I386) - return make(s); - if (machine == ARM64) - return make(s); - assert(machine == ARMNT); - return make(s); +uint16_t DefinedAbsolute::NumOutputSections; + +static Chunk *makeImportThunk(DefinedImportData *S, uint16_t Machine) { + if (Machine == AMD64) + return make(S); + if (Machine == I386) + return make(S); + if (Machine == ARM64) + return make(S); + assert(Machine == ARMNT); + return make(S); } -DefinedImportThunk::DefinedImportThunk(StringRef name, DefinedImportData *s, - uint16_t machine) - : Defined(DefinedImportThunkKind, name), wrappedSym(s), - data(makeImportThunk(s, machine)) {} +DefinedImportThunk::DefinedImportThunk(StringRef Name, DefinedImportData *S, + uint16_t Machine) + : Defined(DefinedImportThunkKind, Name), WrappedSym(S), + Data(makeImportThunk(S, Machine)) {} Defined *Undefined::getWeakAlias() { // A weak alias may be a weak alias to another symbol, so check recursively. - for (Symbol *a = weakAlias; a; a = cast(a)->weakAlias) - if (auto *d = dyn_cast(a)) - return d; + for (Symbol *A = WeakAlias; A; A = cast(A)->WeakAlias) + if (auto *D = dyn_cast(A)) + return D; return nullptr; } - -MemoryBufferRef LazyArchive::getMemberBuffer() { - Archive::Child c = - CHECK(sym.getMember(), - "could not get the member for symbol " + toCOFFString(sym)); - return CHECK(c.getMemoryBufferRef(), - "could not get the buffer for the member defining symbol " + - toCOFFString(sym)); -} } // namespace coff } // namespace lld diff --git a/lld/COFF/Symbols.h b/lld/COFF/Symbols.h index fd79bd5065b1e1..ee0c0e7b05858c 100644 --- a/lld/COFF/Symbols.h +++ b/lld/COFF/Symbols.h @@ -21,14 +21,6 @@ #include namespace lld { - -std::string toString(coff::Symbol &b); - -// There are two different ways to convert an Archive::Symbol to a string: -// One for Microsoft name mangling and one for Itanium name mangling. -// Call the functions toCOFFString and toELFString, not just toString. -std::string toCOFFString(const coff::Archive::Symbol &b); - namespace coff { using llvm::object::Archive; @@ -59,19 +51,21 @@ class Symbol { DefinedSyntheticKind, UndefinedKind, - LazyArchiveKind, - LazyObjectKind, + LazyKind, LastDefinedCOFFKind = DefinedCommonKind, LastDefinedKind = DefinedSyntheticKind, }; - Kind kind() const { return static_cast(symbolKind); } + Kind kind() const { return static_cast(SymbolKind); } + + // Returns true if this is an external symbol. + bool isExternal() { return IsExternal; } // Returns the symbol name. StringRef getName(); - void replaceKeepingName(Symbol *other, size_t size); + void replaceKeepingName(Symbol *Other, size_t Size); // Returns the file from which this symbol was created. InputFile *getFile(); @@ -80,56 +74,52 @@ class Symbol { // after calling markLive. bool isLive() const; - bool isLazy() const { - return symbolKind == LazyArchiveKind || symbolKind == LazyObjectKind; - } - protected: friend SymbolTable; - explicit Symbol(Kind k, StringRef n = "") - : symbolKind(k), isExternal(true), isCOMDAT(false), - writtenToSymtab(false), pendingArchiveLoad(false), isGCRoot(false), - isRuntimePseudoReloc(false), nameSize(n.size()), - nameData(n.empty() ? nullptr : n.data()) {} + explicit Symbol(Kind K, StringRef N = "") + : SymbolKind(K), IsExternal(true), IsCOMDAT(false), + WrittenToSymtab(false), PendingArchiveLoad(false), IsGCRoot(false), + IsRuntimePseudoReloc(false), NameSize(N.size()), + NameData(N.empty() ? nullptr : N.data()) {} - const unsigned symbolKind : 8; - unsigned isExternal : 1; + const unsigned SymbolKind : 8; + unsigned IsExternal : 1; -public: // This bit is used by the \c DefinedRegular subclass. - unsigned isCOMDAT : 1; + unsigned IsCOMDAT : 1; +public: // This bit is used by Writer::createSymbolAndStringTable() to prevent // symbols from being written to the symbol table more than once. - unsigned writtenToSymtab : 1; + unsigned WrittenToSymtab : 1; // True if this symbol was referenced by a regular (non-bitcode) object. - unsigned isUsedInRegularObj : 1; + unsigned IsUsedInRegularObj : 1; // True if we've seen both a lazy and an undefined symbol with this symbol // name, which means that we have enqueued an archive member load and should // not load any more archive members to resolve the same symbol. - unsigned pendingArchiveLoad : 1; + unsigned PendingArchiveLoad : 1; /// True if we've already added this symbol to the list of GC roots. - unsigned isGCRoot : 1; + unsigned IsGCRoot : 1; - unsigned isRuntimePseudoReloc : 1; + unsigned IsRuntimePseudoReloc : 1; protected: // Symbol name length. Assume symbol lengths fit in a 32-bit integer. - uint32_t nameSize; + uint32_t NameSize; - const char *nameData; + const char *NameData; }; // The base class for any defined symbols, including absolute symbols, // etc. class Defined : public Symbol { public: - Defined(Kind k, StringRef n) : Symbol(k, n) {} + Defined(Kind K, StringRef N) : Symbol(K, N) {} - static bool classof(const Symbol *s) { return s->kind() <= LastDefinedKind; } + static bool classof(const Symbol *S) { return S->kind() <= LastDefinedKind; } // Returns the RVA (relative virtual address) of this symbol. The // writer sets and uses RVAs. @@ -148,154 +138,150 @@ class DefinedCOFF : public Defined { friend Symbol; public: - DefinedCOFF(Kind k, InputFile *f, StringRef n, const coff_symbol_generic *s) - : Defined(k, n), file(f), sym(s) {} + DefinedCOFF(Kind K, InputFile *F, StringRef N, const coff_symbol_generic *S) + : Defined(K, N), File(F), Sym(S) {} - static bool classof(const Symbol *s) { - return s->kind() <= LastDefinedCOFFKind; + static bool classof(const Symbol *S) { + return S->kind() <= LastDefinedCOFFKind; } - InputFile *getFile() { return file; } + InputFile *getFile() { return File; } COFFSymbolRef getCOFFSymbol(); - InputFile *file; + InputFile *File; protected: - const coff_symbol_generic *sym; + const coff_symbol_generic *Sym; }; // Regular defined symbols read from object file symbol tables. class DefinedRegular : public DefinedCOFF { public: - DefinedRegular(InputFile *f, StringRef n, bool isCOMDAT, - bool isExternal = false, - const coff_symbol_generic *s = nullptr, - SectionChunk *c = nullptr) - : DefinedCOFF(DefinedRegularKind, f, n, s), data(c ? &c->repl : nullptr) { - this->isExternal = isExternal; - this->isCOMDAT = isCOMDAT; + DefinedRegular(InputFile *F, StringRef N, bool IsCOMDAT, + bool IsExternal = false, + const coff_symbol_generic *S = nullptr, + SectionChunk *C = nullptr) + : DefinedCOFF(DefinedRegularKind, F, N, S), Data(C ? &C->Repl : nullptr) { + this->IsExternal = IsExternal; + this->IsCOMDAT = IsCOMDAT; } - static bool classof(const Symbol *s) { - return s->kind() == DefinedRegularKind; + static bool classof(const Symbol *S) { + return S->kind() == DefinedRegularKind; } - uint64_t getRVA() const { return (*data)->getRVA() + sym->Value; } - SectionChunk *getChunk() const { return *data; } - uint32_t getValue() const { return sym->Value; } + uint64_t getRVA() const { return (*Data)->getRVA() + Sym->Value; } + bool isCOMDAT() const { return IsCOMDAT; } + SectionChunk *getChunk() const { return *Data; } + uint32_t getValue() const { return Sym->Value; } - SectionChunk **data; + SectionChunk **Data; }; class DefinedCommon : public DefinedCOFF { public: - DefinedCommon(InputFile *f, StringRef n, uint64_t size, - const coff_symbol_generic *s = nullptr, - CommonChunk *c = nullptr) - : DefinedCOFF(DefinedCommonKind, f, n, s), data(c), size(size) { - this->isExternal = true; + DefinedCommon(InputFile *F, StringRef N, uint64_t Size, + const coff_symbol_generic *S = nullptr, + CommonChunk *C = nullptr) + : DefinedCOFF(DefinedCommonKind, F, N, S), Data(C), Size(Size) { + this->IsExternal = true; } - static bool classof(const Symbol *s) { - return s->kind() == DefinedCommonKind; + static bool classof(const Symbol *S) { + return S->kind() == DefinedCommonKind; } - uint64_t getRVA() { return data->getRVA(); } - CommonChunk *getChunk() { return data; } + uint64_t getRVA() { return Data->getRVA(); } + CommonChunk *getChunk() { return Data; } private: friend SymbolTable; - uint64_t getSize() const { return size; } - CommonChunk *data; - uint64_t size; + uint64_t getSize() const { return Size; } + CommonChunk *Data; + uint64_t Size; }; // Absolute symbols. class DefinedAbsolute : public Defined { public: - DefinedAbsolute(StringRef n, COFFSymbolRef s) - : Defined(DefinedAbsoluteKind, n), va(s.getValue()) { - isExternal = s.isExternal(); + DefinedAbsolute(StringRef N, COFFSymbolRef S) + : Defined(DefinedAbsoluteKind, N), VA(S.getValue()) { + IsExternal = S.isExternal(); } - DefinedAbsolute(StringRef n, uint64_t v) - : Defined(DefinedAbsoluteKind, n), va(v) {} + DefinedAbsolute(StringRef N, uint64_t V) + : Defined(DefinedAbsoluteKind, N), VA(V) {} - static bool classof(const Symbol *s) { - return s->kind() == DefinedAbsoluteKind; + static bool classof(const Symbol *S) { + return S->kind() == DefinedAbsoluteKind; } - uint64_t getRVA() { return va - config->imageBase; } - void setVA(uint64_t v) { va = v; } + uint64_t getRVA() { return VA - Config->ImageBase; } + void setVA(uint64_t V) { VA = V; } // Section index relocations against absolute symbols resolve to // this 16 bit number, and it is the largest valid section index // plus one. This variable keeps it. - static uint16_t numOutputSections; + static uint16_t NumOutputSections; private: - uint64_t va; + uint64_t VA; }; // This symbol is used for linker-synthesized symbols like __ImageBase and // __safe_se_handler_table. class DefinedSynthetic : public Defined { public: - explicit DefinedSynthetic(StringRef name, Chunk *c) - : Defined(DefinedSyntheticKind, name), c(c) {} + explicit DefinedSynthetic(StringRef Name, Chunk *C) + : Defined(DefinedSyntheticKind, Name), C(C) {} - static bool classof(const Symbol *s) { - return s->kind() == DefinedSyntheticKind; + static bool classof(const Symbol *S) { + return S->kind() == DefinedSyntheticKind; } // A null chunk indicates that this is __ImageBase. Otherwise, this is some // other synthesized chunk, like SEHTableChunk. - uint32_t getRVA() { return c ? c->getRVA() : 0; } - Chunk *getChunk() { return c; } + uint32_t getRVA() { return C ? C->getRVA() : 0; } + Chunk *getChunk() { return C; } private: - Chunk *c; + Chunk *C; }; // This class represents a symbol defined in an archive file. It is // created from an archive file header, and it knows how to load an // object file from an archive to replace itself with a defined -// symbol. If the resolver finds both Undefined and LazyArchive for -// the same name, it will ask the LazyArchive to load a file. -class LazyArchive : public Symbol { +// symbol. If the resolver finds both Undefined and Lazy for +// the same name, it will ask the Lazy to load a file. +class Lazy : public Symbol { public: - LazyArchive(ArchiveFile *f, const Archive::Symbol s) - : Symbol(LazyArchiveKind, s.getName()), file(f), sym(s) {} + Lazy(ArchiveFile *F, const Archive::Symbol S) + : Symbol(LazyKind, S.getName()), File(F), Sym(S) {} - static bool classof(const Symbol *s) { return s->kind() == LazyArchiveKind; } + static bool classof(const Symbol *S) { return S->kind() == LazyKind; } - MemoryBufferRef getMemberBuffer(); + ArchiveFile *File; - ArchiveFile *file; - const Archive::Symbol sym; -}; +private: + friend SymbolTable; -class LazyObject : public Symbol { -public: - LazyObject(LazyObjFile *f, StringRef n) - : Symbol(LazyObjectKind, n), file(f) {} - static bool classof(const Symbol *s) { return s->kind() == LazyObjectKind; } - LazyObjFile *file; +private: + const Archive::Symbol Sym; }; // Undefined symbols. class Undefined : public Symbol { public: - explicit Undefined(StringRef n) : Symbol(UndefinedKind, n) {} + explicit Undefined(StringRef N) : Symbol(UndefinedKind, N) {} - static bool classof(const Symbol *s) { return s->kind() == UndefinedKind; } + static bool classof(const Symbol *S) { return S->kind() == UndefinedKind; } // An undefined symbol can have a fallback symbol which gives an // undefined symbol a second chance if it would remain undefined. // If it remains undefined, it'll be replaced with whatever the // Alias pointer points to. - Symbol *weakAlias = nullptr; + Symbol *WeakAlias = nullptr; // If this symbol is external weak, try to resolve it to a defined // symbol by searching the chain of fallback symbols. Returns the symbol if @@ -311,23 +297,23 @@ class Undefined : public Symbol { // table in an output. The former has "__imp_" prefix. class DefinedImportData : public Defined { public: - DefinedImportData(StringRef n, ImportFile *f) - : Defined(DefinedImportDataKind, n), file(f) { + DefinedImportData(StringRef N, ImportFile *F) + : Defined(DefinedImportDataKind, N), File(F) { } - static bool classof(const Symbol *s) { - return s->kind() == DefinedImportDataKind; + static bool classof(const Symbol *S) { + return S->kind() == DefinedImportDataKind; } - uint64_t getRVA() { return file->location->getRVA(); } - Chunk *getChunk() { return file->location; } - void setLocation(Chunk *addressTable) { file->location = addressTable; } + uint64_t getRVA() { return File->Location->getRVA(); } + Chunk *getChunk() { return File->Location; } + void setLocation(Chunk *AddressTable) { File->Location = AddressTable; } - StringRef getDLLName() { return file->dllName; } - StringRef getExternalName() { return file->externalName; } - uint16_t getOrdinal() { return file->hdr->OrdinalHint; } + StringRef getDLLName() { return File->DLLName; } + StringRef getExternalName() { return File->ExternalName; } + uint16_t getOrdinal() { return File->Hdr->OrdinalHint; } - ImportFile *file; + ImportFile *File; }; // This class represents a symbol for a jump table entry which jumps @@ -337,19 +323,19 @@ class DefinedImportData : public Defined { // a regular name. A function pointer is given as a DefinedImportData. class DefinedImportThunk : public Defined { public: - DefinedImportThunk(StringRef name, DefinedImportData *s, uint16_t machine); + DefinedImportThunk(StringRef Name, DefinedImportData *S, uint16_t Machine); - static bool classof(const Symbol *s) { - return s->kind() == DefinedImportThunkKind; + static bool classof(const Symbol *S) { + return S->kind() == DefinedImportThunkKind; } - uint64_t getRVA() { return data->getRVA(); } - Chunk *getChunk() { return data; } + uint64_t getRVA() { return Data->getRVA(); } + Chunk *getChunk() { return Data; } - DefinedImportData *wrappedSym; + DefinedImportData *WrappedSym; private: - Chunk *data; + Chunk *Data; }; // If you have a symbol "foo" in your object file, a symbol name @@ -359,18 +345,18 @@ class DefinedImportThunk : public Defined { // This is here just for compatibility with MSVC. class DefinedLocalImport : public Defined { public: - DefinedLocalImport(StringRef n, Defined *s) - : Defined(DefinedLocalImportKind, n), data(make(s)) {} + DefinedLocalImport(StringRef N, Defined *S) + : Defined(DefinedLocalImportKind, N), Data(make(S)) {} - static bool classof(const Symbol *s) { - return s->kind() == DefinedLocalImportKind; + static bool classof(const Symbol *S) { + return S->kind() == DefinedLocalImportKind; } - uint64_t getRVA() { return data->getRVA(); } - Chunk *getChunk() { return data; } + uint64_t getRVA() { return Data->getRVA(); } + Chunk *getChunk() { return Data; } private: - LocalImportChunk *data; + LocalImportChunk *Data; }; inline uint64_t Defined::getRVA() { @@ -389,8 +375,7 @@ inline uint64_t Defined::getRVA() { return cast(this)->getRVA(); case DefinedRegularKind: return cast(this)->getRVA(); - case LazyArchiveKind: - case LazyObjectKind: + case LazyKind: case UndefinedKind: llvm_unreachable("Cannot get the address for an undefined symbol."); } @@ -413,8 +398,7 @@ inline Chunk *Defined::getChunk() { return cast(this)->getChunk(); case DefinedCommonKind: return cast(this)->getChunk(); - case LazyArchiveKind: - case LazyObjectKind: + case LazyKind: case UndefinedKind: llvm_unreachable("Cannot get the chunk of an undefined symbol."); } @@ -425,20 +409,19 @@ inline Chunk *Defined::getChunk() { // object. We allocate memory using this class and instantiate a symbol // using the placement new. union SymbolUnion { - alignas(DefinedRegular) char a[sizeof(DefinedRegular)]; - alignas(DefinedCommon) char b[sizeof(DefinedCommon)]; - alignas(DefinedAbsolute) char c[sizeof(DefinedAbsolute)]; - alignas(DefinedSynthetic) char d[sizeof(DefinedSynthetic)]; - alignas(LazyArchive) char e[sizeof(LazyArchive)]; - alignas(Undefined) char f[sizeof(Undefined)]; - alignas(DefinedImportData) char g[sizeof(DefinedImportData)]; - alignas(DefinedImportThunk) char h[sizeof(DefinedImportThunk)]; - alignas(DefinedLocalImport) char i[sizeof(DefinedLocalImport)]; - alignas(LazyObject) char j[sizeof(LazyObject)]; + alignas(DefinedRegular) char A[sizeof(DefinedRegular)]; + alignas(DefinedCommon) char B[sizeof(DefinedCommon)]; + alignas(DefinedAbsolute) char C[sizeof(DefinedAbsolute)]; + alignas(DefinedSynthetic) char D[sizeof(DefinedSynthetic)]; + alignas(Lazy) char E[sizeof(Lazy)]; + alignas(Undefined) char F[sizeof(Undefined)]; + alignas(DefinedImportData) char G[sizeof(DefinedImportData)]; + alignas(DefinedImportThunk) char H[sizeof(DefinedImportThunk)]; + alignas(DefinedLocalImport) char I[sizeof(DefinedLocalImport)]; }; template -void replaceSymbol(Symbol *s, ArgT &&... arg) { +void replaceSymbol(Symbol *S, ArgT &&... Arg) { static_assert(std::is_trivially_destructible(), "Symbol types must be trivially destructible"); static_assert(sizeof(T) <= sizeof(SymbolUnion), "Symbol too small"); @@ -446,10 +429,11 @@ void replaceSymbol(Symbol *s, ArgT &&... arg) { "SymbolUnion not aligned enough"); assert(static_cast(static_cast(nullptr)) == nullptr && "Not a Symbol"); - new (s) T(std::forward(arg)...); + new (S) T(std::forward(Arg)...); } } // namespace coff +std::string toString(coff::Symbol &B); } // namespace lld #endif diff --git a/lld/COFF/TypeMerger.h b/lld/COFF/TypeMerger.h index e2cfe668cfa591..6580770bdd057c 100644 --- a/lld/COFF/TypeMerger.h +++ b/lld/COFF/TypeMerger.h @@ -19,44 +19,44 @@ namespace coff { class TypeMerger { public: - TypeMerger(llvm::BumpPtrAllocator &alloc) - : typeTable(alloc), iDTable(alloc), globalTypeTable(alloc), - globalIDTable(alloc) {} + TypeMerger(llvm::BumpPtrAllocator &Alloc) + : TypeTable(Alloc), IDTable(Alloc), GlobalTypeTable(Alloc), + GlobalIDTable(Alloc) {} /// Get the type table or the global type table if /DEBUG:GHASH is enabled. inline llvm::codeview::TypeCollection &getTypeTable() { - if (config->debugGHashes) - return globalTypeTable; - return typeTable; + if (Config->DebugGHashes) + return GlobalTypeTable; + return TypeTable; } /// Get the ID table or the global ID table if /DEBUG:GHASH is enabled. inline llvm::codeview::TypeCollection &getIDTable() { - if (config->debugGHashes) - return globalIDTable; - return iDTable; + if (Config->DebugGHashes) + return GlobalIDTable; + return IDTable; } /// Type records that will go into the PDB TPI stream. - llvm::codeview::MergingTypeTableBuilder typeTable; + llvm::codeview::MergingTypeTableBuilder TypeTable; /// Item records that will go into the PDB IPI stream. - llvm::codeview::MergingTypeTableBuilder iDTable; + llvm::codeview::MergingTypeTableBuilder IDTable; /// Type records that will go into the PDB TPI stream (for /DEBUG:GHASH) - llvm::codeview::GlobalTypeTableBuilder globalTypeTable; + llvm::codeview::GlobalTypeTableBuilder GlobalTypeTable; /// Item records that will go into the PDB IPI stream (for /DEBUG:GHASH) - llvm::codeview::GlobalTypeTableBuilder globalIDTable; + llvm::codeview::GlobalTypeTableBuilder GlobalIDTable; }; /// Map from type index and item index in a type server PDB to the /// corresponding index in the destination PDB. struct CVIndexMap { - llvm::SmallVector tpiMap; - llvm::SmallVector ipiMap; - bool isTypeServerMap = false; - bool isPrecompiledTypeMap = false; + llvm::SmallVector TPIMap; + llvm::SmallVector IPIMap; + bool IsTypeServerMap = false; + bool IsPrecompiledTypeMap = false; }; } // namespace coff diff --git a/lld/COFF/Writer.cpp b/lld/COFF/Writer.cpp index a98af439d04228..a406c531e9e228 100644 --- a/lld/COFF/Writer.cpp +++ b/lld/COFF/Writer.cpp @@ -63,105 +63,105 @@ align 8, db 0 $ nasm -fbin /tmp/DOSProgram.asm -o /tmp/DOSProgram.bin $ xxd -i /tmp/DOSProgram.bin */ -static unsigned char dosProgram[] = { +static unsigned char DOSProgram[] = { 0x0e, 0x1f, 0xba, 0x0e, 0x00, 0xb4, 0x09, 0xcd, 0x21, 0xb8, 0x01, 0x4c, 0xcd, 0x21, 0x54, 0x68, 0x69, 0x73, 0x20, 0x70, 0x72, 0x6f, 0x67, 0x72, 0x61, 0x6d, 0x20, 0x63, 0x61, 0x6e, 0x6e, 0x6f, 0x74, 0x20, 0x62, 0x65, 0x20, 0x72, 0x75, 0x6e, 0x20, 0x69, 0x6e, 0x20, 0x44, 0x4f, 0x53, 0x20, 0x6d, 0x6f, 0x64, 0x65, 0x2e, 0x24, 0x00, 0x00 }; -static_assert(sizeof(dosProgram) % 8 == 0, +static_assert(sizeof(DOSProgram) % 8 == 0, "DOSProgram size must be multiple of 8"); -static const int dosStubSize = sizeof(dos_header) + sizeof(dosProgram); -static_assert(dosStubSize % 8 == 0, "DOSStub size must be multiple of 8"); +static const int DOSStubSize = sizeof(dos_header) + sizeof(DOSProgram); +static_assert(DOSStubSize % 8 == 0, "DOSStub size must be multiple of 8"); -static const int numberOfDataDirectory = 16; +static const int NumberOfDataDirectory = 16; // Global vector of all output sections. After output sections are finalized, // this can be indexed by Chunk::getOutputSection. -static std::vector outputSections; +static std::vector OutputSections; OutputSection *Chunk::getOutputSection() const { - return osidx == 0 ? nullptr : outputSections[osidx - 1]; + return OSIdx == 0 ? nullptr : OutputSections[OSIdx - 1]; } namespace { class DebugDirectoryChunk : public NonSectionChunk { public: - DebugDirectoryChunk(const std::vector &r, bool writeRepro) - : records(r), writeRepro(writeRepro) {} + DebugDirectoryChunk(const std::vector &R, bool WriteRepro) + : Records(R), WriteRepro(WriteRepro) {} size_t getSize() const override { - return (records.size() + int(writeRepro)) * sizeof(debug_directory); + return (Records.size() + int(WriteRepro)) * sizeof(debug_directory); } - void writeTo(uint8_t *b) const override { - auto *d = reinterpret_cast(b); + void writeTo(uint8_t *B) const override { + auto *D = reinterpret_cast(B); - for (const Chunk *record : records) { - OutputSection *os = record->getOutputSection(); - uint64_t offs = os->getFileOff() + (record->getRVA() - os->getRVA()); - fillEntry(d, COFF::IMAGE_DEBUG_TYPE_CODEVIEW, record->getSize(), - record->getRVA(), offs); - ++d; + for (const Chunk *Record : Records) { + OutputSection *OS = Record->getOutputSection(); + uint64_t Offs = OS->getFileOff() + (Record->getRVA() - OS->getRVA()); + fillEntry(D, COFF::IMAGE_DEBUG_TYPE_CODEVIEW, Record->getSize(), + Record->getRVA(), Offs); + ++D; } - if (writeRepro) { + if (WriteRepro) { // FIXME: The COFF spec allows either a 0-sized entry to just say // "the timestamp field is really a hash", or a 4-byte size field // followed by that many bytes containing a longer hash (with the // lowest 4 bytes usually being the timestamp in little-endian order). // Consider storing the full 8 bytes computed by xxHash64 here. - fillEntry(d, COFF::IMAGE_DEBUG_TYPE_REPRO, 0, 0, 0); + fillEntry(D, COFF::IMAGE_DEBUG_TYPE_REPRO, 0, 0, 0); } } - void setTimeDateStamp(uint32_t timeDateStamp) { - for (support::ulittle32_t *tds : timeDateStamps) - *tds = timeDateStamp; + void setTimeDateStamp(uint32_t TimeDateStamp) { + for (support::ulittle32_t *TDS : TimeDateStamps) + *TDS = TimeDateStamp; } private: - void fillEntry(debug_directory *d, COFF::DebugType debugType, size_t size, - uint64_t rva, uint64_t offs) const { - d->Characteristics = 0; - d->TimeDateStamp = 0; - d->MajorVersion = 0; - d->MinorVersion = 0; - d->Type = debugType; - d->SizeOfData = size; - d->AddressOfRawData = rva; - d->PointerToRawData = offs; - - timeDateStamps.push_back(&d->TimeDateStamp); - } - - mutable std::vector timeDateStamps; - const std::vector &records; - bool writeRepro; + void fillEntry(debug_directory *D, COFF::DebugType DebugType, size_t Size, + uint64_t RVA, uint64_t Offs) const { + D->Characteristics = 0; + D->TimeDateStamp = 0; + D->MajorVersion = 0; + D->MinorVersion = 0; + D->Type = DebugType; + D->SizeOfData = Size; + D->AddressOfRawData = RVA; + D->PointerToRawData = Offs; + + TimeDateStamps.push_back(&D->TimeDateStamp); + } + + mutable std::vector TimeDateStamps; + const std::vector &Records; + bool WriteRepro; }; class CVDebugRecordChunk : public NonSectionChunk { public: size_t getSize() const override { - return sizeof(codeview::DebugInfo) + config->pdbAltPath.size() + 1; + return sizeof(codeview::DebugInfo) + Config->PDBAltPath.size() + 1; } - void writeTo(uint8_t *b) const override { + void writeTo(uint8_t *B) const override { // Save off the DebugInfo entry to backfill the file signature (build id) // in Writer::writeBuildId - buildId = reinterpret_cast(b); + BuildId = reinterpret_cast(B); // variable sized field (PDB Path) - char *p = reinterpret_cast(b + sizeof(*buildId)); - if (!config->pdbAltPath.empty()) - memcpy(p, config->pdbAltPath.data(), config->pdbAltPath.size()); - p[config->pdbAltPath.size()] = '\0'; + char *P = reinterpret_cast(B + sizeof(*BuildId)); + if (!Config->PDBAltPath.empty()) + memcpy(P, Config->PDBAltPath.data(), Config->PDBAltPath.size()); + P[Config->PDBAltPath.size()] = '\0'; } - mutable codeview::DebugInfo *buildId = nullptr; + mutable codeview::DebugInfo *BuildId = nullptr; }; // PartialSection represents a group of chunks that contribute to an @@ -169,15 +169,15 @@ class CVDebugRecordChunk : public NonSectionChunk { // characteristics constitutes the OutputSection. class PartialSectionKey { public: - StringRef name; - unsigned characteristics; + StringRef Name; + unsigned Characteristics; - bool operator<(const PartialSectionKey &other) const { - int c = name.compare(other.name); - if (c == 1) + bool operator<(const PartialSectionKey &Other) const { + int C = Name.compare(Other.Name); + if (C == 1) return false; - if (c == 0) - return characteristics < other.characteristics; + if (C == 0) + return Characteristics < Other.Characteristics; return true; } }; @@ -185,7 +185,7 @@ class PartialSectionKey { // The writer writes a SymbolTable result to a file. class Writer { public: - Writer() : buffer(errorHandler().outputBuffer) {} + Writer() : Buffer(errorHandler().OutputBuffer) {} void run(); private: @@ -202,74 +202,71 @@ class Writer { void removeEmptySections(); void assignOutputSectionIndices(); void createSymbolAndStringTable(); - void openFile(StringRef outputPath); + void openFile(StringRef OutputPath); template void writeHeader(); void createSEHTable(); void createRuntimePseudoRelocs(); void insertCtorDtorSymbols(); void createGuardCFTables(); - void markSymbolsForRVATable(ObjFile *file, - ArrayRef symIdxChunks, - SymbolRVASet &tableSymbols); - void maybeAddRVATable(SymbolRVASet tableSymbols, StringRef tableSym, - StringRef countSym); + void markSymbolsForRVATable(ObjFile *File, + ArrayRef SymIdxChunks, + SymbolRVASet &TableSymbols); + void maybeAddRVATable(SymbolRVASet TableSymbols, StringRef TableSym, + StringRef CountSym); void setSectionPermissions(); void writeSections(); void writeBuildId(); void sortExceptionTable(); - void sortCRTSectionChunks(std::vector &chunks); + void sortCRTSectionChunks(std::vector &Chunks); void addSyntheticIdata(); - void fixPartialSectionChars(StringRef name, uint32_t chars); bool fixGnuImportChunks(); - PartialSection *createPartialSection(StringRef name, uint32_t outChars); - PartialSection *findPartialSection(StringRef name, uint32_t outChars); + PartialSection *createPartialSection(StringRef Name, uint32_t OutChars); + PartialSection *findPartialSection(StringRef Name, uint32_t OutChars); - llvm::Optional createSymbol(Defined *d); - size_t addEntryToStringTable(StringRef str); + llvm::Optional createSymbol(Defined *D); + size_t addEntryToStringTable(StringRef Str); - OutputSection *findSection(StringRef name); + OutputSection *findSection(StringRef Name); void addBaserels(); - void addBaserelBlocks(std::vector &v); + void addBaserelBlocks(std::vector &V); uint32_t getSizeOfInitializedData(); - std::unique_ptr &buffer; - std::map partialSections; - std::vector strtab; - std::vector outputSymtab; - IdataContents idata; - Chunk *importTableStart = nullptr; - uint64_t importTableSize = 0; - Chunk *edataStart = nullptr; - Chunk *edataEnd = nullptr; - Chunk *iatStart = nullptr; - uint64_t iatSize = 0; - DelayLoadContents delayIdata; - EdataContents edata; - bool setNoSEHCharacteristic = false; - - DebugDirectoryChunk *debugDirectory = nullptr; - std::vector debugRecords; - CVDebugRecordChunk *buildId = nullptr; - ArrayRef sectionTable; - - uint64_t fileSize; - uint32_t pointerToSymbolTable = 0; - uint64_t sizeOfImage; - uint64_t sizeOfHeaders; - - OutputSection *textSec; - OutputSection *rdataSec; - OutputSection *buildidSec; - OutputSection *dataSec; - OutputSection *pdataSec; - OutputSection *idataSec; - OutputSection *edataSec; - OutputSection *didatSec; - OutputSection *rsrcSec; - OutputSection *relocSec; - OutputSection *ctorsSec; - OutputSection *dtorsSec; + std::unique_ptr &Buffer; + std::map PartialSections; + std::vector Strtab; + std::vector OutputSymtab; + IdataContents Idata; + Chunk *ImportTableStart = nullptr; + uint64_t ImportTableSize = 0; + Chunk *IATStart = nullptr; + uint64_t IATSize = 0; + DelayLoadContents DelayIdata; + EdataContents Edata; + bool SetNoSEHCharacteristic = false; + + DebugDirectoryChunk *DebugDirectory = nullptr; + std::vector DebugRecords; + CVDebugRecordChunk *BuildId = nullptr; + ArrayRef SectionTable; + + uint64_t FileSize; + uint32_t PointerToSymbolTable = 0; + uint64_t SizeOfImage; + uint64_t SizeOfHeaders; + + OutputSection *TextSec; + OutputSection *RdataSec; + OutputSection *BuildidSec; + OutputSection *DataSec; + OutputSection *PdataSec; + OutputSection *IdataSec; + OutputSection *EdataSec; + OutputSection *DidatSec; + OutputSection *RsrcSec; + OutputSection *RelocSec; + OutputSection *CtorsSec; + OutputSection *DtorsSec; // The first and last .pdata sections in the output file. // @@ -280,85 +277,85 @@ class Writer { // are entirely linker-generated we can keep track of their locations using // the chunks that the linker creates. All .pdata chunks come from input // files, so we need to keep track of them separately. - Chunk *firstPdata = nullptr; - Chunk *lastPdata; + Chunk *FirstPdata = nullptr; + Chunk *LastPdata; }; } // anonymous namespace namespace lld { namespace coff { -static Timer codeLayoutTimer("Code Layout", Timer::root()); -static Timer diskCommitTimer("Commit Output File", Timer::root()); +static Timer CodeLayoutTimer("Code Layout", Timer::root()); +static Timer DiskCommitTimer("Commit Output File", Timer::root()); void writeResult() { Writer().run(); } -void OutputSection::addChunk(Chunk *c) { - chunks.push_back(c); +void OutputSection::addChunk(Chunk *C) { + Chunks.push_back(C); } -void OutputSection::insertChunkAtStart(Chunk *c) { - chunks.insert(chunks.begin(), c); +void OutputSection::insertChunkAtStart(Chunk *C) { + Chunks.insert(Chunks.begin(), C); } -void OutputSection::setPermissions(uint32_t c) { - header.Characteristics &= ~permMask; - header.Characteristics |= c; +void OutputSection::setPermissions(uint32_t C) { + Header.Characteristics &= ~PermMask; + Header.Characteristics |= C; } -void OutputSection::merge(OutputSection *other) { - chunks.insert(chunks.end(), other->chunks.begin(), other->chunks.end()); - other->chunks.clear(); - contribSections.insert(contribSections.end(), other->contribSections.begin(), - other->contribSections.end()); - other->contribSections.clear(); +void OutputSection::merge(OutputSection *Other) { + Chunks.insert(Chunks.end(), Other->Chunks.begin(), Other->Chunks.end()); + Other->Chunks.clear(); + ContribSections.insert(ContribSections.end(), Other->ContribSections.begin(), + Other->ContribSections.end()); + Other->ContribSections.clear(); } // Write the section header to a given buffer. -void OutputSection::writeHeaderTo(uint8_t *buf) { - auto *hdr = reinterpret_cast(buf); - *hdr = header; - if (stringTableOff) { +void OutputSection::writeHeaderTo(uint8_t *Buf) { + auto *Hdr = reinterpret_cast(Buf); + *Hdr = Header; + if (StringTableOff) { // If name is too long, write offset into the string table as a name. - sprintf(hdr->Name, "/%d", stringTableOff); + sprintf(Hdr->Name, "/%d", StringTableOff); } else { - assert(!config->debug || name.size() <= COFF::NameSize || - (hdr->Characteristics & IMAGE_SCN_MEM_DISCARDABLE) == 0); - strncpy(hdr->Name, name.data(), - std::min(name.size(), (size_t)COFF::NameSize)); + assert(!Config->Debug || Name.size() <= COFF::NameSize || + (Hdr->Characteristics & IMAGE_SCN_MEM_DISCARDABLE) == 0); + strncpy(Hdr->Name, Name.data(), + std::min(Name.size(), (size_t)COFF::NameSize)); } } -void OutputSection::addContributingPartialSection(PartialSection *sec) { - contribSections.push_back(sec); +void OutputSection::addContributingPartialSection(PartialSection *Sec) { + ContribSections.push_back(Sec); } } // namespace coff } // namespace lld // Check whether the target address S is in range from a relocation -// of type relType at address P. -static bool isInRange(uint16_t relType, uint64_t s, uint64_t p, int margin) { - if (config->machine == ARMNT) { - int64_t diff = AbsoluteDifference(s, p + 4) + margin; - switch (relType) { +// of type RelType at address P. +static bool isInRange(uint16_t RelType, uint64_t S, uint64_t P, int Margin) { + if (Config->Machine == ARMNT) { + int64_t Diff = AbsoluteDifference(S, P + 4) + Margin; + switch (RelType) { case IMAGE_REL_ARM_BRANCH20T: - return isInt<21>(diff); + return isInt<21>(Diff); case IMAGE_REL_ARM_BRANCH24T: case IMAGE_REL_ARM_BLX23T: - return isInt<25>(diff); + return isInt<25>(Diff); default: return true; } - } else if (config->machine == ARM64) { - int64_t diff = AbsoluteDifference(s, p) + margin; - switch (relType) { + } else if (Config->Machine == ARM64) { + int64_t Diff = AbsoluteDifference(S, P) + Margin; + switch (RelType) { case IMAGE_REL_ARM64_BRANCH26: - return isInt<28>(diff); + return isInt<28>(Diff); case IMAGE_REL_ARM64_BRANCH19: - return isInt<21>(diff); + return isInt<21>(Diff); case IMAGE_REL_ARM64_BRANCH14: - return isInt<16>(diff); + return isInt<16>(Diff); default: return true; } @@ -370,25 +367,25 @@ static bool isInRange(uint16_t relType, uint64_t s, uint64_t p, int margin) { // Return the last thunk for the given target if it is in range, // or create a new one. static std::pair -getThunk(DenseMap &lastThunks, Defined *target, uint64_t p, - uint16_t type, int margin) { - Defined *&lastThunk = lastThunks[target->getRVA()]; - if (lastThunk && isInRange(type, lastThunk->getRVA(), p, margin)) - return {lastThunk, false}; - Chunk *c; - switch (config->machine) { +getThunk(DenseMap &LastThunks, Defined *Target, uint64_t P, + uint16_t Type, int Margin) { + Defined *&LastThunk = LastThunks[Target->getRVA()]; + if (LastThunk && isInRange(Type, LastThunk->getRVA(), P, Margin)) + return {LastThunk, false}; + Chunk *C; + switch (Config->Machine) { case ARMNT: - c = make(target); + C = make(Target); break; case ARM64: - c = make(target); + C = make(Target); break; default: llvm_unreachable("Unexpected architecture"); } - Defined *d = make("", c); - lastThunk = d; - return {d, true}; + Defined *D = make("", C); + LastThunk = D; + return {D, true}; } // This checks all relocations, and for any relocation which isn't in range @@ -402,124 +399,124 @@ getThunk(DenseMap &lastThunks, Defined *target, uint64_t p, // After adding thunks, we verify that all relocations are in range (with // no extra margin requirements). If this failed, we restart (throwing away // the previously created thunks) and retry with a wider margin. -static bool createThunks(OutputSection *os, int margin) { - bool addressesChanged = false; - DenseMap lastThunks; - DenseMap, uint32_t> thunkSymtabIndices; - size_t thunksSize = 0; +static bool createThunks(OutputSection *OS, int Margin) { + bool AddressesChanged = false; + DenseMap LastThunks; + DenseMap, uint32_t> ThunkSymtabIndices; + size_t ThunksSize = 0; // Recheck Chunks.size() each iteration, since we can insert more // elements into it. - for (size_t i = 0; i != os->chunks.size(); ++i) { - SectionChunk *sc = dyn_cast_or_null(os->chunks[i]); - if (!sc) + for (size_t I = 0; I != OS->Chunks.size(); ++I) { + SectionChunk *SC = dyn_cast_or_null(OS->Chunks[I]); + if (!SC) continue; - size_t thunkInsertionSpot = i + 1; + size_t ThunkInsertionSpot = I + 1; // Try to get a good enough estimate of where new thunks will be placed. // Offset this by the size of the new thunks added so far, to make the // estimate slightly better. - size_t thunkInsertionRVA = sc->getRVA() + sc->getSize() + thunksSize; - ObjFile *file = sc->file; - std::vector> relocReplacements; - ArrayRef originalRelocs = - file->getCOFFObj()->getRelocations(sc->header); - for (size_t j = 0, e = originalRelocs.size(); j < e; ++j) { - const coff_relocation &rel = originalRelocs[j]; - Symbol *relocTarget = file->getSymbol(rel.SymbolTableIndex); + size_t ThunkInsertionRVA = SC->getRVA() + SC->getSize() + ThunksSize; + ObjFile *File = SC->File; + std::vector> RelocReplacements; + ArrayRef OriginalRelocs = + File->getCOFFObj()->getRelocations(SC->Header); + for (size_t J = 0, E = OriginalRelocs.size(); J < E; ++J) { + const coff_relocation &Rel = OriginalRelocs[J]; + Symbol *RelocTarget = File->getSymbol(Rel.SymbolTableIndex); // The estimate of the source address P should be pretty accurate, // but we don't know whether the target Symbol address should be - // offset by thunksSize or not (or by some of thunksSize but not all of + // offset by ThunkSize or not (or by some of ThunksSize but not all of // it), giving us some uncertainty once we have added one thunk. - uint64_t p = sc->getRVA() + rel.VirtualAddress + thunksSize; + uint64_t P = SC->getRVA() + Rel.VirtualAddress + ThunksSize; - Defined *sym = dyn_cast_or_null(relocTarget); - if (!sym) + Defined *Sym = dyn_cast_or_null(RelocTarget); + if (!Sym) continue; - uint64_t s = sym->getRVA(); + uint64_t S = Sym->getRVA(); - if (isInRange(rel.Type, s, p, margin)) + if (isInRange(Rel.Type, S, P, Margin)) continue; // If the target isn't in range, hook it up to an existing or new // thunk. - Defined *thunk; - bool wasNew; - std::tie(thunk, wasNew) = getThunk(lastThunks, sym, p, rel.Type, margin); - if (wasNew) { - Chunk *thunkChunk = thunk->getChunk(); - thunkChunk->setRVA( - thunkInsertionRVA); // Estimate of where it will be located. - os->chunks.insert(os->chunks.begin() + thunkInsertionSpot, thunkChunk); - thunkInsertionSpot++; - thunksSize += thunkChunk->getSize(); - thunkInsertionRVA += thunkChunk->getSize(); - addressesChanged = true; + Defined *Thunk; + bool WasNew; + std::tie(Thunk, WasNew) = getThunk(LastThunks, Sym, P, Rel.Type, Margin); + if (WasNew) { + Chunk *ThunkChunk = Thunk->getChunk(); + ThunkChunk->setRVA( + ThunkInsertionRVA); // Estimate of where it will be located. + OS->Chunks.insert(OS->Chunks.begin() + ThunkInsertionSpot, ThunkChunk); + ThunkInsertionSpot++; + ThunksSize += ThunkChunk->getSize(); + ThunkInsertionRVA += ThunkChunk->getSize(); + AddressesChanged = true; } // To redirect the relocation, add a symbol to the parent object file's // symbol table, and replace the relocation symbol table index with the // new index. - auto insertion = thunkSymtabIndices.insert({{file, thunk}, ~0U}); - uint32_t &thunkSymbolIndex = insertion.first->second; - if (insertion.second) - thunkSymbolIndex = file->addRangeThunkSymbol(thunk); - relocReplacements.push_back({j, thunkSymbolIndex}); + auto Insertion = ThunkSymtabIndices.insert({{File, Thunk}, ~0U}); + uint32_t &ThunkSymbolIndex = Insertion.first->second; + if (Insertion.second) + ThunkSymbolIndex = File->addRangeThunkSymbol(Thunk); + RelocReplacements.push_back({J, ThunkSymbolIndex}); } // Get a writable copy of this section's relocations so they can be // modified. If the relocations point into the object file, allocate new // memory. Otherwise, this must be previously allocated memory that can be // modified in place. - ArrayRef curRelocs = sc->getRelocs(); - MutableArrayRef newRelocs; - if (originalRelocs.data() == curRelocs.data()) { - newRelocs = makeMutableArrayRef( - bAlloc.Allocate(originalRelocs.size()), - originalRelocs.size()); + ArrayRef CurRelocs = SC->getRelocs(); + MutableArrayRef NewRelocs; + if (OriginalRelocs.data() == CurRelocs.data()) { + NewRelocs = makeMutableArrayRef( + BAlloc.Allocate(OriginalRelocs.size()), + OriginalRelocs.size()); } else { - newRelocs = makeMutableArrayRef( - const_cast(curRelocs.data()), curRelocs.size()); + NewRelocs = makeMutableArrayRef( + const_cast(CurRelocs.data()), CurRelocs.size()); } // Copy each relocation, but replace the symbol table indices which need // thunks. - auto nextReplacement = relocReplacements.begin(); - auto endReplacement = relocReplacements.end(); - for (size_t i = 0, e = originalRelocs.size(); i != e; ++i) { - newRelocs[i] = originalRelocs[i]; - if (nextReplacement != endReplacement && nextReplacement->first == i) { - newRelocs[i].SymbolTableIndex = nextReplacement->second; - ++nextReplacement; + auto NextReplacement = RelocReplacements.begin(); + auto EndReplacement = RelocReplacements.end(); + for (size_t I = 0, E = OriginalRelocs.size(); I != E; ++I) { + NewRelocs[I] = OriginalRelocs[I]; + if (NextReplacement != EndReplacement && NextReplacement->first == I) { + NewRelocs[I].SymbolTableIndex = NextReplacement->second; + ++NextReplacement; } } - sc->setRelocs(newRelocs); + SC->setRelocs(NewRelocs); } - return addressesChanged; + return AddressesChanged; } // Verify that all relocations are in range, with no extra margin requirements. -static bool verifyRanges(const std::vector chunks) { - for (Chunk *c : chunks) { - SectionChunk *sc = dyn_cast_or_null(c); - if (!sc) +static bool verifyRanges(const std::vector Chunks) { + for (Chunk *C : Chunks) { + SectionChunk *SC = dyn_cast_or_null(C); + if (!SC) continue; - ArrayRef relocs = sc->getRelocs(); - for (size_t j = 0, e = relocs.size(); j < e; ++j) { - const coff_relocation &rel = relocs[j]; - Symbol *relocTarget = sc->file->getSymbol(rel.SymbolTableIndex); + ArrayRef Relocs = SC->getRelocs(); + for (size_t J = 0, E = Relocs.size(); J < E; ++J) { + const coff_relocation &Rel = Relocs[J]; + Symbol *RelocTarget = SC->File->getSymbol(Rel.SymbolTableIndex); - Defined *sym = dyn_cast_or_null(relocTarget); - if (!sym) + Defined *Sym = dyn_cast_or_null(RelocTarget); + if (!Sym) continue; - uint64_t p = sc->getRVA() + rel.VirtualAddress; - uint64_t s = sym->getRVA(); + uint64_t P = SC->getRVA() + Rel.VirtualAddress; + uint64_t S = Sym->getRVA(); - if (!isInRange(rel.Type, s, p, 0)) + if (!isInRange(Rel.Type, S, P, 0)) return false; } } @@ -529,68 +526,68 @@ static bool verifyRanges(const std::vector chunks) { // Assign addresses and add thunks if necessary. void Writer::finalizeAddresses() { assignAddresses(); - if (config->machine != ARMNT && config->machine != ARM64) + if (Config->Machine != ARMNT && Config->Machine != ARM64) return; - size_t origNumChunks = 0; - for (OutputSection *sec : outputSections) { - sec->origChunks = sec->chunks; - origNumChunks += sec->chunks.size(); + size_t OrigNumChunks = 0; + for (OutputSection *Sec : OutputSections) { + Sec->OrigChunks = Sec->Chunks; + OrigNumChunks += Sec->Chunks.size(); } - int pass = 0; - int margin = 1024 * 100; + int Pass = 0; + int Margin = 1024 * 100; while (true) { // First check whether we need thunks at all, or if the previous pass of // adding them turned out ok. - bool rangesOk = true; - size_t numChunks = 0; - for (OutputSection *sec : outputSections) { - if (!verifyRanges(sec->chunks)) { - rangesOk = false; + bool RangesOk = true; + size_t NumChunks = 0; + for (OutputSection *Sec : OutputSections) { + if (!verifyRanges(Sec->Chunks)) { + RangesOk = false; break; } - numChunks += sec->chunks.size(); + NumChunks += Sec->Chunks.size(); } - if (rangesOk) { - if (pass > 0) - log("Added " + Twine(numChunks - origNumChunks) + " thunks with " + - "margin " + Twine(margin) + " in " + Twine(pass) + " passes"); + if (RangesOk) { + if (Pass > 0) + log("Added " + Twine(NumChunks - OrigNumChunks) + " thunks with " + + "margin " + Twine(Margin) + " in " + Twine(Pass) + " passes"); return; } - if (pass >= 10) - fatal("adding thunks hasn't converged after " + Twine(pass) + " passes"); + if (Pass >= 10) + fatal("adding thunks hasn't converged after " + Twine(Pass) + " passes"); - if (pass > 0) { + if (Pass > 0) { // If the previous pass didn't work out, reset everything back to the // original conditions before retrying with a wider margin. This should // ideally never happen under real circumstances. - for (OutputSection *sec : outputSections) - sec->chunks = sec->origChunks; - margin *= 2; + for (OutputSection *Sec : OutputSections) + Sec->Chunks = Sec->OrigChunks; + Margin *= 2; } // Try adding thunks everywhere where it is needed, with a margin // to avoid things going out of range due to the added thunks. - bool addressesChanged = false; - for (OutputSection *sec : outputSections) - addressesChanged |= createThunks(sec, margin); + bool AddressesChanged = false; + for (OutputSection *Sec : OutputSections) + AddressesChanged |= createThunks(Sec, Margin); // If the verification above thought we needed thunks, we should have // added some. - assert(addressesChanged); + assert(AddressesChanged); // Recalculate the layout for the whole image (and verify the ranges at // the start of the next round). assignAddresses(); - pass++; + Pass++; } } // The main function of the writer. void Writer::run() { - ScopedTimer t1(codeLayoutTimer); + ScopedTimer T1(CodeLayoutTimer); createImportTables(); createSections(); @@ -605,12 +602,12 @@ void Writer::run() { setSectionPermissions(); createSymbolAndStringTable(); - if (fileSize > UINT32_MAX) - fatal("image size (" + Twine(fileSize) + ") " + + if (FileSize > UINT32_MAX) + fatal("image size (" + Twine(FileSize) + ") " + "exceeds maximum allowable size (" + Twine(UINT32_MAX) + ")"); - openFile(config->outputFile); - if (config->is64()) { + openFile(Config->OutputFile); + if (Config->is64()) { writeHeader(); } else { writeHeader(); @@ -618,64 +615,43 @@ void Writer::run() { writeSections(); sortExceptionTable(); - t1.stop(); + T1.stop(); - if (!config->pdbPath.empty() && config->debug) { - assert(buildId); - createPDB(symtab, outputSections, sectionTable, buildId->buildId); + if (!Config->PDBPath.empty() && Config->Debug) { + assert(BuildId); + createPDB(Symtab, OutputSections, SectionTable, BuildId->BuildId); } writeBuildId(); - writeMapFile(outputSections); + writeMapFile(OutputSections); - if (errorCount()) - return; - - ScopedTimer t2(diskCommitTimer); - if (auto e = buffer->commit()) - fatal("failed to write the output file: " + toString(std::move(e))); + ScopedTimer T2(DiskCommitTimer); + if (auto E = Buffer->commit()) + fatal("failed to write the output file: " + toString(std::move(E))); } -static StringRef getOutputSectionName(StringRef name) { - StringRef s = name.split('$').first; +static StringRef getOutputSectionName(StringRef Name) { + StringRef S = Name.split('$').first; // Treat a later period as a separator for MinGW, for sections like // ".ctors.01234". - return s.substr(0, s.find('.', 1)); + return S.substr(0, S.find('.', 1)); } // For /order. -static void sortBySectionOrder(std::vector &chunks) { - auto getPriority = [](const Chunk *c) { - if (auto *sec = dyn_cast(c)) - if (sec->sym) - return config->order.lookup(sec->sym->getName()); +static void sortBySectionOrder(std::vector &Chunks) { + auto GetPriority = [](const Chunk *C) { + if (auto *Sec = dyn_cast(C)) + if (Sec->Sym) + return Config->Order.lookup(Sec->Sym->getName()); return 0; }; - llvm::stable_sort(chunks, [=](const Chunk *a, const Chunk *b) { - return getPriority(a) < getPriority(b); + llvm::stable_sort(Chunks, [=](const Chunk *A, const Chunk *B) { + return GetPriority(A) < GetPriority(B); }); } -// Change the characteristics of existing PartialSections that belong to the -// section Name to Chars. -void Writer::fixPartialSectionChars(StringRef name, uint32_t chars) { - for (auto it : partialSections) { - PartialSection *pSec = it.second; - StringRef curName = pSec->name; - if (!curName.consume_front(name) || - (!curName.empty() && !curName.startswith("$"))) - continue; - if (pSec->characteristics == chars) - continue; - PartialSection *destSec = createPartialSection(pSec->name, chars); - destSec->chunks.insert(destSec->chunks.end(), pSec->chunks.begin(), - pSec->chunks.end()); - pSec->chunks.clear(); - } -} - // Sort concrete section chunks from GNU import libraries. // // GNU binutils doesn't use short import files, but instead produces import @@ -687,269 +663,258 @@ void Writer::fixPartialSectionChars(StringRef name, uint32_t chars) { // to be grouped by library, and sorted alphabetically within each library // (which makes sure the header comes first and the trailer last). bool Writer::fixGnuImportChunks() { - uint32_t rdata = IMAGE_SCN_CNT_INITIALIZED_DATA | IMAGE_SCN_MEM_READ; + uint32_t RDATA = IMAGE_SCN_CNT_INITIALIZED_DATA | IMAGE_SCN_MEM_READ; // Make sure all .idata$* section chunks are mapped as RDATA in order to // be sorted into the same sections as our own synthesized .idata chunks. - fixPartialSectionChars(".idata", rdata); + for (auto It : PartialSections) { + PartialSection *PSec = It.second; + if (!PSec->Name.startswith(".idata")) + continue; + if (PSec->Characteristics == RDATA) + continue; + PartialSection *RDataSec = createPartialSection(PSec->Name, RDATA); + RDataSec->Chunks.insert(RDataSec->Chunks.end(), PSec->Chunks.begin(), + PSec->Chunks.end()); + PSec->Chunks.clear(); + } - bool hasIdata = false; + bool HasIdata = false; // Sort all .idata$* chunks, grouping chunks from the same library, // with alphabetical ordering of the object fils within a library. - for (auto it : partialSections) { - PartialSection *pSec = it.second; - if (!pSec->name.startswith(".idata")) + for (auto It : PartialSections) { + PartialSection *PSec = It.second; + if (!PSec->Name.startswith(".idata")) continue; - if (!pSec->chunks.empty()) - hasIdata = true; - llvm::stable_sort(pSec->chunks, [&](Chunk *s, Chunk *t) { - SectionChunk *sc1 = dyn_cast_or_null(s); - SectionChunk *sc2 = dyn_cast_or_null(t); - if (!sc1 || !sc2) { + if (!PSec->Chunks.empty()) + HasIdata = true; + llvm::stable_sort(PSec->Chunks, [&](Chunk *S, Chunk *T) { + SectionChunk *SC1 = dyn_cast_or_null(S); + SectionChunk *SC2 = dyn_cast_or_null(T); + if (!SC1 || !SC2) { // if SC1, order them ascending. If SC2 or both null, // S is not less than T. - return sc1 != nullptr; + return SC1 != nullptr; } // Make a string with "libraryname/objectfile" for sorting, achieving // both grouping by library and sorting of objects within a library, // at once. - std::string key1 = - (sc1->file->parentName + "/" + sc1->file->getName()).str(); - std::string key2 = - (sc2->file->parentName + "/" + sc2->file->getName()).str(); - return key1 < key2; + std::string Key1 = + (SC1->File->ParentName + "/" + SC1->File->getName()).str(); + std::string Key2 = + (SC2->File->ParentName + "/" + SC2->File->getName()).str(); + return Key1 < Key2; }); } - return hasIdata; + return HasIdata; } // Add generated idata chunks, for imported symbols and DLLs, and a // terminator in .idata$2. void Writer::addSyntheticIdata() { - uint32_t rdata = IMAGE_SCN_CNT_INITIALIZED_DATA | IMAGE_SCN_MEM_READ; - idata.create(); + uint32_t RDATA = IMAGE_SCN_CNT_INITIALIZED_DATA | IMAGE_SCN_MEM_READ; + Idata.create(); // Add the .idata content in the right section groups, to allow // chunks from other linked in object files to be grouped together. // See Microsoft PE/COFF spec 5.4 for details. - auto add = [&](StringRef n, std::vector &v) { - PartialSection *pSec = createPartialSection(n, rdata); - pSec->chunks.insert(pSec->chunks.end(), v.begin(), v.end()); + auto Add = [&](StringRef N, std::vector &V) { + PartialSection *PSec = createPartialSection(N, RDATA); + PSec->Chunks.insert(PSec->Chunks.end(), V.begin(), V.end()); }; // The loader assumes a specific order of data. // Add each type in the correct order. - add(".idata$2", idata.dirs); - add(".idata$4", idata.lookups); - add(".idata$5", idata.addresses); - add(".idata$6", idata.hints); - add(".idata$7", idata.dllNames); + Add(".idata$2", Idata.Dirs); + Add(".idata$4", Idata.Lookups); + Add(".idata$5", Idata.Addresses); + Add(".idata$6", Idata.Hints); + Add(".idata$7", Idata.DLLNames); } // Locate the first Chunk and size of the import directory list and the // IAT. void Writer::locateImportTables() { - uint32_t rdata = IMAGE_SCN_CNT_INITIALIZED_DATA | IMAGE_SCN_MEM_READ; + uint32_t RDATA = IMAGE_SCN_CNT_INITIALIZED_DATA | IMAGE_SCN_MEM_READ; - if (PartialSection *importDirs = findPartialSection(".idata$2", rdata)) { - if (!importDirs->chunks.empty()) - importTableStart = importDirs->chunks.front(); - for (Chunk *c : importDirs->chunks) - importTableSize += c->getSize(); + if (PartialSection *ImportDirs = findPartialSection(".idata$2", RDATA)) { + if (!ImportDirs->Chunks.empty()) + ImportTableStart = ImportDirs->Chunks.front(); + for (Chunk *C : ImportDirs->Chunks) + ImportTableSize += C->getSize(); } - if (PartialSection *importAddresses = findPartialSection(".idata$5", rdata)) { - if (!importAddresses->chunks.empty()) - iatStart = importAddresses->chunks.front(); - for (Chunk *c : importAddresses->chunks) - iatSize += c->getSize(); + if (PartialSection *ImportAddresses = findPartialSection(".idata$5", RDATA)) { + if (!ImportAddresses->Chunks.empty()) + IATStart = ImportAddresses->Chunks.front(); + for (Chunk *C : ImportAddresses->Chunks) + IATSize += C->getSize(); } } -// Return whether a SectionChunk's suffix (the dollar and any trailing -// suffix) should be removed and sorted into the main suffixless -// PartialSection. -static bool shouldStripSectionSuffix(SectionChunk *sc, StringRef name) { - // On MinGW, comdat groups are formed by putting the comdat group name - // after the '$' in the section name. For .eh_frame$, that must - // still be sorted before the .eh_frame trailer from crtend.o, thus just - // strip the section name trailer. For other sections, such as - // .tls$$ (where non-comdat .tls symbols are otherwise stored in - // ".tls$"), they must be strictly sorted after .tls. And for the - // hypothetical case of comdat .CRT$XCU, we definitely need to keep the - // suffix for sorting. Thus, to play it safe, only strip the suffix for - // the standard sections. - if (!config->mingw) - return false; - if (!sc || !sc->isCOMDAT()) - return false; - return name.startswith(".text$") || name.startswith(".data$") || - name.startswith(".rdata$") || name.startswith(".pdata$") || - name.startswith(".xdata$") || name.startswith(".eh_frame$"); -} - // Create output section objects and add them to OutputSections. void Writer::createSections() { // First, create the builtin sections. - const uint32_t data = IMAGE_SCN_CNT_INITIALIZED_DATA; - const uint32_t bss = IMAGE_SCN_CNT_UNINITIALIZED_DATA; - const uint32_t code = IMAGE_SCN_CNT_CODE; - const uint32_t discardable = IMAGE_SCN_MEM_DISCARDABLE; - const uint32_t r = IMAGE_SCN_MEM_READ; - const uint32_t w = IMAGE_SCN_MEM_WRITE; - const uint32_t x = IMAGE_SCN_MEM_EXECUTE; - - SmallDenseMap, OutputSection *> sections; - auto createSection = [&](StringRef name, uint32_t outChars) { - OutputSection *&sec = sections[{name, outChars}]; - if (!sec) { - sec = make(name, outChars); - outputSections.push_back(sec); + const uint32_t DATA = IMAGE_SCN_CNT_INITIALIZED_DATA; + const uint32_t BSS = IMAGE_SCN_CNT_UNINITIALIZED_DATA; + const uint32_t CODE = IMAGE_SCN_CNT_CODE; + const uint32_t DISCARDABLE = IMAGE_SCN_MEM_DISCARDABLE; + const uint32_t R = IMAGE_SCN_MEM_READ; + const uint32_t W = IMAGE_SCN_MEM_WRITE; + const uint32_t X = IMAGE_SCN_MEM_EXECUTE; + + SmallDenseMap, OutputSection *> Sections; + auto CreateSection = [&](StringRef Name, uint32_t OutChars) { + OutputSection *&Sec = Sections[{Name, OutChars}]; + if (!Sec) { + Sec = make(Name, OutChars); + OutputSections.push_back(Sec); } - return sec; + return Sec; }; // Try to match the section order used by link.exe. - textSec = createSection(".text", code | r | x); - createSection(".bss", bss | r | w); - rdataSec = createSection(".rdata", data | r); - buildidSec = createSection(".buildid", data | r); - dataSec = createSection(".data", data | r | w); - pdataSec = createSection(".pdata", data | r); - idataSec = createSection(".idata", data | r); - edataSec = createSection(".edata", data | r); - didatSec = createSection(".didat", data | r); - rsrcSec = createSection(".rsrc", data | r); - relocSec = createSection(".reloc", data | discardable | r); - ctorsSec = createSection(".ctors", data | r | w); - dtorsSec = createSection(".dtors", data | r | w); + TextSec = CreateSection(".text", CODE | R | X); + CreateSection(".bss", BSS | R | W); + RdataSec = CreateSection(".rdata", DATA | R); + BuildidSec = CreateSection(".buildid", DATA | R); + DataSec = CreateSection(".data", DATA | R | W); + PdataSec = CreateSection(".pdata", DATA | R); + IdataSec = CreateSection(".idata", DATA | R); + EdataSec = CreateSection(".edata", DATA | R); + DidatSec = CreateSection(".didat", DATA | R); + RsrcSec = CreateSection(".rsrc", DATA | R); + RelocSec = CreateSection(".reloc", DATA | DISCARDABLE | R); + CtorsSec = CreateSection(".ctors", DATA | R | W); + DtorsSec = CreateSection(".dtors", DATA | R | W); // Then bin chunks by name and output characteristics. - for (Chunk *c : symtab->getChunks()) { - auto *sc = dyn_cast(c); - if (sc && !sc->live) { - if (config->verbose) - sc->printDiscardedMessage(); + for (Chunk *C : Symtab->getChunks()) { + auto *SC = dyn_cast(C); + if (SC && !SC->Live) { + if (Config->Verbose) + SC->printDiscardedMessage(); continue; } - StringRef name = c->getSectionName(); - if (shouldStripSectionSuffix(sc, name)) - name = name.split('$').first; - PartialSection *pSec = createPartialSection(name, - c->getOutputCharacteristics()); - pSec->chunks.push_back(c); + StringRef Name = C->getSectionName(); + // On MinGW, comdat groups are formed by putting the comdat group name + // after the '$' in the section name. Such a section name suffix shouldn't + // imply separate alphabetical sorting of those section chunks though. + if (Config->MinGW && SC && SC->isCOMDAT()) + Name = Name.split('$').first; + PartialSection *PSec = createPartialSection(Name, + C->getOutputCharacteristics()); + PSec->Chunks.push_back(C); } - fixPartialSectionChars(".rsrc", data | r); - fixPartialSectionChars(".edata", data | r); // Even in non MinGW cases, we might need to link against GNU import // libraries. - bool hasIdata = fixGnuImportChunks(); - if (!idata.empty()) - hasIdata = true; + bool HasIdata = fixGnuImportChunks(); + if (!Idata.empty()) + HasIdata = true; - if (hasIdata) + if (HasIdata) addSyntheticIdata(); // Process an /order option. - if (!config->order.empty()) - for (auto it : partialSections) - sortBySectionOrder(it.second->chunks); + if (!Config->Order.empty()) + for (auto It : PartialSections) + sortBySectionOrder(It.second->Chunks); - if (hasIdata) + if (HasIdata) locateImportTables(); // Then create an OutputSection for each section. // '$' and all following characters in input section names are // discarded when determining output section. So, .text$foo // contributes to .text, for example. See PE/COFF spec 3.2. - for (auto it : partialSections) { - PartialSection *pSec = it.second; - StringRef name = getOutputSectionName(pSec->name); - uint32_t outChars = pSec->characteristics; + for (auto It : PartialSections) { + PartialSection *PSec = It.second; + StringRef Name = getOutputSectionName(PSec->Name); + uint32_t OutChars = PSec->Characteristics; - if (name == ".CRT") { + if (Name == ".CRT") { // In link.exe, there is a special case for the I386 target where .CRT // sections are treated as if they have output characteristics DATA | R if // their characteristics are DATA | R | W. This implements the same // special case for all architectures. - outChars = data | r; + OutChars = DATA | R; - log("Processing section " + pSec->name + " -> " + name); + log("Processing section " + PSec->Name + " -> " + Name); - sortCRTSectionChunks(pSec->chunks); + sortCRTSectionChunks(PSec->Chunks); } - OutputSection *sec = createSection(name, outChars); - for (Chunk *c : pSec->chunks) - sec->addChunk(c); + OutputSection *Sec = CreateSection(Name, OutChars); + for (Chunk *C : PSec->Chunks) + Sec->addChunk(C); - sec->addContributingPartialSection(pSec); + Sec->addContributingPartialSection(PSec); } // Finally, move some output sections to the end. - auto sectionOrder = [&](const OutputSection *s) { + auto SectionOrder = [&](const OutputSection *S) { // Move DISCARDABLE (or non-memory-mapped) sections to the end of file // because the loader cannot handle holes. Stripping can remove other // discardable ones than .reloc, which is first of them (created early). - if (s->header.Characteristics & IMAGE_SCN_MEM_DISCARDABLE) + if (S->Header.Characteristics & IMAGE_SCN_MEM_DISCARDABLE) return 2; // .rsrc should come at the end of the non-discardable sections because its // size may change by the Win32 UpdateResources() function, causing // subsequent sections to move (see https://crbug.com/827082). - if (s == rsrcSec) + if (S == RsrcSec) return 1; return 0; }; - llvm::stable_sort(outputSections, - [&](const OutputSection *s, const OutputSection *t) { - return sectionOrder(s) < sectionOrder(t); + llvm::stable_sort(OutputSections, + [&](const OutputSection *S, const OutputSection *T) { + return SectionOrder(S) < SectionOrder(T); }); } void Writer::createMiscChunks() { - for (MergeChunk *p : MergeChunk::instances) { - if (p) { - p->finalizeContents(); - rdataSec->addChunk(p); + for (MergeChunk *P : MergeChunk::Instances) { + if (P) { + P->finalizeContents(); + RdataSec->addChunk(P); } } // Create thunks for locally-dllimported symbols. - if (!symtab->localImportChunks.empty()) { - for (Chunk *c : symtab->localImportChunks) - rdataSec->addChunk(c); + if (!Symtab->LocalImportChunks.empty()) { + for (Chunk *C : Symtab->LocalImportChunks) + RdataSec->addChunk(C); } // Create Debug Information Chunks - OutputSection *debugInfoSec = config->mingw ? buildidSec : rdataSec; - if (config->debug || config->repro) { - debugDirectory = make(debugRecords, config->repro); - debugInfoSec->addChunk(debugDirectory); + OutputSection *DebugInfoSec = Config->MinGW ? BuildidSec : RdataSec; + if (Config->Debug || Config->Repro) { + DebugDirectory = make(DebugRecords, Config->Repro); + DebugInfoSec->addChunk(DebugDirectory); } - if (config->debug) { + if (Config->Debug) { // Make a CVDebugRecordChunk even when /DEBUG:CV is not specified. We // output a PDB no matter what, and this chunk provides the only means of // allowing a debugger to match a PDB and an executable. So we need it even // if we're ultimately not going to write CodeView data to the PDB. - buildId = make(); - debugRecords.push_back(buildId); + BuildId = make(); + DebugRecords.push_back(BuildId); - for (Chunk *c : debugRecords) - debugInfoSec->addChunk(c); + for (Chunk *C : DebugRecords) + DebugInfoSec->addChunk(C); } // Create SEH table. x86-only. - if (config->safeSEH) + if (Config->Machine == I386) createSEHTable(); // Create /guard:cf tables if requested. - if (config->guardCF != GuardCFLevel::Off) + if (Config->GuardCF != GuardCFLevel::Off) createGuardCFTables(); - if (config->mingw) { + if (Config->MinGW) { createRuntimePseudoRelocs(); insertCtorDtorSymbols(); @@ -964,132 +929,123 @@ void Writer::createImportTables() { // Initialize DLLOrder so that import entries are ordered in // the same order as in the command line. (That affects DLL // initialization order, and this ordering is MSVC-compatible.) - for (ImportFile *file : ImportFile::instances) { - if (!file->live) + for (ImportFile *File : ImportFile::Instances) { + if (!File->Live) continue; - std::string dll = StringRef(file->dllName).lower(); - if (config->dllOrder.count(dll) == 0) - config->dllOrder[dll] = config->dllOrder.size(); - - if (file->impSym && !isa(file->impSym)) - fatal(toString(*file->impSym) + " was replaced"); - DefinedImportData *impSym = cast_or_null(file->impSym); - if (config->delayLoads.count(StringRef(file->dllName).lower())) { - if (!file->thunkSym) - fatal("cannot delay-load " + toString(file) + - " due to import of data: " + toString(*impSym)); - delayIdata.add(impSym); + std::string DLL = StringRef(File->DLLName).lower(); + if (Config->DLLOrder.count(DLL) == 0) + Config->DLLOrder[DLL] = Config->DLLOrder.size(); + + if (File->ImpSym && !isa(File->ImpSym)) + fatal(toString(*File->ImpSym) + " was replaced"); + DefinedImportData *ImpSym = cast_or_null(File->ImpSym); + if (Config->DelayLoads.count(StringRef(File->DLLName).lower())) { + if (!File->ThunkSym) + fatal("cannot delay-load " + toString(File) + + " due to import of data: " + toString(*ImpSym)); + DelayIdata.add(ImpSym); } else { - idata.add(impSym); + Idata.add(ImpSym); } } } void Writer::appendImportThunks() { - if (ImportFile::instances.empty()) + if (ImportFile::Instances.empty()) return; - for (ImportFile *file : ImportFile::instances) { - if (!file->live) + for (ImportFile *File : ImportFile::Instances) { + if (!File->Live) continue; - if (!file->thunkSym) + if (!File->ThunkSym) continue; - if (!isa(file->thunkSym)) - fatal(toString(*file->thunkSym) + " was replaced"); - DefinedImportThunk *thunk = cast(file->thunkSym); - if (file->thunkLive) - textSec->addChunk(thunk->getChunk()); + if (!isa(File->ThunkSym)) + fatal(toString(*File->ThunkSym) + " was replaced"); + DefinedImportThunk *Thunk = cast(File->ThunkSym); + if (File->ThunkLive) + TextSec->addChunk(Thunk->getChunk()); } - if (!delayIdata.empty()) { - Defined *helper = cast(config->delayLoadHelper); - delayIdata.create(helper); - for (Chunk *c : delayIdata.getChunks()) - didatSec->addChunk(c); - for (Chunk *c : delayIdata.getDataChunks()) - dataSec->addChunk(c); - for (Chunk *c : delayIdata.getCodeChunks()) - textSec->addChunk(c); + if (!DelayIdata.empty()) { + Defined *Helper = cast(Config->DelayLoadHelper); + DelayIdata.create(Helper); + for (Chunk *C : DelayIdata.getChunks()) + DidatSec->addChunk(C); + for (Chunk *C : DelayIdata.getDataChunks()) + DataSec->addChunk(C); + for (Chunk *C : DelayIdata.getCodeChunks()) + TextSec->addChunk(C); } } void Writer::createExportTable() { - if (!edataSec->chunks.empty()) { - // Allow using a custom built export table from input object files, instead - // of having the linker synthesize the tables. - if (config->hadExplicitExports) - warn("literal .edata sections override exports"); - } else if (!config->exports.empty()) { - for (Chunk *c : edata.chunks) - edataSec->addChunk(c); - } - if (!edataSec->chunks.empty()) { - edataStart = edataSec->chunks.front(); - edataEnd = edataSec->chunks.back(); - } + if (Config->Exports.empty()) + return; + for (Chunk *C : Edata.Chunks) + EdataSec->addChunk(C); } void Writer::removeUnusedSections() { // Remove sections that we can be sure won't get content, to avoid // allocating space for their section headers. - auto isUnused = [this](OutputSection *s) { - if (s == relocSec) + auto IsUnused = [this](OutputSection *S) { + if (S == RelocSec) return false; // This section is populated later. // MergeChunks have zero size at this point, as their size is finalized // later. Only remove sections that have no Chunks at all. - return s->chunks.empty(); + return S->Chunks.empty(); }; - outputSections.erase( - std::remove_if(outputSections.begin(), outputSections.end(), isUnused), - outputSections.end()); + OutputSections.erase( + std::remove_if(OutputSections.begin(), OutputSections.end(), IsUnused), + OutputSections.end()); } // The Windows loader doesn't seem to like empty sections, // so we remove them if any. void Writer::removeEmptySections() { - auto isEmpty = [](OutputSection *s) { return s->getVirtualSize() == 0; }; - outputSections.erase( - std::remove_if(outputSections.begin(), outputSections.end(), isEmpty), - outputSections.end()); + auto IsEmpty = [](OutputSection *S) { return S->getVirtualSize() == 0; }; + OutputSections.erase( + std::remove_if(OutputSections.begin(), OutputSections.end(), IsEmpty), + OutputSections.end()); } void Writer::assignOutputSectionIndices() { // Assign final output section indices, and assign each chunk to its output // section. - uint32_t idx = 1; - for (OutputSection *os : outputSections) { - os->sectionIndex = idx; - for (Chunk *c : os->chunks) - c->setOutputSectionIdx(idx); - ++idx; + uint32_t Idx = 1; + for (OutputSection *OS : OutputSections) { + OS->SectionIndex = Idx; + for (Chunk *C : OS->Chunks) + C->setOutputSectionIdx(Idx); + ++Idx; } // Merge chunks are containers of chunks, so assign those an output section // too. - for (MergeChunk *mc : MergeChunk::instances) - if (mc) - for (SectionChunk *sc : mc->sections) - if (sc && sc->live) - sc->setOutputSectionIdx(mc->getOutputSectionIdx()); + for (MergeChunk *MC : MergeChunk::Instances) + if (MC) + for (SectionChunk *SC : MC->Sections) + if (SC && SC->Live) + SC->setOutputSectionIdx(MC->getOutputSectionIdx()); } -size_t Writer::addEntryToStringTable(StringRef str) { - assert(str.size() > COFF::NameSize); - size_t offsetOfEntry = strtab.size() + 4; // +4 for the size field - strtab.insert(strtab.end(), str.begin(), str.end()); - strtab.push_back('\0'); - return offsetOfEntry; +size_t Writer::addEntryToStringTable(StringRef Str) { + assert(Str.size() > COFF::NameSize); + size_t OffsetOfEntry = Strtab.size() + 4; // +4 for the size field + Strtab.insert(Strtab.end(), Str.begin(), Str.end()); + Strtab.push_back('\0'); + return OffsetOfEntry; } -Optional Writer::createSymbol(Defined *def) { - coff_symbol16 sym; - switch (def->kind()) { +Optional Writer::createSymbol(Defined *Def) { + coff_symbol16 Sym; + switch (Def->kind()) { case Symbol::DefinedAbsoluteKind: - sym.Value = def->getRVA(); - sym.SectionNumber = IMAGE_SYM_ABSOLUTE; + Sym.Value = Def->getRVA(); + Sym.SectionNumber = IMAGE_SYM_ABSOLUTE; break; case Symbol::DefinedSyntheticKind: // Relative symbols are unrepresentable in a COFF symbol table. @@ -1097,45 +1053,38 @@ Optional Writer::createSymbol(Defined *def) { default: { // Don't write symbols that won't be written to the output to the symbol // table. - Chunk *c = def->getChunk(); - if (!c) + Chunk *C = Def->getChunk(); + if (!C) return None; - OutputSection *os = c->getOutputSection(); - if (!os) + OutputSection *OS = C->getOutputSection(); + if (!OS) return None; - sym.Value = def->getRVA() - os->getRVA(); - sym.SectionNumber = os->sectionIndex; + Sym.Value = Def->getRVA() - OS->getRVA(); + Sym.SectionNumber = OS->SectionIndex; break; } } - // Symbols that are runtime pseudo relocations don't point to the actual - // symbol data itself (as they are imported), but points to the IAT entry - // instead. Avoid emitting them to the symbol table, as they can confuse - // debuggers. - if (def->isRuntimePseudoReloc) - return None; - - StringRef name = def->getName(); - if (name.size() > COFF::NameSize) { - sym.Name.Offset.Zeroes = 0; - sym.Name.Offset.Offset = addEntryToStringTable(name); + StringRef Name = Def->getName(); + if (Name.size() > COFF::NameSize) { + Sym.Name.Offset.Zeroes = 0; + Sym.Name.Offset.Offset = addEntryToStringTable(Name); } else { - memset(sym.Name.ShortName, 0, COFF::NameSize); - memcpy(sym.Name.ShortName, name.data(), name.size()); + memset(Sym.Name.ShortName, 0, COFF::NameSize); + memcpy(Sym.Name.ShortName, Name.data(), Name.size()); } - if (auto *d = dyn_cast(def)) { - COFFSymbolRef ref = d->getCOFFSymbol(); - sym.Type = ref.getType(); - sym.StorageClass = ref.getStorageClass(); + if (auto *D = dyn_cast(Def)) { + COFFSymbolRef Ref = D->getCOFFSymbol(); + Sym.Type = Ref.getType(); + Sym.StorageClass = Ref.getStorageClass(); } else { - sym.Type = IMAGE_SYM_TYPE_NULL; - sym.StorageClass = IMAGE_SYM_CLASS_EXTERNAL; + Sym.Type = IMAGE_SYM_TYPE_NULL; + Sym.StorageClass = IMAGE_SYM_CLASS_EXTERNAL; } - sym.NumberOfAuxSymbols = 0; - return sym; + Sym.NumberOfAuxSymbols = 0; + return Sym; } void Writer::createSymbolAndStringTable() { @@ -1147,122 +1096,120 @@ void Writer::createSymbolAndStringTable() { // solution where discardable sections have long names preserved and // non-discardable sections have their names truncated, to ensure that any // section which is mapped at runtime also has its name mapped at runtime. - for (OutputSection *sec : outputSections) { - if (sec->name.size() <= COFF::NameSize) + for (OutputSection *Sec : OutputSections) { + if (Sec->Name.size() <= COFF::NameSize) continue; - if ((sec->header.Characteristics & IMAGE_SCN_MEM_DISCARDABLE) == 0) + if ((Sec->Header.Characteristics & IMAGE_SCN_MEM_DISCARDABLE) == 0) continue; - sec->setStringTableOff(addEntryToStringTable(sec->name)); + Sec->setStringTableOff(addEntryToStringTable(Sec->Name)); } - if (config->debugDwarf || config->debugSymtab) { - for (ObjFile *file : ObjFile::instances) { - for (Symbol *b : file->getSymbols()) { - auto *d = dyn_cast_or_null(b); - if (!d || d->writtenToSymtab) + if (Config->DebugDwarf || Config->DebugSymtab) { + for (ObjFile *File : ObjFile::Instances) { + for (Symbol *B : File->getSymbols()) { + auto *D = dyn_cast_or_null(B); + if (!D || D->WrittenToSymtab) continue; - d->writtenToSymtab = true; + D->WrittenToSymtab = true; - if (Optional sym = createSymbol(d)) - outputSymtab.push_back(*sym); + if (Optional Sym = createSymbol(D)) + OutputSymtab.push_back(*Sym); } } } - if (outputSymtab.empty() && strtab.empty()) + if (OutputSymtab.empty() && Strtab.empty()) return; // We position the symbol table to be adjacent to the end of the last section. - uint64_t fileOff = fileSize; - pointerToSymbolTable = fileOff; - fileOff += outputSymtab.size() * sizeof(coff_symbol16); - fileOff += 4 + strtab.size(); - fileSize = alignTo(fileOff, config->fileAlign); + uint64_t FileOff = FileSize; + PointerToSymbolTable = FileOff; + FileOff += OutputSymtab.size() * sizeof(coff_symbol16); + FileOff += 4 + Strtab.size(); + FileSize = alignTo(FileOff, Config->FileAlign); } void Writer::mergeSections() { - if (!pdataSec->chunks.empty()) { - firstPdata = pdataSec->chunks.front(); - lastPdata = pdataSec->chunks.back(); + if (!PdataSec->Chunks.empty()) { + FirstPdata = PdataSec->Chunks.front(); + LastPdata = PdataSec->Chunks.back(); } - for (auto &p : config->merge) { - StringRef toName = p.second; - if (p.first == toName) + for (auto &P : Config->Merge) { + StringRef ToName = P.second; + if (P.first == ToName) continue; - StringSet<> names; + StringSet<> Names; while (1) { - if (!names.insert(toName).second) - fatal("/merge: cycle found for section '" + p.first + "'"); - auto i = config->merge.find(toName); - if (i == config->merge.end()) + if (!Names.insert(ToName).second) + fatal("/merge: cycle found for section '" + P.first + "'"); + auto I = Config->Merge.find(ToName); + if (I == Config->Merge.end()) break; - toName = i->second; + ToName = I->second; } - OutputSection *from = findSection(p.first); - OutputSection *to = findSection(toName); - if (!from) + OutputSection *From = findSection(P.first); + OutputSection *To = findSection(ToName); + if (!From) continue; - if (!to) { - from->name = toName; + if (!To) { + From->Name = ToName; continue; } - to->merge(from); + To->merge(From); } } // Visits all sections to assign incremental, non-overlapping RVAs and // file offsets. void Writer::assignAddresses() { - sizeOfHeaders = dosStubSize + sizeof(PEMagic) + sizeof(coff_file_header) + - sizeof(data_directory) * numberOfDataDirectory + - sizeof(coff_section) * outputSections.size(); - sizeOfHeaders += - config->is64() ? sizeof(pe32plus_header) : sizeof(pe32_header); - sizeOfHeaders = alignTo(sizeOfHeaders, config->fileAlign); - fileSize = sizeOfHeaders; - - // The first page is kept unmapped. - uint64_t rva = alignTo(sizeOfHeaders, config->align); - - for (OutputSection *sec : outputSections) { - if (sec == relocSec) + SizeOfHeaders = DOSStubSize + sizeof(PEMagic) + sizeof(coff_file_header) + + sizeof(data_directory) * NumberOfDataDirectory + + sizeof(coff_section) * OutputSections.size(); + SizeOfHeaders += + Config->is64() ? sizeof(pe32plus_header) : sizeof(pe32_header); + SizeOfHeaders = alignTo(SizeOfHeaders, Config->FileAlign); + uint64_t RVA = PageSize; // The first page is kept unmapped. + FileSize = SizeOfHeaders; + + for (OutputSection *Sec : OutputSections) { + if (Sec == RelocSec) addBaserels(); - uint64_t rawSize = 0, virtualSize = 0; - sec->header.VirtualAddress = rva; + uint64_t RawSize = 0, VirtualSize = 0; + Sec->Header.VirtualAddress = RVA; // If /FUNCTIONPADMIN is used, functions are padded in order to create a // hotpatchable image. - const bool isCodeSection = - (sec->header.Characteristics & IMAGE_SCN_CNT_CODE) && - (sec->header.Characteristics & IMAGE_SCN_MEM_READ) && - (sec->header.Characteristics & IMAGE_SCN_MEM_EXECUTE); - uint32_t padding = isCodeSection ? config->functionPadMin : 0; - - for (Chunk *c : sec->chunks) { - if (padding && c->isHotPatchable()) - virtualSize += padding; - virtualSize = alignTo(virtualSize, c->getAlignment()); - c->setRVA(rva + virtualSize); - virtualSize += c->getSize(); - if (c->hasData) - rawSize = alignTo(virtualSize, config->fileAlign); + const bool IsCodeSection = + (Sec->Header.Characteristics & IMAGE_SCN_CNT_CODE) && + (Sec->Header.Characteristics & IMAGE_SCN_MEM_READ) && + (Sec->Header.Characteristics & IMAGE_SCN_MEM_EXECUTE); + uint32_t Padding = IsCodeSection ? Config->FunctionPadMin : 0; + + for (Chunk *C : Sec->Chunks) { + if (Padding && C->isHotPatchable()) + VirtualSize += Padding; + VirtualSize = alignTo(VirtualSize, C->getAlignment()); + C->setRVA(RVA + VirtualSize); + VirtualSize += C->getSize(); + if (C->hasData()) + RawSize = alignTo(VirtualSize, Config->FileAlign); } - if (virtualSize > UINT32_MAX) - error("section larger than 4 GiB: " + sec->name); - sec->header.VirtualSize = virtualSize; - sec->header.SizeOfRawData = rawSize; - if (rawSize != 0) - sec->header.PointerToRawData = fileSize; - rva += alignTo(virtualSize, config->align); - fileSize += alignTo(rawSize, config->fileAlign); + if (VirtualSize > UINT32_MAX) + error("section larger than 4 GiB: " + Sec->Name); + Sec->Header.VirtualSize = VirtualSize; + Sec->Header.SizeOfRawData = RawSize; + if (RawSize != 0) + Sec->Header.PointerToRawData = FileSize; + RVA += alignTo(VirtualSize, PageSize); + FileSize += alignTo(RawSize, Config->FileAlign); } - sizeOfImage = alignTo(rva, config->align); + SizeOfImage = alignTo(RVA, PageSize); // Assign addresses to sections in MergeChunks. - for (MergeChunk *mc : MergeChunk::instances) - if (mc) - mc->assignSubsectionRVAs(); + for (MergeChunk *MC : MergeChunk::Instances) + if (MC) + MC->assignSubsectionRVAs(); } template void Writer::writeHeader() { @@ -1271,242 +1218,249 @@ template void Writer::writeHeader() { // under DOS, that program gets run (usually to just print an error message). // When run under Windows, the loader looks at AddressOfNewExeHeader and uses // the PE header instead. - uint8_t *buf = buffer->getBufferStart(); - auto *dos = reinterpret_cast(buf); - buf += sizeof(dos_header); - dos->Magic[0] = 'M'; - dos->Magic[1] = 'Z'; - dos->UsedBytesInTheLastPage = dosStubSize % 512; - dos->FileSizeInPages = divideCeil(dosStubSize, 512); - dos->HeaderSizeInParagraphs = sizeof(dos_header) / 16; - - dos->AddressOfRelocationTable = sizeof(dos_header); - dos->AddressOfNewExeHeader = dosStubSize; + uint8_t *Buf = Buffer->getBufferStart(); + auto *DOS = reinterpret_cast(Buf); + Buf += sizeof(dos_header); + DOS->Magic[0] = 'M'; + DOS->Magic[1] = 'Z'; + DOS->UsedBytesInTheLastPage = DOSStubSize % 512; + DOS->FileSizeInPages = divideCeil(DOSStubSize, 512); + DOS->HeaderSizeInParagraphs = sizeof(dos_header) / 16; + + DOS->AddressOfRelocationTable = sizeof(dos_header); + DOS->AddressOfNewExeHeader = DOSStubSize; // Write DOS program. - memcpy(buf, dosProgram, sizeof(dosProgram)); - buf += sizeof(dosProgram); + memcpy(Buf, DOSProgram, sizeof(DOSProgram)); + Buf += sizeof(DOSProgram); // Write PE magic - memcpy(buf, PEMagic, sizeof(PEMagic)); - buf += sizeof(PEMagic); + memcpy(Buf, PEMagic, sizeof(PEMagic)); + Buf += sizeof(PEMagic); // Write COFF header - auto *coff = reinterpret_cast(buf); - buf += sizeof(*coff); - coff->Machine = config->machine; - coff->NumberOfSections = outputSections.size(); - coff->Characteristics = IMAGE_FILE_EXECUTABLE_IMAGE; - if (config->largeAddressAware) - coff->Characteristics |= IMAGE_FILE_LARGE_ADDRESS_AWARE; - if (!config->is64()) - coff->Characteristics |= IMAGE_FILE_32BIT_MACHINE; - if (config->dll) - coff->Characteristics |= IMAGE_FILE_DLL; - if (!config->relocatable) - coff->Characteristics |= IMAGE_FILE_RELOCS_STRIPPED; - if (config->swaprunCD) - coff->Characteristics |= IMAGE_FILE_REMOVABLE_RUN_FROM_SWAP; - if (config->swaprunNet) - coff->Characteristics |= IMAGE_FILE_NET_RUN_FROM_SWAP; - coff->SizeOfOptionalHeader = - sizeof(PEHeaderTy) + sizeof(data_directory) * numberOfDataDirectory; + auto *COFF = reinterpret_cast(Buf); + Buf += sizeof(*COFF); + COFF->Machine = Config->Machine; + COFF->NumberOfSections = OutputSections.size(); + COFF->Characteristics = IMAGE_FILE_EXECUTABLE_IMAGE; + if (Config->LargeAddressAware) + COFF->Characteristics |= IMAGE_FILE_LARGE_ADDRESS_AWARE; + if (!Config->is64()) + COFF->Characteristics |= IMAGE_FILE_32BIT_MACHINE; + if (Config->DLL) + COFF->Characteristics |= IMAGE_FILE_DLL; + if (!Config->Relocatable) + COFF->Characteristics |= IMAGE_FILE_RELOCS_STRIPPED; + if (Config->SwaprunCD) + COFF->Characteristics |= IMAGE_FILE_REMOVABLE_RUN_FROM_SWAP; + if (Config->SwaprunNet) + COFF->Characteristics |= IMAGE_FILE_NET_RUN_FROM_SWAP; + COFF->SizeOfOptionalHeader = + sizeof(PEHeaderTy) + sizeof(data_directory) * NumberOfDataDirectory; // Write PE header - auto *pe = reinterpret_cast(buf); - buf += sizeof(*pe); - pe->Magic = config->is64() ? PE32Header::PE32_PLUS : PE32Header::PE32; + auto *PE = reinterpret_cast(Buf); + Buf += sizeof(*PE); + PE->Magic = Config->is64() ? PE32Header::PE32_PLUS : PE32Header::PE32; // If {Major,Minor}LinkerVersion is left at 0.0, then for some // reason signing the resulting PE file with Authenticode produces a // signature that fails to validate on Windows 7 (but is OK on 10). // Set it to 14.0, which is what VS2015 outputs, and which avoids // that problem. - pe->MajorLinkerVersion = 14; - pe->MinorLinkerVersion = 0; - - pe->ImageBase = config->imageBase; - pe->SectionAlignment = config->align; - pe->FileAlignment = config->fileAlign; - pe->MajorImageVersion = config->majorImageVersion; - pe->MinorImageVersion = config->minorImageVersion; - pe->MajorOperatingSystemVersion = config->majorOSVersion; - pe->MinorOperatingSystemVersion = config->minorOSVersion; - pe->MajorSubsystemVersion = config->majorOSVersion; - pe->MinorSubsystemVersion = config->minorOSVersion; - pe->Subsystem = config->subsystem; - pe->SizeOfImage = sizeOfImage; - pe->SizeOfHeaders = sizeOfHeaders; - if (!config->noEntry) { - Defined *entry = cast(config->entry); - pe->AddressOfEntryPoint = entry->getRVA(); + PE->MajorLinkerVersion = 14; + PE->MinorLinkerVersion = 0; + + PE->ImageBase = Config->ImageBase; + PE->SectionAlignment = PageSize; + PE->FileAlignment = Config->FileAlign; + PE->MajorImageVersion = Config->MajorImageVersion; + PE->MinorImageVersion = Config->MinorImageVersion; + PE->MajorOperatingSystemVersion = Config->MajorOSVersion; + PE->MinorOperatingSystemVersion = Config->MinorOSVersion; + PE->MajorSubsystemVersion = Config->MajorOSVersion; + PE->MinorSubsystemVersion = Config->MinorOSVersion; + PE->Subsystem = Config->Subsystem; + PE->SizeOfImage = SizeOfImage; + PE->SizeOfHeaders = SizeOfHeaders; + if (!Config->NoEntry) { + Defined *Entry = cast(Config->Entry); + PE->AddressOfEntryPoint = Entry->getRVA(); // Pointer to thumb code must have the LSB set, so adjust it. - if (config->machine == ARMNT) - pe->AddressOfEntryPoint |= 1; - } - pe->SizeOfStackReserve = config->stackReserve; - pe->SizeOfStackCommit = config->stackCommit; - pe->SizeOfHeapReserve = config->heapReserve; - pe->SizeOfHeapCommit = config->heapCommit; - if (config->appContainer) - pe->DLLCharacteristics |= IMAGE_DLL_CHARACTERISTICS_APPCONTAINER; - if (config->dynamicBase) - pe->DLLCharacteristics |= IMAGE_DLL_CHARACTERISTICS_DYNAMIC_BASE; - if (config->highEntropyVA) - pe->DLLCharacteristics |= IMAGE_DLL_CHARACTERISTICS_HIGH_ENTROPY_VA; - if (!config->allowBind) - pe->DLLCharacteristics |= IMAGE_DLL_CHARACTERISTICS_NO_BIND; - if (config->nxCompat) - pe->DLLCharacteristics |= IMAGE_DLL_CHARACTERISTICS_NX_COMPAT; - if (!config->allowIsolation) - pe->DLLCharacteristics |= IMAGE_DLL_CHARACTERISTICS_NO_ISOLATION; - if (config->guardCF != GuardCFLevel::Off) - pe->DLLCharacteristics |= IMAGE_DLL_CHARACTERISTICS_GUARD_CF; - if (config->integrityCheck) - pe->DLLCharacteristics |= IMAGE_DLL_CHARACTERISTICS_FORCE_INTEGRITY; - if (setNoSEHCharacteristic) - pe->DLLCharacteristics |= IMAGE_DLL_CHARACTERISTICS_NO_SEH; - if (config->terminalServerAware) - pe->DLLCharacteristics |= IMAGE_DLL_CHARACTERISTICS_TERMINAL_SERVER_AWARE; - pe->NumberOfRvaAndSize = numberOfDataDirectory; - if (textSec->getVirtualSize()) { - pe->BaseOfCode = textSec->getRVA(); - pe->SizeOfCode = textSec->getRawSize(); - } - pe->SizeOfInitializedData = getSizeOfInitializedData(); + if (Config->Machine == ARMNT) + PE->AddressOfEntryPoint |= 1; + } + PE->SizeOfStackReserve = Config->StackReserve; + PE->SizeOfStackCommit = Config->StackCommit; + PE->SizeOfHeapReserve = Config->HeapReserve; + PE->SizeOfHeapCommit = Config->HeapCommit; + if (Config->AppContainer) + PE->DLLCharacteristics |= IMAGE_DLL_CHARACTERISTICS_APPCONTAINER; + if (Config->DynamicBase) + PE->DLLCharacteristics |= IMAGE_DLL_CHARACTERISTICS_DYNAMIC_BASE; + if (Config->HighEntropyVA) + PE->DLLCharacteristics |= IMAGE_DLL_CHARACTERISTICS_HIGH_ENTROPY_VA; + if (!Config->AllowBind) + PE->DLLCharacteristics |= IMAGE_DLL_CHARACTERISTICS_NO_BIND; + if (Config->NxCompat) + PE->DLLCharacteristics |= IMAGE_DLL_CHARACTERISTICS_NX_COMPAT; + if (!Config->AllowIsolation) + PE->DLLCharacteristics |= IMAGE_DLL_CHARACTERISTICS_NO_ISOLATION; + if (Config->GuardCF != GuardCFLevel::Off) + PE->DLLCharacteristics |= IMAGE_DLL_CHARACTERISTICS_GUARD_CF; + if (Config->IntegrityCheck) + PE->DLLCharacteristics |= IMAGE_DLL_CHARACTERISTICS_FORCE_INTEGRITY; + if (SetNoSEHCharacteristic) + PE->DLLCharacteristics |= IMAGE_DLL_CHARACTERISTICS_NO_SEH; + if (Config->TerminalServerAware) + PE->DLLCharacteristics |= IMAGE_DLL_CHARACTERISTICS_TERMINAL_SERVER_AWARE; + PE->NumberOfRvaAndSize = NumberOfDataDirectory; + if (TextSec->getVirtualSize()) { + PE->BaseOfCode = TextSec->getRVA(); + PE->SizeOfCode = TextSec->getRawSize(); + } + PE->SizeOfInitializedData = getSizeOfInitializedData(); // Write data directory - auto *dir = reinterpret_cast(buf); - buf += sizeof(*dir) * numberOfDataDirectory; - if (edataStart) { - dir[EXPORT_TABLE].RelativeVirtualAddress = edataStart->getRVA(); - dir[EXPORT_TABLE].Size = - edataEnd->getRVA() + edataEnd->getSize() - edataStart->getRVA(); - } - if (importTableStart) { - dir[IMPORT_TABLE].RelativeVirtualAddress = importTableStart->getRVA(); - dir[IMPORT_TABLE].Size = importTableSize; - } - if (iatStart) { - dir[IAT].RelativeVirtualAddress = iatStart->getRVA(); - dir[IAT].Size = iatSize; - } - if (rsrcSec->getVirtualSize()) { - dir[RESOURCE_TABLE].RelativeVirtualAddress = rsrcSec->getRVA(); - dir[RESOURCE_TABLE].Size = rsrcSec->getVirtualSize(); - } - if (firstPdata) { - dir[EXCEPTION_TABLE].RelativeVirtualAddress = firstPdata->getRVA(); - dir[EXCEPTION_TABLE].Size = - lastPdata->getRVA() + lastPdata->getSize() - firstPdata->getRVA(); - } - if (relocSec->getVirtualSize()) { - dir[BASE_RELOCATION_TABLE].RelativeVirtualAddress = relocSec->getRVA(); - dir[BASE_RELOCATION_TABLE].Size = relocSec->getVirtualSize(); - } - if (Symbol *sym = symtab->findUnderscore("_tls_used")) { - if (Defined *b = dyn_cast(sym)) { - dir[TLS_TABLE].RelativeVirtualAddress = b->getRVA(); - dir[TLS_TABLE].Size = config->is64() + auto *Dir = reinterpret_cast(Buf); + Buf += sizeof(*Dir) * NumberOfDataDirectory; + if (!Config->Exports.empty()) { + Dir[EXPORT_TABLE].RelativeVirtualAddress = Edata.getRVA(); + Dir[EXPORT_TABLE].Size = Edata.getSize(); + } + if (ImportTableStart) { + Dir[IMPORT_TABLE].RelativeVirtualAddress = ImportTableStart->getRVA(); + Dir[IMPORT_TABLE].Size = ImportTableSize; + } + if (IATStart) { + Dir[IAT].RelativeVirtualAddress = IATStart->getRVA(); + Dir[IAT].Size = IATSize; + } + if (RsrcSec->getVirtualSize()) { + Dir[RESOURCE_TABLE].RelativeVirtualAddress = RsrcSec->getRVA(); + Dir[RESOURCE_TABLE].Size = RsrcSec->getVirtualSize(); + } + if (FirstPdata) { + Dir[EXCEPTION_TABLE].RelativeVirtualAddress = FirstPdata->getRVA(); + Dir[EXCEPTION_TABLE].Size = + LastPdata->getRVA() + LastPdata->getSize() - FirstPdata->getRVA(); + } + if (RelocSec->getVirtualSize()) { + Dir[BASE_RELOCATION_TABLE].RelativeVirtualAddress = RelocSec->getRVA(); + Dir[BASE_RELOCATION_TABLE].Size = RelocSec->getVirtualSize(); + } + if (Symbol *Sym = Symtab->findUnderscore("_tls_used")) { + if (Defined *B = dyn_cast(Sym)) { + Dir[TLS_TABLE].RelativeVirtualAddress = B->getRVA(); + Dir[TLS_TABLE].Size = Config->is64() ? sizeof(object::coff_tls_directory64) : sizeof(object::coff_tls_directory32); } } - if (debugDirectory) { - dir[DEBUG_DIRECTORY].RelativeVirtualAddress = debugDirectory->getRVA(); - dir[DEBUG_DIRECTORY].Size = debugDirectory->getSize(); + if (DebugDirectory) { + Dir[DEBUG_DIRECTORY].RelativeVirtualAddress = DebugDirectory->getRVA(); + Dir[DEBUG_DIRECTORY].Size = DebugDirectory->getSize(); } - if (Symbol *sym = symtab->findUnderscore("_load_config_used")) { - if (auto *b = dyn_cast(sym)) { - SectionChunk *sc = b->getChunk(); - assert(b->getRVA() >= sc->getRVA()); - uint64_t offsetInChunk = b->getRVA() - sc->getRVA(); - if (!sc->hasData || offsetInChunk + 4 > sc->getSize()) + if (Symbol *Sym = Symtab->findUnderscore("_load_config_used")) { + if (auto *B = dyn_cast(Sym)) { + SectionChunk *SC = B->getChunk(); + assert(B->getRVA() >= SC->getRVA()); + uint64_t OffsetInChunk = B->getRVA() - SC->getRVA(); + if (!SC->hasData() || OffsetInChunk + 4 > SC->getSize()) fatal("_load_config_used is malformed"); - ArrayRef secContents = sc->getContents(); - uint32_t loadConfigSize = - *reinterpret_cast(&secContents[offsetInChunk]); - if (offsetInChunk + loadConfigSize > sc->getSize()) + ArrayRef SecContents = SC->getContents(); + uint32_t LoadConfigSize = + *reinterpret_cast(&SecContents[OffsetInChunk]); + if (OffsetInChunk + LoadConfigSize > SC->getSize()) fatal("_load_config_used is too large"); - dir[LOAD_CONFIG_TABLE].RelativeVirtualAddress = b->getRVA(); - dir[LOAD_CONFIG_TABLE].Size = loadConfigSize; + Dir[LOAD_CONFIG_TABLE].RelativeVirtualAddress = B->getRVA(); + Dir[LOAD_CONFIG_TABLE].Size = LoadConfigSize; } } - if (!delayIdata.empty()) { - dir[DELAY_IMPORT_DESCRIPTOR].RelativeVirtualAddress = - delayIdata.getDirRVA(); - dir[DELAY_IMPORT_DESCRIPTOR].Size = delayIdata.getDirSize(); + if (!DelayIdata.empty()) { + Dir[DELAY_IMPORT_DESCRIPTOR].RelativeVirtualAddress = + DelayIdata.getDirRVA(); + Dir[DELAY_IMPORT_DESCRIPTOR].Size = DelayIdata.getDirSize(); } // Write section table - for (OutputSection *sec : outputSections) { - sec->writeHeaderTo(buf); - buf += sizeof(coff_section); + for (OutputSection *Sec : OutputSections) { + Sec->writeHeaderTo(Buf); + Buf += sizeof(coff_section); } - sectionTable = ArrayRef( - buf - outputSections.size() * sizeof(coff_section), buf); + SectionTable = ArrayRef( + Buf - OutputSections.size() * sizeof(coff_section), Buf); - if (outputSymtab.empty() && strtab.empty()) + if (OutputSymtab.empty() && Strtab.empty()) return; - coff->PointerToSymbolTable = pointerToSymbolTable; - uint32_t numberOfSymbols = outputSymtab.size(); - coff->NumberOfSymbols = numberOfSymbols; - auto *symbolTable = reinterpret_cast( - buffer->getBufferStart() + coff->PointerToSymbolTable); - for (size_t i = 0; i != numberOfSymbols; ++i) - symbolTable[i] = outputSymtab[i]; + COFF->PointerToSymbolTable = PointerToSymbolTable; + uint32_t NumberOfSymbols = OutputSymtab.size(); + COFF->NumberOfSymbols = NumberOfSymbols; + auto *SymbolTable = reinterpret_cast( + Buffer->getBufferStart() + COFF->PointerToSymbolTable); + for (size_t I = 0; I != NumberOfSymbols; ++I) + SymbolTable[I] = OutputSymtab[I]; // Create the string table, it follows immediately after the symbol table. // The first 4 bytes is length including itself. - buf = reinterpret_cast(&symbolTable[numberOfSymbols]); - write32le(buf, strtab.size() + 4); - if (!strtab.empty()) - memcpy(buf + 4, strtab.data(), strtab.size()); + Buf = reinterpret_cast(&SymbolTable[NumberOfSymbols]); + write32le(Buf, Strtab.size() + 4); + if (!Strtab.empty()) + memcpy(Buf + 4, Strtab.data(), Strtab.size()); } -void Writer::openFile(StringRef path) { - buffer = CHECK( - FileOutputBuffer::create(path, fileSize, FileOutputBuffer::F_executable), - "failed to open " + path); +void Writer::openFile(StringRef Path) { + Buffer = CHECK( + FileOutputBuffer::create(Path, FileSize, FileOutputBuffer::F_executable), + "failed to open " + Path); } void Writer::createSEHTable() { - SymbolRVASet handlers; - for (ObjFile *file : ObjFile::instances) { - if (!file->hasSafeSEH()) - error("/safeseh: " + file->getName() + " is not compatible with SEH"); - markSymbolsForRVATable(file, file->getSXDataChunks(), handlers); + // Set the no SEH characteristic on x86 binaries unless we find exception + // handlers. + SetNoSEHCharacteristic = true; + + SymbolRVASet Handlers; + for (ObjFile *File : ObjFile::Instances) { + // FIXME: We should error here instead of earlier unless /safeseh:no was + // passed. + if (!File->hasSafeSEH()) + return; + + markSymbolsForRVATable(File, File->getSXDataChunks(), Handlers); } - // Set the "no SEH" characteristic if there really were no handlers, or if - // there is no load config object to point to the table of handlers. - setNoSEHCharacteristic = - handlers.empty() || !symtab->findUnderscore("_load_config_used"); + // Remove the "no SEH" characteristic if all object files were built with + // safeseh, we found some exception handlers, and there is a load config in + // the object. + SetNoSEHCharacteristic = + Handlers.empty() || !Symtab->findUnderscore("_load_config_used"); - maybeAddRVATable(std::move(handlers), "__safe_se_handler_table", + maybeAddRVATable(std::move(Handlers), "__safe_se_handler_table", "__safe_se_handler_count"); } // Add a symbol to an RVA set. Two symbols may have the same RVA, but an RVA set // cannot contain duplicates. Therefore, the set is uniqued by Chunk and the // symbol's offset into that Chunk. -static void addSymbolToRVASet(SymbolRVASet &rvaSet, Defined *s) { - Chunk *c = s->getChunk(); - if (auto *sc = dyn_cast(c)) - c = sc->repl; // Look through ICF replacement. - uint32_t off = s->getRVA() - (c ? c->getRVA() : 0); - rvaSet.insert({c, off}); +static void addSymbolToRVASet(SymbolRVASet &RVASet, Defined *S) { + Chunk *C = S->getChunk(); + if (auto *SC = dyn_cast(C)) + C = SC->Repl; // Look through ICF replacement. + uint32_t Off = S->getRVA() - (C ? C->getRVA() : 0); + RVASet.insert({C, Off}); } // Given a symbol, add it to the GFIDs table if it is a live, defined, function // symbol in an executable section. -static void maybeAddAddressTakenFunction(SymbolRVASet &addressTakenSyms, - Symbol *s) { - if (!s) +static void maybeAddAddressTakenFunction(SymbolRVASet &AddressTakenSyms, + Symbol *S) { + if (!S) return; - switch (s->kind()) { + switch (S->kind()) { case Symbol::DefinedLocalImportKind: case Symbol::DefinedImportDataKind: // Defines an __imp_ pointer, so it is data, so it is ignored. @@ -1519,8 +1473,7 @@ static void maybeAddAddressTakenFunction(SymbolRVASet &addressTakenSyms, // Absolute is never code, synthetic generally isn't and usually isn't // determinable. break; - case Symbol::LazyArchiveKind: - case Symbol::LazyObjectKind: + case Symbol::LazyKind: case Symbol::UndefinedKind: // Undefined symbols resolve to zero, so they don't have an RVA. Lazy // symbols shouldn't have relocations. @@ -1528,19 +1481,19 @@ static void maybeAddAddressTakenFunction(SymbolRVASet &addressTakenSyms, case Symbol::DefinedImportThunkKind: // Thunks are always code, include them. - addSymbolToRVASet(addressTakenSyms, cast(s)); + addSymbolToRVASet(AddressTakenSyms, cast(S)); break; case Symbol::DefinedRegularKind: { // This is a regular, defined, symbol from a COFF file. Mark the symbol as // address taken if the symbol type is function and it's in an executable // section. - auto *d = cast(s); - if (d->getCOFFSymbol().getComplexType() == COFF::IMAGE_SYM_DTYPE_FUNCTION) { - SectionChunk *sc = dyn_cast(d->getChunk()); - if (sc && sc->live && - sc->getOutputCharacteristics() & IMAGE_SCN_MEM_EXECUTE) - addSymbolToRVASet(addressTakenSyms, d); + auto *D = cast(S); + if (D->getCOFFSymbol().getComplexType() == COFF::IMAGE_SYM_DTYPE_FUNCTION) { + SectionChunk *SC = dyn_cast(D->getChunk()); + if (SC && SC->Live && + SC->getOutputCharacteristics() & IMAGE_SCN_MEM_EXECUTE) + addSymbolToRVASet(AddressTakenSyms, D); } break; } @@ -1549,23 +1502,23 @@ static void maybeAddAddressTakenFunction(SymbolRVASet &addressTakenSyms, // Visit all relocations from all section contributions of this object file and // mark the relocation target as address-taken. -static void markSymbolsWithRelocations(ObjFile *file, - SymbolRVASet &usedSymbols) { - for (Chunk *c : file->getChunks()) { +static void markSymbolsWithRelocations(ObjFile *File, + SymbolRVASet &UsedSymbols) { + for (Chunk *C : File->getChunks()) { // We only care about live section chunks. Common chunks and other chunks // don't generally contain relocations. - SectionChunk *sc = dyn_cast(c); - if (!sc || !sc->live) + SectionChunk *SC = dyn_cast(C); + if (!SC || !SC->Live) continue; - for (const coff_relocation &reloc : sc->getRelocs()) { - if (config->machine == I386 && reloc.Type == COFF::IMAGE_REL_I386_REL32) + for (const coff_relocation &Reloc : SC->getRelocs()) { + if (Config->Machine == I386 && Reloc.Type == COFF::IMAGE_REL_I386_REL32) // Ignore relative relocations on x86. On x86_64 they can't be ignored // since they're also used to compute absolute addresses. continue; - Symbol *ref = sc->file->getSymbol(reloc.SymbolTableIndex); - maybeAddAddressTakenFunction(usedSymbols, ref); + Symbol *Ref = SC->File->getSymbol(Reloc.SymbolTableIndex); + maybeAddAddressTakenFunction(UsedSymbols, Ref); } } } @@ -1574,109 +1527,109 @@ static void markSymbolsWithRelocations(ObjFile *file, // address-taken functions. It is sorted and uniqued, just like the safe SEH // table. void Writer::createGuardCFTables() { - SymbolRVASet addressTakenSyms; - SymbolRVASet longJmpTargets; - for (ObjFile *file : ObjFile::instances) { + SymbolRVASet AddressTakenSyms; + SymbolRVASet LongJmpTargets; + for (ObjFile *File : ObjFile::Instances) { // If the object was compiled with /guard:cf, the address taken symbols // are in .gfids$y sections, and the longjmp targets are in .gljmp$y // sections. If the object was not compiled with /guard:cf, we assume there // were no setjmp targets, and that all code symbols with relocations are // possibly address-taken. - if (file->hasGuardCF()) { - markSymbolsForRVATable(file, file->getGuardFidChunks(), addressTakenSyms); - markSymbolsForRVATable(file, file->getGuardLJmpChunks(), longJmpTargets); + if (File->hasGuardCF()) { + markSymbolsForRVATable(File, File->getGuardFidChunks(), AddressTakenSyms); + markSymbolsForRVATable(File, File->getGuardLJmpChunks(), LongJmpTargets); } else { - markSymbolsWithRelocations(file, addressTakenSyms); + markSymbolsWithRelocations(File, AddressTakenSyms); } } // Mark the image entry as address-taken. - if (config->entry) - maybeAddAddressTakenFunction(addressTakenSyms, config->entry); + if (Config->Entry) + maybeAddAddressTakenFunction(AddressTakenSyms, Config->Entry); // Mark exported symbols in executable sections as address-taken. - for (Export &e : config->exports) - maybeAddAddressTakenFunction(addressTakenSyms, e.sym); + for (Export &E : Config->Exports) + maybeAddAddressTakenFunction(AddressTakenSyms, E.Sym); // Ensure sections referenced in the gfid table are 16-byte aligned. - for (const ChunkAndOffset &c : addressTakenSyms) - if (c.inputChunk->getAlignment() < 16) - c.inputChunk->setAlignment(16); + for (const ChunkAndOffset &C : AddressTakenSyms) + if (C.InputChunk->getAlignment() < 16) + C.InputChunk->setAlignment(16); - maybeAddRVATable(std::move(addressTakenSyms), "__guard_fids_table", + maybeAddRVATable(std::move(AddressTakenSyms), "__guard_fids_table", "__guard_fids_count"); // Add the longjmp target table unless the user told us not to. - if (config->guardCF == GuardCFLevel::Full) - maybeAddRVATable(std::move(longJmpTargets), "__guard_longjmp_table", + if (Config->GuardCF == GuardCFLevel::Full) + maybeAddRVATable(std::move(LongJmpTargets), "__guard_longjmp_table", "__guard_longjmp_count"); // Set __guard_flags, which will be used in the load config to indicate that // /guard:cf was enabled. - uint32_t guardFlags = uint32_t(coff_guard_flags::CFInstrumented) | + uint32_t GuardFlags = uint32_t(coff_guard_flags::CFInstrumented) | uint32_t(coff_guard_flags::HasFidTable); - if (config->guardCF == GuardCFLevel::Full) - guardFlags |= uint32_t(coff_guard_flags::HasLongJmpTable); - Symbol *flagSym = symtab->findUnderscore("__guard_flags"); - cast(flagSym)->setVA(guardFlags); + if (Config->GuardCF == GuardCFLevel::Full) + GuardFlags |= uint32_t(coff_guard_flags::HasLongJmpTable); + Symbol *FlagSym = Symtab->findUnderscore("__guard_flags"); + cast(FlagSym)->setVA(GuardFlags); } // Take a list of input sections containing symbol table indices and add those // symbols to an RVA table. The challenge is that symbol RVAs are not known and // depend on the table size, so we can't directly build a set of integers. -void Writer::markSymbolsForRVATable(ObjFile *file, - ArrayRef symIdxChunks, - SymbolRVASet &tableSymbols) { - for (SectionChunk *c : symIdxChunks) { +void Writer::markSymbolsForRVATable(ObjFile *File, + ArrayRef SymIdxChunks, + SymbolRVASet &TableSymbols) { + for (SectionChunk *C : SymIdxChunks) { // Skip sections discarded by linker GC. This comes up when a .gfids section // is associated with something like a vtable and the vtable is discarded. // In this case, the associated gfids section is discarded, and we don't // mark the virtual member functions as address-taken by the vtable. - if (!c->live) + if (!C->Live) continue; // Validate that the contents look like symbol table indices. - ArrayRef data = c->getContents(); - if (data.size() % 4 != 0) { - warn("ignoring " + c->getSectionName() + - " symbol table index section in object " + toString(file)); + ArrayRef Data = C->getContents(); + if (Data.size() % 4 != 0) { + warn("ignoring " + C->getSectionName() + + " symbol table index section in object " + toString(File)); continue; } // Read each symbol table index and check if that symbol was included in the // final link. If so, add it to the table symbol set. - ArrayRef symIndices( - reinterpret_cast(data.data()), data.size() / 4); - ArrayRef objSymbols = file->getSymbols(); - for (uint32_t symIndex : symIndices) { - if (symIndex >= objSymbols.size()) { + ArrayRef SymIndices( + reinterpret_cast(Data.data()), Data.size() / 4); + ArrayRef ObjSymbols = File->getSymbols(); + for (uint32_t SymIndex : SymIndices) { + if (SymIndex >= ObjSymbols.size()) { warn("ignoring invalid symbol table index in section " + - c->getSectionName() + " in object " + toString(file)); + C->getSectionName() + " in object " + toString(File)); continue; } - if (Symbol *s = objSymbols[symIndex]) { - if (s->isLive()) - addSymbolToRVASet(tableSymbols, cast(s)); + if (Symbol *S = ObjSymbols[SymIndex]) { + if (S->isLive()) + addSymbolToRVASet(TableSymbols, cast(S)); } } } } // Replace the absolute table symbol with a synthetic symbol pointing to -// tableChunk so that we can emit base relocations for it and resolve section +// TableChunk so that we can emit base relocations for it and resolve section // relative relocations. -void Writer::maybeAddRVATable(SymbolRVASet tableSymbols, StringRef tableSym, - StringRef countSym) { - if (tableSymbols.empty()) +void Writer::maybeAddRVATable(SymbolRVASet TableSymbols, StringRef TableSym, + StringRef CountSym) { + if (TableSymbols.empty()) return; - RVATableChunk *tableChunk = make(std::move(tableSymbols)); - rdataSec->addChunk(tableChunk); + RVATableChunk *TableChunk = make(std::move(TableSymbols)); + RdataSec->addChunk(TableChunk); - Symbol *t = symtab->findUnderscore(tableSym); - Symbol *c = symtab->findUnderscore(countSym); - replaceSymbol(t, t->getName(), tableChunk); - cast(c)->setVA(tableChunk->getSize() / 4); + Symbol *T = Symtab->findUnderscore(TableSym); + Symbol *C = Symtab->findUnderscore(CountSym); + replaceSymbol(T, T->getName(), TableChunk); + cast(C)->setVA(TableChunk->getSize() / 4); } // MinGW specific. Gather all relocations that are imported from a DLL even @@ -1684,26 +1637,26 @@ void Writer::maybeAddRVATable(SymbolRVASet tableSymbols, StringRef tableSym, // uses for fixing them up, and provide the synthetic symbols that the // runtime uses for finding the table. void Writer::createRuntimePseudoRelocs() { - std::vector rels; + std::vector Rels; - for (Chunk *c : symtab->getChunks()) { - auto *sc = dyn_cast(c); - if (!sc || !sc->live) + for (Chunk *C : Symtab->getChunks()) { + auto *SC = dyn_cast(C); + if (!SC || !SC->Live) continue; - sc->getRuntimePseudoRelocs(rels); + SC->getRuntimePseudoRelocs(Rels); } - if (!rels.empty()) - log("Writing " + Twine(rels.size()) + " runtime pseudo relocations"); - PseudoRelocTableChunk *table = make(rels); - rdataSec->addChunk(table); - EmptyChunk *endOfList = make(); - rdataSec->addChunk(endOfList); + if (!Rels.empty()) + log("Writing " + Twine(Rels.size()) + " runtime pseudo relocations"); + PseudoRelocTableChunk *Table = make(Rels); + RdataSec->addChunk(Table); + EmptyChunk *EndOfList = make(); + RdataSec->addChunk(EndOfList); - Symbol *headSym = symtab->findUnderscore("__RUNTIME_PSEUDO_RELOC_LIST__"); - Symbol *endSym = symtab->findUnderscore("__RUNTIME_PSEUDO_RELOC_LIST_END__"); - replaceSymbol(headSym, headSym->getName(), table); - replaceSymbol(endSym, endSym->getName(), endOfList); + Symbol *HeadSym = Symtab->findUnderscore("__RUNTIME_PSEUDO_RELOC_LIST__"); + Symbol *EndSym = Symtab->findUnderscore("__RUNTIME_PSEUDO_RELOC_LIST_END__"); + replaceSymbol(HeadSym, HeadSym->getName(), Table); + replaceSymbol(EndSym, EndSym->getName(), EndOfList); } // MinGW specific. @@ -1712,32 +1665,32 @@ void Writer::createRuntimePseudoRelocs() { // There's a symbol pointing to the start sentinel pointer, __CTOR_LIST__ // and __DTOR_LIST__ respectively. void Writer::insertCtorDtorSymbols() { - AbsolutePointerChunk *ctorListHead = make(-1); - AbsolutePointerChunk *ctorListEnd = make(0); - AbsolutePointerChunk *dtorListHead = make(-1); - AbsolutePointerChunk *dtorListEnd = make(0); - ctorsSec->insertChunkAtStart(ctorListHead); - ctorsSec->addChunk(ctorListEnd); - dtorsSec->insertChunkAtStart(dtorListHead); - dtorsSec->addChunk(dtorListEnd); - - Symbol *ctorListSym = symtab->findUnderscore("__CTOR_LIST__"); - Symbol *dtorListSym = symtab->findUnderscore("__DTOR_LIST__"); - replaceSymbol(ctorListSym, ctorListSym->getName(), - ctorListHead); - replaceSymbol(dtorListSym, dtorListSym->getName(), - dtorListHead); + AbsolutePointerChunk *CtorListHead = make(-1); + AbsolutePointerChunk *CtorListEnd = make(0); + AbsolutePointerChunk *DtorListHead = make(-1); + AbsolutePointerChunk *DtorListEnd = make(0); + CtorsSec->insertChunkAtStart(CtorListHead); + CtorsSec->addChunk(CtorListEnd); + DtorsSec->insertChunkAtStart(DtorListHead); + DtorsSec->addChunk(DtorListEnd); + + Symbol *CtorListSym = Symtab->findUnderscore("__CTOR_LIST__"); + Symbol *DtorListSym = Symtab->findUnderscore("__DTOR_LIST__"); + replaceSymbol(CtorListSym, CtorListSym->getName(), + CtorListHead); + replaceSymbol(DtorListSym, DtorListSym->getName(), + DtorListHead); } // Handles /section options to allow users to overwrite // section attributes. void Writer::setSectionPermissions() { - for (auto &p : config->section) { - StringRef name = p.first; - uint32_t perm = p.second; - for (OutputSection *sec : outputSections) - if (sec->name == name) - sec->setPermissions(perm); + for (auto &P : Config->Section) { + StringRef Name = P.first; + uint32_t Perm = P.second; + for (OutputSection *Sec : OutputSections) + if (Sec->Name == Name) + Sec->setPermissions(Perm); } } @@ -1745,18 +1698,18 @@ void Writer::setSectionPermissions() { void Writer::writeSections() { // Record the number of sections to apply section index relocations // against absolute symbols. See applySecIdx in Chunks.cpp.. - DefinedAbsolute::numOutputSections = outputSections.size(); + DefinedAbsolute::NumOutputSections = OutputSections.size(); - uint8_t *buf = buffer->getBufferStart(); - for (OutputSection *sec : outputSections) { - uint8_t *secBuf = buf + sec->getFileOff(); + uint8_t *Buf = Buffer->getBufferStart(); + for (OutputSection *Sec : OutputSections) { + uint8_t *SecBuf = Buf + Sec->getFileOff(); // Fill gaps between functions in .text with INT3 instructions // instead of leaving as NUL bytes (which can be interpreted as // ADD instructions). - if (sec->header.Characteristics & IMAGE_SCN_CNT_CODE) - memset(secBuf, 0xCC, sec->getRawSize()); - parallelForEach(sec->chunks, [&](Chunk *c) { - c->writeTo(secBuf + c->getRVA() - sec->getRVA()); + if (Sec->Header.Characteristics & IMAGE_SCN_CNT_CODE) + memset(SecBuf, 0xCC, Sec->getRawSize()); + parallelForEach(Sec->Chunks, [&](Chunk *C) { + C->writeTo(SecBuf + C->getRVA() - Sec->getRVA()); }); } } @@ -1768,8 +1721,8 @@ void Writer::writeBuildId() { // 2) In all cases, the PE COFF file header also contains a timestamp. // For reproducibility, instead of a timestamp we want to use a hash of the // PE contents. - if (config->debug) { - assert(buildId && "BuildId is not set!"); + if (Config->Debug) { + assert(BuildId && "BuildId is not set!"); // BuildId->BuildId was filled in when the PDB was written. } @@ -1777,65 +1730,65 @@ void Writer::writeBuildId() { // "timestamp" in the COFF file header, and the ones in the coff debug // directory. Now we can hash the file and write that hash to the various // timestamp fields in the file. - StringRef outputFileData( - reinterpret_cast(buffer->getBufferStart()), - buffer->getBufferSize()); + StringRef OutputFileData( + reinterpret_cast(Buffer->getBufferStart()), + Buffer->getBufferSize()); - uint32_t timestamp = config->timestamp; - uint64_t hash = 0; - bool generateSyntheticBuildId = - config->mingw && config->debug && config->pdbPath.empty(); + uint32_t Timestamp = Config->Timestamp; + uint64_t Hash = 0; + bool GenerateSyntheticBuildId = + Config->MinGW && Config->Debug && Config->PDBPath.empty(); - if (config->repro || generateSyntheticBuildId) - hash = xxHash64(outputFileData); + if (Config->Repro || GenerateSyntheticBuildId) + Hash = xxHash64(OutputFileData); - if (config->repro) - timestamp = static_cast(hash); + if (Config->Repro) + Timestamp = static_cast(Hash); - if (generateSyntheticBuildId) { + if (GenerateSyntheticBuildId) { // For MinGW builds without a PDB file, we still generate a build id // to allow associating a crash dump to the executable. - buildId->buildId->PDB70.CVSignature = OMF::Signature::PDB70; - buildId->buildId->PDB70.Age = 1; - memcpy(buildId->buildId->PDB70.Signature, &hash, 8); + BuildId->BuildId->PDB70.CVSignature = OMF::Signature::PDB70; + BuildId->BuildId->PDB70.Age = 1; + memcpy(BuildId->BuildId->PDB70.Signature, &Hash, 8); // xxhash only gives us 8 bytes, so put some fixed data in the other half. - memcpy(&buildId->buildId->PDB70.Signature[8], "LLD PDB.", 8); + memcpy(&BuildId->BuildId->PDB70.Signature[8], "LLD PDB.", 8); } - if (debugDirectory) - debugDirectory->setTimeDateStamp(timestamp); + if (DebugDirectory) + DebugDirectory->setTimeDateStamp(Timestamp); - uint8_t *buf = buffer->getBufferStart(); - buf += dosStubSize + sizeof(PEMagic); - object::coff_file_header *coffHeader = - reinterpret_cast(buf); - coffHeader->TimeDateStamp = timestamp; + uint8_t *Buf = Buffer->getBufferStart(); + Buf += DOSStubSize + sizeof(PEMagic); + object::coff_file_header *CoffHeader = + reinterpret_cast(Buf); + CoffHeader->TimeDateStamp = Timestamp; } // Sort .pdata section contents according to PE/COFF spec 5.5. void Writer::sortExceptionTable() { - if (!firstPdata) + if (!FirstPdata) return; // We assume .pdata contains function table entries only. - auto bufAddr = [&](Chunk *c) { - OutputSection *os = c->getOutputSection(); - return buffer->getBufferStart() + os->getFileOff() + c->getRVA() - - os->getRVA(); + auto BufAddr = [&](Chunk *C) { + OutputSection *OS = C->getOutputSection(); + return Buffer->getBufferStart() + OS->getFileOff() + C->getRVA() - + OS->getRVA(); }; - uint8_t *begin = bufAddr(firstPdata); - uint8_t *end = bufAddr(lastPdata) + lastPdata->getSize(); - if (config->machine == AMD64) { - struct Entry { ulittle32_t begin, end, unwind; }; + uint8_t *Begin = BufAddr(FirstPdata); + uint8_t *End = BufAddr(LastPdata) + LastPdata->getSize(); + if (Config->Machine == AMD64) { + struct Entry { ulittle32_t Begin, End, Unwind; }; parallelSort( - MutableArrayRef((Entry *)begin, (Entry *)end), - [](const Entry &a, const Entry &b) { return a.begin < b.begin; }); + MutableArrayRef((Entry *)Begin, (Entry *)End), + [](const Entry &A, const Entry &B) { return A.Begin < B.Begin; }); return; } - if (config->machine == ARMNT || config->machine == ARM64) { - struct Entry { ulittle32_t begin, unwind; }; + if (Config->Machine == ARMNT || Config->Machine == ARM64) { + struct Entry { ulittle32_t Begin, Unwind; }; parallelSort( - MutableArrayRef((Entry *)begin, (Entry *)end), - [](const Entry &a, const Entry &b) { return a.begin < b.begin; }); + MutableArrayRef((Entry *)Begin, (Entry *)End), + [](const Entry &A, const Entry &B) { return A.Begin < B.Begin; }); return; } errs() << "warning: don't know how to handle .pdata.\n"; @@ -1855,92 +1808,92 @@ void Writer::sortExceptionTable() { // pointers in the order that they are listed in the object file (top to // bottom), otherwise global objects might not be initialized in the // correct order. -void Writer::sortCRTSectionChunks(std::vector &chunks) { - auto sectionChunkOrder = [](const Chunk *a, const Chunk *b) { - auto sa = dyn_cast(a); - auto sb = dyn_cast(b); - assert(sa && sb && "Non-section chunks in CRT section!"); +void Writer::sortCRTSectionChunks(std::vector &Chunks) { + auto SectionChunkOrder = [](const Chunk *A, const Chunk *B) { + auto SA = dyn_cast(A); + auto SB = dyn_cast(B); + assert(SA && SB && "Non-section chunks in CRT section!"); - StringRef sAObj = sa->file->mb.getBufferIdentifier(); - StringRef sBObj = sb->file->mb.getBufferIdentifier(); + StringRef SAObj = SA->File->MB.getBufferIdentifier(); + StringRef SBObj = SB->File->MB.getBufferIdentifier(); - return sAObj == sBObj && sa->getSectionNumber() < sb->getSectionNumber(); + return SAObj == SBObj && SA->getSectionNumber() < SB->getSectionNumber(); }; - llvm::stable_sort(chunks, sectionChunkOrder); + llvm::stable_sort(Chunks, SectionChunkOrder); - if (config->verbose) { - for (auto &c : chunks) { - auto sc = dyn_cast(c); - log(" " + sc->file->mb.getBufferIdentifier().str() + - ", SectionID: " + Twine(sc->getSectionNumber())); + if (Config->Verbose) { + for (auto &C : Chunks) { + auto SC = dyn_cast(C); + log(" " + SC->File->MB.getBufferIdentifier().str() + + ", SectionID: " + Twine(SC->getSectionNumber())); } } } -OutputSection *Writer::findSection(StringRef name) { - for (OutputSection *sec : outputSections) - if (sec->name == name) - return sec; +OutputSection *Writer::findSection(StringRef Name) { + for (OutputSection *Sec : OutputSections) + if (Sec->Name == Name) + return Sec; return nullptr; } uint32_t Writer::getSizeOfInitializedData() { - uint32_t res = 0; - for (OutputSection *s : outputSections) - if (s->header.Characteristics & IMAGE_SCN_CNT_INITIALIZED_DATA) - res += s->getRawSize(); - return res; + uint32_t Res = 0; + for (OutputSection *S : OutputSections) + if (S->Header.Characteristics & IMAGE_SCN_CNT_INITIALIZED_DATA) + Res += S->getRawSize(); + return Res; } // Add base relocations to .reloc section. void Writer::addBaserels() { - if (!config->relocatable) + if (!Config->Relocatable) return; - relocSec->chunks.clear(); - std::vector v; - for (OutputSection *sec : outputSections) { - if (sec->header.Characteristics & IMAGE_SCN_MEM_DISCARDABLE) + RelocSec->Chunks.clear(); + std::vector V; + for (OutputSection *Sec : OutputSections) { + if (Sec->Header.Characteristics & IMAGE_SCN_MEM_DISCARDABLE) continue; // Collect all locations for base relocations. - for (Chunk *c : sec->chunks) - c->getBaserels(&v); + for (Chunk *C : Sec->Chunks) + C->getBaserels(&V); // Add the addresses to .reloc section. - if (!v.empty()) - addBaserelBlocks(v); - v.clear(); + if (!V.empty()) + addBaserelBlocks(V); + V.clear(); } } // Add addresses to .reloc section. Note that addresses are grouped by page. -void Writer::addBaserelBlocks(std::vector &v) { - const uint32_t mask = ~uint32_t(pageSize - 1); - uint32_t page = v[0].rva & mask; - size_t i = 0, j = 1; - for (size_t e = v.size(); j < e; ++j) { - uint32_t p = v[j].rva & mask; - if (p == page) +void Writer::addBaserelBlocks(std::vector &V) { + const uint32_t Mask = ~uint32_t(PageSize - 1); + uint32_t Page = V[0].RVA & Mask; + size_t I = 0, J = 1; + for (size_t E = V.size(); J < E; ++J) { + uint32_t P = V[J].RVA & Mask; + if (P == Page) continue; - relocSec->addChunk(make(page, &v[i], &v[0] + j)); - i = j; - page = p; + RelocSec->addChunk(make(Page, &V[I], &V[0] + J)); + I = J; + Page = P; } - if (i == j) + if (I == J) return; - relocSec->addChunk(make(page, &v[i], &v[0] + j)); + RelocSec->addChunk(make(Page, &V[I], &V[0] + J)); } -PartialSection *Writer::createPartialSection(StringRef name, - uint32_t outChars) { - PartialSection *&pSec = partialSections[{name, outChars}]; - if (pSec) - return pSec; - pSec = make(name, outChars); - return pSec; +PartialSection *Writer::createPartialSection(StringRef Name, + uint32_t OutChars) { + PartialSection *&PSec = PartialSections[{Name, OutChars}]; + if (PSec) + return PSec; + PSec = make(Name, OutChars); + return PSec; } -PartialSection *Writer::findPartialSection(StringRef name, uint32_t outChars) { - auto it = partialSections.find({name, outChars}); - if (it != partialSections.end()) - return it->second; +PartialSection *Writer::findPartialSection(StringRef Name, uint32_t OutChars) { + auto It = PartialSections.find({Name, OutChars}); + if (It != PartialSections.end()) + return It->second; return nullptr; } diff --git a/lld/COFF/Writer.h b/lld/COFF/Writer.h index 96389df2ac0ae1..8fd97cb2c96fb0 100644 --- a/lld/COFF/Writer.h +++ b/lld/COFF/Writer.h @@ -18,17 +18,17 @@ namespace lld { namespace coff { -static const int pageSize = 4096; +static const int PageSize = 4096; void writeResult(); class PartialSection { public: - PartialSection(StringRef n, uint32_t chars) - : name(n), characteristics(chars) {} - StringRef name; - unsigned characteristics; - std::vector chunks; + PartialSection(StringRef N, uint32_t Chars) + : Name(N), Characteristics(Chars) {} + StringRef Name; + unsigned Characteristics; + std::vector Chunks; }; // OutputSection represents a section in an output file. It's a @@ -38,45 +38,45 @@ class PartialSection { // non-overlapping file offsets and RVAs. class OutputSection { public: - OutputSection(llvm::StringRef n, uint32_t chars) : name(n) { - header.Characteristics = chars; + OutputSection(llvm::StringRef N, uint32_t Chars) : Name(N) { + Header.Characteristics = Chars; } - void addChunk(Chunk *c); - void insertChunkAtStart(Chunk *c); - void merge(OutputSection *other); - void setPermissions(uint32_t c); - uint64_t getRVA() { return header.VirtualAddress; } - uint64_t getFileOff() { return header.PointerToRawData; } - void writeHeaderTo(uint8_t *buf); - void addContributingPartialSection(PartialSection *sec); + void addChunk(Chunk *C); + void insertChunkAtStart(Chunk *C); + void merge(OutputSection *Other); + void setPermissions(uint32_t C); + uint64_t getRVA() { return Header.VirtualAddress; } + uint64_t getFileOff() { return Header.PointerToRawData; } + void writeHeaderTo(uint8_t *Buf); + void addContributingPartialSection(PartialSection *Sec); // Returns the size of this section in an executable memory image. // This may be smaller than the raw size (the raw size is multiple // of disk sector size, so there may be padding at end), or may be // larger (if that's the case, the loader reserves spaces after end // of raw data). - uint64_t getVirtualSize() { return header.VirtualSize; } + uint64_t getVirtualSize() { return Header.VirtualSize; } // Returns the size of the section in the output file. - uint64_t getRawSize() { return header.SizeOfRawData; } + uint64_t getRawSize() { return Header.SizeOfRawData; } // Set offset into the string table storing this section name. // Used only when the name is longer than 8 bytes. - void setStringTableOff(uint32_t v) { stringTableOff = v; } + void setStringTableOff(uint32_t V) { StringTableOff = V; } // N.B. The section index is one based. - uint32_t sectionIndex = 0; + uint32_t SectionIndex = 0; - llvm::StringRef name; - llvm::object::coff_section header = {}; + llvm::StringRef Name; + llvm::object::coff_section Header = {}; - std::vector chunks; - std::vector origChunks; + std::vector Chunks; + std::vector OrigChunks; - std::vector contribSections; + std::vector ContribSections; private: - uint32_t stringTableOff = 0; + uint32_t StringTableOff = 0; }; } // namespace coff diff --git a/lld/Common/Args.cpp b/lld/Common/Args.cpp index 4ea3a435c7ae04..0691189a1568da 100644 --- a/lld/Common/Args.cpp +++ b/lld/Common/Args.cpp @@ -19,64 +19,64 @@ using namespace lld; // TODO(sbc): Remove this once CGOptLevel can be set completely based on bitcode // function metadata. -CodeGenOpt::Level lld::args::getCGOptLevel(int optLevelLTO) { - if (optLevelLTO == 3) +CodeGenOpt::Level lld::args::getCGOptLevel(int OptLevelLTO) { + if (OptLevelLTO == 3) return CodeGenOpt::Aggressive; - assert(optLevelLTO < 3); + assert(OptLevelLTO < 3); return CodeGenOpt::Default; } -int64_t lld::args::getInteger(opt::InputArgList &args, unsigned key, +int64_t lld::args::getInteger(opt::InputArgList &Args, unsigned Key, int64_t Default) { - auto *a = args.getLastArg(key); - if (!a) + auto *A = Args.getLastArg(Key); + if (!A) return Default; - int64_t v; - if (to_integer(a->getValue(), v, 10)) - return v; + int64_t V; + if (to_integer(A->getValue(), V, 10)) + return V; - StringRef spelling = args.getArgString(a->getIndex()); - error(spelling + ": number expected, but got '" + a->getValue() + "'"); + StringRef Spelling = Args.getArgString(A->getIndex()); + error(Spelling + ": number expected, but got '" + A->getValue() + "'"); return 0; } -std::vector lld::args::getStrings(opt::InputArgList &args, int id) { - std::vector v; - for (auto *arg : args.filtered(id)) - v.push_back(arg->getValue()); - return v; +std::vector lld::args::getStrings(opt::InputArgList &Args, int Id) { + std::vector V; + for (auto *Arg : Args.filtered(Id)) + V.push_back(Arg->getValue()); + return V; } -uint64_t lld::args::getZOptionValue(opt::InputArgList &args, int id, - StringRef key, uint64_t Default) { - for (auto *arg : args.filtered_reverse(id)) { - std::pair kv = StringRef(arg->getValue()).split('='); - if (kv.first == key) { - uint64_t result = Default; - if (!to_integer(kv.second, result)) - error("invalid " + key + ": " + kv.second); - return result; +uint64_t lld::args::getZOptionValue(opt::InputArgList &Args, int Id, + StringRef Key, uint64_t Default) { + for (auto *Arg : Args.filtered_reverse(Id)) { + std::pair KV = StringRef(Arg->getValue()).split('='); + if (KV.first == Key) { + uint64_t Result = Default; + if (!to_integer(KV.second, Result)) + error("invalid " + Key + ": " + KV.second); + return Result; } } return Default; } -std::vector lld::args::getLines(MemoryBufferRef mb) { - SmallVector arr; - mb.getBuffer().split(arr, '\n'); +std::vector lld::args::getLines(MemoryBufferRef MB) { + SmallVector Arr; + MB.getBuffer().split(Arr, '\n'); - std::vector ret; - for (StringRef s : arr) { - s = s.trim(); - if (!s.empty() && s[0] != '#') - ret.push_back(s); + std::vector Ret; + for (StringRef S : Arr) { + S = S.trim(); + if (!S.empty() && S[0] != '#') + Ret.push_back(S); } - return ret; + return Ret; } -StringRef lld::args::getFilenameWithoutExe(StringRef path) { - if (path.endswith_lower(".exe")) - return sys::path::stem(path); - return sys::path::filename(path); +StringRef lld::args::getFilenameWithoutExe(StringRef Path) { + if (Path.endswith_lower(".exe")) + return sys::path::stem(Path); + return sys::path::filename(Path); } diff --git a/lld/Common/ErrorHandler.cpp b/lld/Common/ErrorHandler.cpp index b91854c51cef81..7c68353069f7b2 100644 --- a/lld/Common/ErrorHandler.cpp +++ b/lld/Common/ErrorHandler.cpp @@ -16,7 +16,6 @@ #include "llvm/Support/ManagedStatic.h" #include "llvm/Support/raw_ostream.h" #include -#include #if !defined(_MSC_VER) && !defined(__MINGW32__) #include @@ -27,31 +26,29 @@ using namespace lld; // The functions defined in this file can be called from multiple threads, // but outs() or errs() are not thread-safe. We protect them using a mutex. -static std::mutex mu; - -// We want to separate multi-line messages with a newline. `sep` is "\n" -// if the last messages was multi-line. Otherwise "". -static StringRef sep; - -static StringRef getSeparator(const Twine &msg) { - if (StringRef(msg.str()).contains('\n')) - return "\n"; - return ""; +static std::mutex Mu; + +// Prints "\n" or does nothing, depending on Msg contents of +// the previous call of this function. +static void newline(raw_ostream *ErrorOS, const Twine &Msg) { + // True if the previous error message contained "\n". + // We want to separate multi-line error messages with a newline. + static bool Flag; + + if (Flag) + *ErrorOS << "\n"; + Flag = StringRef(Msg.str()).contains('\n'); } ErrorHandler &lld::errorHandler() { - static ErrorHandler handler; - return handler; -} - -void lld::enableColors(bool enable) { - errorHandler().errorOS->enable_colors(enable); + static ErrorHandler Handler; + return Handler; } -void lld::exitLld(int val) { +void lld::exitLld(int Val) { // Delete any temporary file, while keeping the memory mapping open. - if (errorHandler().outputBuffer) - errorHandler().outputBuffer->discard(); + if (errorHandler().OutputBuffer) + errorHandler().OutputBuffer->discard(); // Dealloc/destroy ManagedStatic variables before calling // _exit(). In a non-LTO build, this is a nop. In an LTO @@ -60,150 +57,87 @@ void lld::exitLld(int val) { outs().flush(); errs().flush(); - _exit(val); + _exit(Val); } -void lld::diagnosticHandler(const DiagnosticInfo &di) { - SmallString<128> s; - raw_svector_ostream os(s); - DiagnosticPrinterRawOStream dp(os); - di.print(dp); - switch (di.getSeverity()) { +void lld::diagnosticHandler(const DiagnosticInfo &DI) { + SmallString<128> S; + raw_svector_ostream OS(S); + DiagnosticPrinterRawOStream DP(OS); + DI.print(DP); + switch (DI.getSeverity()) { case DS_Error: - error(s); + error(S); break; case DS_Warning: - warn(s); + warn(S); break; case DS_Remark: case DS_Note: - message(s); + message(S); break; } } -void lld::checkError(Error e) { - handleAllErrors(std::move(e), - [&](ErrorInfoBase &eib) { error(eib.message()); }); +void lld::checkError(Error E) { + handleAllErrors(std::move(E), + [&](ErrorInfoBase &EIB) { error(EIB.message()); }); } -// This is for --vs-diagnostics. -// -// Normally, lld's error message starts with argv[0]. Therefore, it usually -// looks like this: -// -// ld.lld: error: ... -// -// This error message style is unfortunately unfriendly to Visual Studio -// IDE. VS interprets the first word of the first line as an error location -// and make it clickable, thus "ld.lld" in the above message would become a -// clickable text. When you click it, VS opens "ld.lld" executable file with -// a binary editor. -// -// As a workaround, we print out an error location instead of "ld.lld" if -// lld is running in VS diagnostics mode. As a result, error message will -// look like this: -// -// src/foo.c(35): error: ... -// -// This function returns an error location string. An error location is -// extracted from an error message using regexps. -std::string ErrorHandler::getLocation(const Twine &msg) { - if (!vsDiagnostics) - return logName; - - static std::regex regexes[] = { - std::regex( - R"(^undefined (?:\S+ )?symbol:.*\n)" - R"(>>> referenced by .+\((\S+):(\d+)\))"), - std::regex( - R"(^undefined (?:\S+ )?symbol:.*\n>>> referenced by (\S+):(\d+))"), - std::regex(R"(^undefined symbol:.*\n>>> referenced by (.*):)"), - std::regex( - R"(^duplicate symbol: .*\n>>> defined in (\S+)\n>>> defined in.*)"), - std::regex( - R"(^duplicate symbol: .*\n>>> defined at .+\((\S+):(\d+)\))"), - std::regex(R"(^duplicate symbol: .*\n>>> defined at (\S+):(\d+))"), - std::regex( - R"(.*\n>>> defined in .*\n>>> referenced by .+\((\S+):(\d+)\))"), - std::regex(R"(.*\n>>> defined in .*\n>>> referenced by (\S+):(\d+))"), - std::regex(R"((\S+):(\d+): unclosed quote)"), - }; - - std::string str = msg.str(); - for (std::regex &re : regexes) { - std::smatch m; - if (!std::regex_search(str, m, re)) - continue; - - assert(m.size() == 2 || m.size() == 3); - if (m.size() == 2) - return m.str(1); - return m.str(1) + "(" + m.str(2) + ")"; +void ErrorHandler::print(StringRef S, raw_ostream::Colors C) { + *ErrorOS << LogName << ": "; + if (ColorDiagnostics) { + ErrorOS->changeColor(C, true); + *ErrorOS << S; + ErrorOS->resetColor(); + } else { + *ErrorOS << S; } - - return logName; } -void ErrorHandler::log(const Twine &msg) { - if (!verbose) - return; - std::lock_guard lock(mu); - *errorOS << logName << ": " << msg << "\n"; +void ErrorHandler::log(const Twine &Msg) { + if (Verbose) { + std::lock_guard Lock(Mu); + *ErrorOS << LogName << ": " << Msg << "\n"; + } } -void ErrorHandler::message(const Twine &msg) { - std::lock_guard lock(mu); - outs() << msg << "\n"; +void ErrorHandler::message(const Twine &Msg) { + std::lock_guard Lock(Mu); + outs() << Msg << "\n"; outs().flush(); } -void ErrorHandler::warn(const Twine &msg) { - if (fatalWarnings) { - error(msg); +void ErrorHandler::warn(const Twine &Msg) { + if (FatalWarnings) { + error(Msg); return; } - std::lock_guard lock(mu); - *errorOS << sep << getLocation(msg) << ": " << Colors::MAGENTA - << "warning: " << Colors::RESET << msg << "\n"; - sep = getSeparator(msg); + std::lock_guard Lock(Mu); + newline(ErrorOS, Msg); + print("warning: ", raw_ostream::MAGENTA); + *ErrorOS << Msg << "\n"; } -void ErrorHandler::error(const Twine &msg) { - // If Visual Studio-style error message mode is enabled, - // this particular error is printed out as two errors. - if (vsDiagnostics) { - static std::regex re(R"(^(duplicate symbol: .*))" - R"((\n>>> defined at \S+:\d+.*\n>>>.*))" - R"((\n>>> defined at \S+:\d+.*\n>>>.*))"); - std::string str = msg.str(); - std::smatch m; - - if (std::regex_match(str, m, re)) { - error(m.str(1) + m.str(2)); - error(m.str(1) + m.str(3)); - return; - } - } - - std::lock_guard lock(mu); - - if (errorLimit == 0 || errorCount < errorLimit) { - *errorOS << sep << getLocation(msg) << ": " << Colors::RED - << "error: " << Colors::RESET << msg << "\n"; - } else if (errorCount == errorLimit) { - *errorOS << sep << getLocation(msg) << ": " << Colors::RED - << "error: " << Colors::RESET << errorLimitExceededMsg << "\n"; - if (exitEarly) +void ErrorHandler::error(const Twine &Msg) { + std::lock_guard Lock(Mu); + newline(ErrorOS, Msg); + + if (ErrorLimit == 0 || ErrorCount < ErrorLimit) { + print("error: ", raw_ostream::RED); + *ErrorOS << Msg << "\n"; + } else if (ErrorCount == ErrorLimit) { + print("error: ", raw_ostream::RED); + *ErrorOS << ErrorLimitExceededMsg << "\n"; + if (ExitEarly) exitLld(1); } - sep = getSeparator(msg); - ++errorCount; + ++ErrorCount; } -void ErrorHandler::fatal(const Twine &msg) { - error(msg); +void ErrorHandler::fatal(const Twine &Msg) { + error(Msg); exitLld(1); } diff --git a/lld/Common/Filesystem.cpp b/lld/Common/Filesystem.cpp index c3d3f998f03b75..6484286f14b822 100644 --- a/lld/Common/Filesystem.cpp +++ b/lld/Common/Filesystem.cpp @@ -38,43 +38,43 @@ using namespace lld; // // This function spawns a background thread to remove the file. // The calling thread returns almost immediately. -void lld::unlinkAsync(StringRef path) { +void lld::unlinkAsync(StringRef Path) { // Removing a file is async on windows. #if defined(_WIN32) - sys::fs::remove(path); + sys::fs::remove(Path); #else - if (!threadsEnabled || !sys::fs::exists(path) || - !sys::fs::is_regular_file(path)) + if (!ThreadsEnabled || !sys::fs::exists(Path) || + !sys::fs::is_regular_file(Path)) return; // We cannot just remove path from a different thread because we are now going // to create path as a new file. // Instead we open the file and unlink it on this thread. The unlink is fast // since the open fd guarantees that it is not removing the last reference. - int fd; - std::error_code ec = sys::fs::openFileForRead(path, fd); - sys::fs::remove(path); + int FD; + std::error_code EC = sys::fs::openFileForRead(Path, FD); + sys::fs::remove(Path); - if (ec) + if (EC) return; // close and therefore remove TempPath in background. - std::mutex m; - std::condition_variable cv; - bool started = false; - std::thread([&, fd] { + std::mutex M; + std::condition_variable CV; + bool Started = false; + std::thread([&, FD] { { - std::lock_guard l(m); - started = true; - cv.notify_all(); + std::lock_guard L(M); + Started = true; + CV.notify_all(); } - ::close(fd); + ::close(FD); }).detach(); // GLIBC 2.26 and earlier have race condition that crashes an entire process // if the main thread calls exit(2) while other thread is starting up. - std::unique_lock l(m); - cv.wait(l, [&] { return started; }); + std::unique_lock L(M); + CV.wait(L, [&] { return Started; }); #endif } @@ -90,10 +90,10 @@ void lld::unlinkAsync(StringRef path) { // FileOutputBuffer doesn't touch a desitnation file until commit() // is called. We use that class without calling commit() to predict // if the given file is writable. -std::error_code lld::tryCreateFile(StringRef path) { - if (path.empty()) +std::error_code lld::tryCreateFile(StringRef Path) { + if (Path.empty()) return std::error_code(); - if (path == "-") + if (Path == "-") return std::error_code(); - return errorToErrorCode(FileOutputBuffer::create(path, 1).takeError()); + return errorToErrorCode(FileOutputBuffer::create(Path, 1).takeError()); } diff --git a/lld/Common/Memory.cpp b/lld/Common/Memory.cpp index c53e1d3e6cfc76..5a6ead421ecff6 100644 --- a/lld/Common/Memory.cpp +++ b/lld/Common/Memory.cpp @@ -11,12 +11,12 @@ using namespace llvm; using namespace lld; -BumpPtrAllocator lld::bAlloc; -StringSaver lld::saver{bAlloc}; -std::vector lld::SpecificAllocBase::instances; +BumpPtrAllocator lld::BAlloc; +StringSaver lld::Saver{BAlloc}; +std::vector lld::SpecificAllocBase::Instances; void lld::freeArena() { - for (SpecificAllocBase *alloc : SpecificAllocBase::instances) - alloc->reset(); - bAlloc.Reset(); + for (SpecificAllocBase *Alloc : SpecificAllocBase::Instances) + Alloc->reset(); + BAlloc.Reset(); } diff --git a/lld/Common/Reproduce.cpp b/lld/Common/Reproduce.cpp index 24210c420418c8..ce33d367bf559b 100644 --- a/lld/Common/Reproduce.cpp +++ b/lld/Common/Reproduce.cpp @@ -21,41 +21,39 @@ using namespace llvm::sys; // assuming that the current directory is "/home/john/bar". // Returned string is a forward slash separated path even on Windows to avoid // a mess with backslash-as-escape and backslash-as-path-separator. -std::string lld::relativeToRoot(StringRef path) { - SmallString<128> abs = path; - if (fs::make_absolute(abs)) - return path; - path::remove_dots(abs, /*remove_dot_dot=*/true); +std::string lld::relativeToRoot(StringRef Path) { + SmallString<128> Abs = Path; + if (fs::make_absolute(Abs)) + return Path; + path::remove_dots(Abs, /*remove_dot_dot=*/true); // This is Windows specific. root_name() returns a drive letter // (e.g. "c:") or a UNC name (//net). We want to keep it as part // of the result. - SmallString<128> res; - StringRef root = path::root_name(abs); - if (root.endswith(":")) - res = root.drop_back(); - else if (root.startswith("//")) - res = root.substr(2); + SmallString<128> Res; + StringRef Root = path::root_name(Abs); + if (Root.endswith(":")) + Res = Root.drop_back(); + else if (Root.startswith("//")) + Res = Root.substr(2); - path::append(res, path::relative_path(abs)); - return path::convert_to_slash(res); + path::append(Res, path::relative_path(Abs)); + return path::convert_to_slash(Res); } // Quote a given string if it contains a space character. -std::string lld::quote(StringRef s) { - if (s.contains(' ')) - return ("\"" + s + "\"").str(); - return s; +std::string lld::quote(StringRef S) { + if (S.contains(' ')) + return ("\"" + S + "\"").str(); + return S; } -// Converts an Arg to a string representation suitable for a response file. -// To show an Arg in a diagnostic, use Arg::getAsString() instead. -std::string lld::toString(const opt::Arg &arg) { - std::string k = arg.getSpelling(); - if (arg.getNumValues() == 0) - return k; - std::string v = quote(arg.getValue()); - if (arg.getOption().getRenderStyle() == opt::Option::RenderJoinedStyle) - return k + v; - return k + " " + v; +std::string lld::toString(const opt::Arg &Arg) { + std::string K = Arg.getSpelling(); + if (Arg.getNumValues() == 0) + return K; + std::string V = quote(Arg.getValue()); + if (Arg.getOption().getRenderStyle() == opt::Option::RenderJoinedStyle) + return K + V; + return K + " " + V; } diff --git a/lld/Common/Strings.cpp b/lld/Common/Strings.cpp index 2240f9644e1213..afd5bd39f7704d 100644 --- a/lld/Common/Strings.cpp +++ b/lld/Common/Strings.cpp @@ -19,85 +19,85 @@ using namespace llvm; using namespace lld; // Returns the demangled C++ symbol name for Name. -Optional lld::demangleItanium(StringRef name) { +Optional lld::demangleItanium(StringRef Name) { // itaniumDemangle can be used to demangle strings other than symbol // names which do not necessarily start with "_Z". Name can be // either a C or C++ symbol. Don't call itaniumDemangle if the name // does not look like a C++ symbol name to avoid getting unexpected // result for a C symbol that happens to match a mangled type name. - if (!name.startswith("_Z")) + if (!Name.startswith("_Z")) return None; - char *buf = itaniumDemangle(name.str().c_str(), nullptr, nullptr, nullptr); - if (!buf) + char *Buf = itaniumDemangle(Name.str().c_str(), nullptr, nullptr, nullptr); + if (!Buf) return None; - std::string s(buf); - free(buf); - return s; + std::string S(Buf); + free(Buf); + return S; } -Optional lld::demangleMSVC(StringRef name) { - std::string prefix; - if (name.consume_front("__imp_")) - prefix = "__declspec(dllimport) "; +Optional lld::demangleMSVC(StringRef Name) { + std::string Prefix; + if (Name.consume_front("__imp_")) + Prefix = "__declspec(dllimport) "; // Demangle only C++ names. - if (!name.startswith("?")) + if (!Name.startswith("?")) return None; - char *buf = microsoftDemangle(name.str().c_str(), nullptr, nullptr, nullptr); - if (!buf) + char *Buf = microsoftDemangle(Name.str().c_str(), nullptr, nullptr, nullptr); + if (!Buf) return None; - std::string s(buf); - free(buf); - return prefix + s; + std::string S(Buf); + free(Buf); + return Prefix + S; } -StringMatcher::StringMatcher(ArrayRef pat) { - for (StringRef s : pat) { - Expected pat = GlobPattern::create(s); - if (!pat) - error(toString(pat.takeError())); +StringMatcher::StringMatcher(ArrayRef Pat) { + for (StringRef S : Pat) { + Expected Pat = GlobPattern::create(S); + if (!Pat) + error(toString(Pat.takeError())); else - patterns.push_back(*pat); + Patterns.push_back(*Pat); } } -bool StringMatcher::match(StringRef s) const { - for (const GlobPattern &pat : patterns) - if (pat.match(s)) +bool StringMatcher::match(StringRef S) const { + for (const GlobPattern &Pat : Patterns) + if (Pat.match(S)) return true; return false; } // Converts a hex string (e.g. "deadbeef") to a vector. -std::vector lld::parseHex(StringRef s) { - std::vector hex; - while (!s.empty()) { - StringRef b = s.substr(0, 2); - s = s.substr(2); - uint8_t h; - if (!to_integer(b, h, 16)) { - error("not a hexadecimal value: " + b); +std::vector lld::parseHex(StringRef S) { + std::vector Hex; + while (!S.empty()) { + StringRef B = S.substr(0, 2); + S = S.substr(2); + uint8_t H; + if (!to_integer(B, H, 16)) { + error("not a hexadecimal value: " + B); return {}; } - hex.push_back(h); + Hex.push_back(H); } - return hex; + return Hex; } // Returns true if S is valid as a C language identifier. -bool lld::isValidCIdentifier(StringRef s) { - return !s.empty() && (isAlpha(s[0]) || s[0] == '_') && - std::all_of(s.begin() + 1, s.end(), - [](char c) { return c == '_' || isAlnum(c); }); +bool lld::isValidCIdentifier(StringRef S) { + return !S.empty() && (isAlpha(S[0]) || S[0] == '_') && + std::all_of(S.begin() + 1, S.end(), + [](char C) { return C == '_' || isAlnum(C); }); } // Write the contents of the a buffer to a file -void lld::saveBuffer(StringRef buffer, const Twine &path) { - std::error_code ec; - raw_fd_ostream os(path.str(), ec, sys::fs::OpenFlags::OF_None); - if (ec) - error("cannot create " + path + ": " + ec.message()); - os << buffer; +void lld::saveBuffer(StringRef Buffer, const Twine &Path) { + std::error_code EC; + raw_fd_ostream OS(Path.str(), EC, sys::fs::OpenFlags::F_None); + if (EC) + error("cannot create " + Path + ": " + EC.message()); + OS << Buffer; } diff --git a/lld/Common/TargetOptionsCommandFlags.cpp b/lld/Common/TargetOptionsCommandFlags.cpp index 0137feb63f371d..d4c29d7f88b80d 100644 --- a/lld/Common/TargetOptionsCommandFlags.cpp +++ b/lld/Common/TargetOptionsCommandFlags.cpp @@ -26,10 +26,6 @@ llvm::TargetOptions lld::initTargetOptionsFromCodeGenFlags() { return ::InitTargetOptionsFromCodeGenFlags(); } -llvm::Optional lld::getRelocModelFromCMModel() { - return getRelocModel(); -} - llvm::Optional lld::getCodeModelFromCMModel() { return getCodeModel(); } diff --git a/lld/Common/Threads.cpp b/lld/Common/Threads.cpp index af04972a37602c..5e0af288263605 100644 --- a/lld/Common/Threads.cpp +++ b/lld/Common/Threads.cpp @@ -8,4 +8,4 @@ #include "lld/Common/Threads.h" -bool lld::threadsEnabled = true; +bool lld::ThreadsEnabled = true; diff --git a/lld/Common/Timer.cpp b/lld/Common/Timer.cpp index 4b7d11003b2cbb..30862539c785dc 100644 --- a/lld/Common/Timer.cpp +++ b/lld/Common/Timer.cpp @@ -13,43 +13,43 @@ using namespace lld; using namespace llvm; -ScopedTimer::ScopedTimer(Timer &t) : t(&t) { t.start(); } +ScopedTimer::ScopedTimer(Timer &T) : T(&T) { T.start(); } void ScopedTimer::stop() { - if (!t) + if (!T) return; - t->stop(); - t = nullptr; + T->stop(); + T = nullptr; } ScopedTimer::~ScopedTimer() { stop(); } -Timer::Timer(llvm::StringRef name) : name(name), parent(nullptr) {} -Timer::Timer(llvm::StringRef name, Timer &parent) - : name(name), parent(&parent) {} +Timer::Timer(llvm::StringRef Name) : Name(Name), Parent(nullptr) {} +Timer::Timer(llvm::StringRef Name, Timer &Parent) + : Name(Name), Parent(&Parent) {} void Timer::start() { - if (parent && total.count() == 0) - parent->children.push_back(this); - startTime = std::chrono::high_resolution_clock::now(); + if (Parent && Total.count() == 0) + Parent->Children.push_back(this); + StartTime = std::chrono::high_resolution_clock::now(); } void Timer::stop() { - total += (std::chrono::high_resolution_clock::now() - startTime); + Total += (std::chrono::high_resolution_clock::now() - StartTime); } Timer &Timer::root() { - static Timer rootTimer("Total Link Time"); - return rootTimer; + static Timer RootTimer("Total Link Time"); + return RootTimer; } void Timer::print() { - double totalDuration = static_cast(root().millis()); + double TotalDuration = static_cast(root().millis()); // We want to print the grand total under all the intermediate phases, so we // print all children first, then print the total under that. - for (const auto &child : children) - child->print(1, totalDuration); + for (const auto &Child : Children) + Child->print(1, TotalDuration); message(std::string(49, '-')); @@ -58,22 +58,22 @@ void Timer::print() { double Timer::millis() const { return std::chrono::duration_cast>( - total) + Total) .count(); } -void Timer::print(int depth, double totalDuration, bool recurse) const { - double p = 100.0 * millis() / totalDuration; +void Timer::print(int Depth, double TotalDuration, bool Recurse) const { + double P = 100.0 * millis() / TotalDuration; - SmallString<32> str; - llvm::raw_svector_ostream stream(str); - std::string s = std::string(depth * 2, ' ') + name + std::string(":"); - stream << format("%-30s%5d ms (%5.1f%%)", s.c_str(), (int)millis(), p); + SmallString<32> Str; + llvm::raw_svector_ostream Stream(Str); + std::string S = std::string(Depth * 2, ' ') + Name + std::string(":"); + Stream << format("%-30s%5d ms (%5.1f%%)", S.c_str(), (int)millis(), P); - message(str); + message(Str); - if (recurse) { - for (const auto &child : children) - child->print(depth + 1, totalDuration); + if (Recurse) { + for (const auto &Child : Children) + Child->print(Depth + 1, TotalDuration); } } diff --git a/lld/ELF/AArch64ErrataFix.cpp b/lld/ELF/AArch64ErrataFix.cpp index b2eda4dcbc4e98..ebf43ea5095722 100644 --- a/lld/ELF/AArch64ErrataFix.cpp +++ b/lld/ELF/AArch64ErrataFix.cpp @@ -56,8 +56,8 @@ using namespace lld::elf; // ADRP // | 1 | immlo (2) | 1 | 0 0 0 0 | immhi (19) | Rd (5) | -static bool isADRP(uint32_t instr) { - return (instr & 0x9f000000) == 0x90000000; +static bool isADRP(uint32_t Instr) { + return (Instr & 0x9f000000) == 0x90000000; } // Load and store bit patterns from ARMv8-A ARM ARM. @@ -66,8 +66,8 @@ static bool isADRP(uint32_t instr) { // All loads and stores have 1 (at bit postion 27), (0 at bit position 25). // | op0 x op1 (2) | 1 op2 0 op3 (2) | x | op4 (5) | xxxx | op5 (2) | x (10) | -static bool isLoadStoreClass(uint32_t instr) { - return (instr & 0x0a000000) == 0x08000000; +static bool isLoadStoreClass(uint32_t Instr) { + return (Instr & 0x0a000000) == 0x08000000; } // LDN/STN multiple no offset @@ -82,20 +82,20 @@ static bool isLoadStoreClass(uint32_t instr) { // opcode == 0110 ST1 3 registers. // opcode == 0111 ST1 1 register. // opcode == 1010 ST1 2 registers. -static bool isST1MultipleOpcode(uint32_t instr) { - return (instr & 0x0000f000) == 0x00002000 || - (instr & 0x0000f000) == 0x00006000 || - (instr & 0x0000f000) == 0x00007000 || - (instr & 0x0000f000) == 0x0000a000; +static bool isST1MultipleOpcode(uint32_t Instr) { + return (Instr & 0x0000f000) == 0x00002000 || + (Instr & 0x0000f000) == 0x00006000 || + (Instr & 0x0000f000) == 0x00007000 || + (Instr & 0x0000f000) == 0x0000a000; } -static bool isST1Multiple(uint32_t instr) { - return (instr & 0xbfff0000) == 0x0c000000 && isST1MultipleOpcode(instr); +static bool isST1Multiple(uint32_t Instr) { + return (Instr & 0xbfff0000) == 0x0c000000 && isST1MultipleOpcode(Instr); } // Writes to Rn (writeback). -static bool isST1MultiplePost(uint32_t instr) { - return (instr & 0xbfe00000) == 0x0c800000 && isST1MultipleOpcode(instr); +static bool isST1MultiplePost(uint32_t Instr) { + return (Instr & 0xbfe00000) == 0x0c800000 && isST1MultipleOpcode(Instr); } // LDN/STN single no offset @@ -110,41 +110,41 @@ static bool isST1MultiplePost(uint32_t instr) { // opcode == 000 ST1 8-bit. // opcode == 010 ST1 16-bit. // opcode == 100 ST1 32 or 64-bit (Size determines which). -static bool isST1SingleOpcode(uint32_t instr) { - return (instr & 0x0040e000) == 0x00000000 || - (instr & 0x0040e000) == 0x00004000 || - (instr & 0x0040e000) == 0x00008000; +static bool isST1SingleOpcode(uint32_t Instr) { + return (Instr & 0x0040e000) == 0x00000000 || + (Instr & 0x0040e000) == 0x00004000 || + (Instr & 0x0040e000) == 0x00008000; } -static bool isST1Single(uint32_t instr) { - return (instr & 0xbfff0000) == 0x0d000000 && isST1SingleOpcode(instr); +static bool isST1Single(uint32_t Instr) { + return (Instr & 0xbfff0000) == 0x0d000000 && isST1SingleOpcode(Instr); } // Writes to Rn (writeback). -static bool isST1SinglePost(uint32_t instr) { - return (instr & 0xbfe00000) == 0x0d800000 && isST1SingleOpcode(instr); +static bool isST1SinglePost(uint32_t Instr) { + return (Instr & 0xbfe00000) == 0x0d800000 && isST1SingleOpcode(Instr); } -static bool isST1(uint32_t instr) { - return isST1Multiple(instr) || isST1MultiplePost(instr) || - isST1Single(instr) || isST1SinglePost(instr); +static bool isST1(uint32_t Instr) { + return isST1Multiple(Instr) || isST1MultiplePost(Instr) || + isST1Single(Instr) || isST1SinglePost(Instr); } // Load/store exclusive // | size (2) 00 | 1000 | o2 L o1 | Rs (5) | o0 | Rt2 (5) | Rn (5) | Rt (5) | // L == 0 for Stores. -static bool isLoadStoreExclusive(uint32_t instr) { - return (instr & 0x3f000000) == 0x08000000; +static bool isLoadStoreExclusive(uint32_t Instr) { + return (Instr & 0x3f000000) == 0x08000000; } -static bool isLoadExclusive(uint32_t instr) { - return (instr & 0x3f400000) == 0x08400000; +static bool isLoadExclusive(uint32_t Instr) { + return (Instr & 0x3f400000) == 0x08400000; } // Load register literal // | opc (2) 01 | 1 V 00 | imm19 | Rt (5) | -static bool isLoadLiteral(uint32_t instr) { - return (instr & 0x3b000000) == 0x18000000; +static bool isLoadLiteral(uint32_t Instr) { + return (Instr & 0x3b000000) == 0x18000000; } // Load/store no-allocate pair @@ -152,8 +152,8 @@ static bool isLoadLiteral(uint32_t instr) { // | opc (2) 10 | 1 V 00 | 0 L | imm7 | Rt2 (5) | Rn (5) | Rt (5) | // L == 0 for stores. // Never writes to register -static bool isSTNP(uint32_t instr) { - return (instr & 0x3bc00000) == 0x28000000; +static bool isSTNP(uint32_t Instr) { + return (Instr & 0x3bc00000) == 0x28000000; } // Load/store register pair @@ -161,69 +161,69 @@ static bool isSTNP(uint32_t instr) { // | opc (2) 10 | 1 V 00 | 1 L | imm7 | Rt2 (5) | Rn (5) | Rt (5) | // L == 0 for stores, V == 0 for Scalar, V == 1 for Simd/FP // Writes to Rn. -static bool isSTPPost(uint32_t instr) { - return (instr & 0x3bc00000) == 0x28800000; +static bool isSTPPost(uint32_t Instr) { + return (Instr & 0x3bc00000) == 0x28800000; } // (offset) // | opc (2) 10 | 1 V 01 | 0 L | imm7 | Rt2 (5) | Rn (5) | Rt (5) | -static bool isSTPOffset(uint32_t instr) { - return (instr & 0x3bc00000) == 0x29000000; +static bool isSTPOffset(uint32_t Instr) { + return (Instr & 0x3bc00000) == 0x29000000; } // (pre-index) // | opc (2) 10 | 1 V 01 | 1 L | imm7 | Rt2 (5) | Rn (5) | Rt (5) | // Writes to Rn. -static bool isSTPPre(uint32_t instr) { - return (instr & 0x3bc00000) == 0x29800000; +static bool isSTPPre(uint32_t Instr) { + return (Instr & 0x3bc00000) == 0x29800000; } -static bool isSTP(uint32_t instr) { - return isSTPPost(instr) || isSTPOffset(instr) || isSTPPre(instr); +static bool isSTP(uint32_t Instr) { + return isSTPPost(Instr) || isSTPOffset(Instr) || isSTPPre(Instr); } // Load/store register (unscaled immediate) // | size (2) 11 | 1 V 00 | opc (2) 0 | imm9 | 00 | Rn (5) | Rt (5) | // V == 0 for Scalar, V == 1 for Simd/FP. -static bool isLoadStoreUnscaled(uint32_t instr) { - return (instr & 0x3b000c00) == 0x38000000; +static bool isLoadStoreUnscaled(uint32_t Instr) { + return (Instr & 0x3b000c00) == 0x38000000; } // Load/store register (immediate post-indexed) // | size (2) 11 | 1 V 00 | opc (2) 0 | imm9 | 01 | Rn (5) | Rt (5) | -static bool isLoadStoreImmediatePost(uint32_t instr) { - return (instr & 0x3b200c00) == 0x38000400; +static bool isLoadStoreImmediatePost(uint32_t Instr) { + return (Instr & 0x3b200c00) == 0x38000400; } // Load/store register (unprivileged) // | size (2) 11 | 1 V 00 | opc (2) 0 | imm9 | 10 | Rn (5) | Rt (5) | -static bool isLoadStoreUnpriv(uint32_t instr) { - return (instr & 0x3b200c00) == 0x38000800; +static bool isLoadStoreUnpriv(uint32_t Instr) { + return (Instr & 0x3b200c00) == 0x38000800; } // Load/store register (immediate pre-indexed) // | size (2) 11 | 1 V 00 | opc (2) 0 | imm9 | 11 | Rn (5) | Rt (5) | -static bool isLoadStoreImmediatePre(uint32_t instr) { - return (instr & 0x3b200c00) == 0x38000c00; +static bool isLoadStoreImmediatePre(uint32_t Instr) { + return (Instr & 0x3b200c00) == 0x38000c00; } // Load/store register (register offset) // | size (2) 11 | 1 V 00 | opc (2) 1 | Rm (5) | option (3) S | 10 | Rn | Rt | -static bool isLoadStoreRegisterOff(uint32_t instr) { - return (instr & 0x3b200c00) == 0x38200800; +static bool isLoadStoreRegisterOff(uint32_t Instr) { + return (Instr & 0x3b200c00) == 0x38200800; } // Load/store register (unsigned immediate) // | size (2) 11 | 1 V 01 | opc (2) | imm12 | Rn (5) | Rt (5) | -static bool isLoadStoreRegisterUnsigned(uint32_t instr) { - return (instr & 0x3b000000) == 0x39000000; +static bool isLoadStoreRegisterUnsigned(uint32_t Instr) { + return (Instr & 0x3b000000) == 0x39000000; } // Rt is always in bit position 0 - 4. -static uint32_t getRt(uint32_t instr) { return (instr & 0x1f); } +static uint32_t getRt(uint32_t Instr) { return (Instr & 0x1f); } // Rn is always in bit position 5 - 9. -static uint32_t getRn(uint32_t instr) { return (instr >> 5) & 0x1f; } +static uint32_t getRn(uint32_t Instr) { return (Instr >> 5) & 0x1f; } // C4.1.2 Branches, Exception Generating and System instructions // | op0 (3) 1 | 01 op1 (4) | x (22) | @@ -232,41 +232,41 @@ static uint32_t getRn(uint32_t instr) { return (instr >> 5) & 0x1f; } // op0 == x00 101 op1 == xxxx Unconditional Branch immediate. // op0 == x01 101 op1 == 0xxx Compare and branch immediate. // op0 == x01 101 op1 == 1xxx Test and branch immediate. -static bool isBranch(uint32_t instr) { - return ((instr & 0xfe000000) == 0xd6000000) || // Cond branch. - ((instr & 0xfe000000) == 0x54000000) || // Uncond branch reg. - ((instr & 0x7c000000) == 0x14000000) || // Uncond branch imm. - ((instr & 0x7c000000) == 0x34000000); // Compare and test branch. +static bool isBranch(uint32_t Instr) { + return ((Instr & 0xfe000000) == 0xd6000000) || // Cond branch. + ((Instr & 0xfe000000) == 0x54000000) || // Uncond branch reg. + ((Instr & 0x7c000000) == 0x14000000) || // Uncond branch imm. + ((Instr & 0x7c000000) == 0x34000000); // Compare and test branch. } -static bool isV8SingleRegisterNonStructureLoadStore(uint32_t instr) { - return isLoadStoreUnscaled(instr) || isLoadStoreImmediatePost(instr) || - isLoadStoreUnpriv(instr) || isLoadStoreImmediatePre(instr) || - isLoadStoreRegisterOff(instr) || isLoadStoreRegisterUnsigned(instr); +static bool isV8SingleRegisterNonStructureLoadStore(uint32_t Instr) { + return isLoadStoreUnscaled(Instr) || isLoadStoreImmediatePost(Instr) || + isLoadStoreUnpriv(Instr) || isLoadStoreImmediatePre(Instr) || + isLoadStoreRegisterOff(Instr) || isLoadStoreRegisterUnsigned(Instr); } // Note that this function refers to v8.0 only and does not include the // additional load and store instructions added for in later revisions of // the architecture such as the Atomic memory operations introduced // in v8.1. -static bool isV8NonStructureLoad(uint32_t instr) { - if (isLoadExclusive(instr)) +static bool isV8NonStructureLoad(uint32_t Instr) { + if (isLoadExclusive(Instr)) return true; - if (isLoadLiteral(instr)) + if (isLoadLiteral(Instr)) return true; - else if (isV8SingleRegisterNonStructureLoadStore(instr)) { + else if (isV8SingleRegisterNonStructureLoadStore(Instr)) { // For Load and Store single register, Loads are derived from a // combination of the Size, V and Opc fields. - uint32_t size = (instr >> 30) & 0xff; - uint32_t v = (instr >> 26) & 0x1; - uint32_t opc = (instr >> 22) & 0x3; + uint32_t Size = (Instr >> 30) & 0xff; + uint32_t V = (Instr >> 26) & 0x1; + uint32_t Opc = (Instr >> 22) & 0x3; // For the load and store instructions that we are decoding. // Opc == 0 are all stores. // Opc == 1 with a couple of exceptions are loads. The exceptions are: // Size == 00 (0), V == 1, Opc == 10 (2) which is a store and // Size == 11 (3), V == 0, Opc == 10 (2) which is a prefetch. - return opc != 0 && !(size == 0 && v == 1 && opc == 2) && - !(size == 3 && v == 0 && opc == 2); + return Opc != 0 && !(Size == 0 && V == 1 && Opc == 2) && + !(Size == 3 && V == 0 && Opc == 2); } return false; } @@ -275,18 +275,18 @@ static bool isV8NonStructureLoad(uint32_t instr) { // needed for errata 843419. // Instruction with writeback updates the index register after the load/store. -static bool hasWriteback(uint32_t instr) { - return isLoadStoreImmediatePre(instr) || isLoadStoreImmediatePost(instr) || - isSTPPre(instr) || isSTPPost(instr) || isST1SinglePost(instr) || - isST1MultiplePost(instr); +static bool hasWriteback(uint32_t Instr) { + return isLoadStoreImmediatePre(Instr) || isLoadStoreImmediatePost(Instr) || + isSTPPre(Instr) || isSTPPost(Instr) || isST1SinglePost(Instr) || + isST1MultiplePost(Instr); } // For the load and store class of instructions, a load can write to the // destination register, a load and a store can write to the base register when // the instruction has writeback. -static bool doesLoadStoreWriteToReg(uint32_t instr, uint32_t reg) { - return (isV8NonStructureLoad(instr) && getRt(instr) == reg) || - (hasWriteback(instr) && getRn(instr) == reg); +static bool doesLoadStoreWriteToReg(uint32_t Instr, uint32_t Reg) { + return (isV8NonStructureLoad(Instr) && getRt(Instr) == Reg) || + (hasWriteback(Instr) && getRn(Instr) == Reg); } // Scanner for Cortex-A53 errata 843419 @@ -318,18 +318,18 @@ static bool doesLoadStoreWriteToReg(uint32_t instr, uint32_t reg) { // Return true if the Instruction sequence Adrp, Instr2, and Instr4 match // the erratum sequence. The Adrp, Instr2 and Instr4 correspond to 1.), 2.), // and 4.) in the Scanner for Cortex-A53 errata comment above. -static bool is843419ErratumSequence(uint32_t instr1, uint32_t instr2, - uint32_t instr4) { - if (!isADRP(instr1)) +static bool is843419ErratumSequence(uint32_t Instr1, uint32_t Instr2, + uint32_t Instr4) { + if (!isADRP(Instr1)) return false; - uint32_t rn = getRt(instr1); - return isLoadStoreClass(instr2) && - (isLoadStoreExclusive(instr2) || isLoadLiteral(instr2) || - isV8SingleRegisterNonStructureLoadStore(instr2) || isSTP(instr2) || - isSTNP(instr2) || isST1(instr2)) && - !doesLoadStoreWriteToReg(instr2, rn) && - isLoadStoreRegisterUnsigned(instr4) && getRn(instr4) == rn; + uint32_t Rn = getRt(Instr1); + return isLoadStoreClass(Instr2) && + (isLoadStoreExclusive(Instr2) || isLoadLiteral(Instr2) || + isV8SingleRegisterNonStructureLoadStore(Instr2) || isSTP(Instr2) || + isSTNP(Instr2) || isST1(Instr2)) && + !doesLoadStoreWriteToReg(Instr2, Rn) && + isLoadStoreRegisterUnsigned(Instr4) && getRn(Instr4) == Rn; } // Scan the instruction sequence starting at Offset Off from the base of @@ -338,143 +338,143 @@ static bool is843419ErratumSequence(uint32_t instr1, uint32_t instr2, // instructions we've scanned. // Return the offset of the load or store instruction in IS that we want to // patch or 0 if no patch required. -static uint64_t scanCortexA53Errata843419(InputSection *isec, uint64_t &off, - uint64_t limit) { - uint64_t isecAddr = isec->getVA(0); +static uint64_t scanCortexA53Errata843419(InputSection *IS, uint64_t &Off, + uint64_t Limit) { + uint64_t ISAddr = IS->getVA(0); // Advance Off so that (ISAddr + Off) modulo 0x1000 is at least 0xff8. - uint64_t initialPageOff = (isecAddr + off) & 0xfff; - if (initialPageOff < 0xff8) - off += 0xff8 - initialPageOff; + uint64_t InitialPageOff = (ISAddr + Off) & 0xfff; + if (InitialPageOff < 0xff8) + Off += 0xff8 - InitialPageOff; - bool optionalAllowed = limit - off > 12; - if (off >= limit || limit - off < 12) { + bool OptionalAllowed = Limit - Off > 12; + if (Off >= Limit || Limit - Off < 12) { // Need at least 3 4-byte sized instructions to trigger erratum. - off = limit; + Off = Limit; return 0; } - uint64_t patchOff = 0; - const uint8_t *buf = isec->data().begin(); - const ulittle32_t *instBuf = reinterpret_cast(buf + off); - uint32_t instr1 = *instBuf++; - uint32_t instr2 = *instBuf++; - uint32_t instr3 = *instBuf++; - if (is843419ErratumSequence(instr1, instr2, instr3)) { - patchOff = off + 8; - } else if (optionalAllowed && !isBranch(instr3)) { - uint32_t instr4 = *instBuf++; - if (is843419ErratumSequence(instr1, instr2, instr4)) - patchOff = off + 12; + uint64_t PatchOff = 0; + const uint8_t *Buf = IS->data().begin(); + const ulittle32_t *InstBuf = reinterpret_cast(Buf + Off); + uint32_t Instr1 = *InstBuf++; + uint32_t Instr2 = *InstBuf++; + uint32_t Instr3 = *InstBuf++; + if (is843419ErratumSequence(Instr1, Instr2, Instr3)) { + PatchOff = Off + 8; + } else if (OptionalAllowed && !isBranch(Instr3)) { + uint32_t Instr4 = *InstBuf++; + if (is843419ErratumSequence(Instr1, Instr2, Instr4)) + PatchOff = Off + 12; } - if (((isecAddr + off) & 0xfff) == 0xff8) - off += 4; + if (((ISAddr + Off) & 0xfff) == 0xff8) + Off += 4; else - off += 0xffc; - return patchOff; + Off += 0xffc; + return PatchOff; } class lld::elf::Patch843419Section : public SyntheticSection { public: - Patch843419Section(InputSection *p, uint64_t off); + Patch843419Section(InputSection *P, uint64_t Off); - void writeTo(uint8_t *buf) override; + void writeTo(uint8_t *Buf) override; size_t getSize() const override { return 8; } uint64_t getLDSTAddr() const; // The Section we are patching. - const InputSection *patchee; + const InputSection *Patchee; // The offset of the instruction in the Patchee section we are patching. - uint64_t patcheeOffset; + uint64_t PatcheeOffset; // A label for the start of the Patch that we can use as a relocation target. - Symbol *patchSym; + Symbol *PatchSym; }; -lld::elf::Patch843419Section::Patch843419Section(InputSection *p, uint64_t off) +lld::elf::Patch843419Section::Patch843419Section(InputSection *P, uint64_t Off) : SyntheticSection(SHF_ALLOC | SHF_EXECINSTR, SHT_PROGBITS, 4, ".text.patch"), - patchee(p), patcheeOffset(off) { - this->parent = p->getParent(); - patchSym = addSyntheticLocal( - saver.save("__CortexA53843419_" + utohexstr(getLDSTAddr())), STT_FUNC, 0, + Patchee(P), PatcheeOffset(Off) { + this->Parent = P->getParent(); + PatchSym = addSyntheticLocal( + Saver.save("__CortexA53843419_" + utohexstr(getLDSTAddr())), STT_FUNC, 0, getSize(), *this); - addSyntheticLocal(saver.save("$x"), STT_NOTYPE, 0, 0, *this); + addSyntheticLocal(Saver.save("$x"), STT_NOTYPE, 0, 0, *this); } uint64_t lld::elf::Patch843419Section::getLDSTAddr() const { - return patchee->getVA(patcheeOffset); + return Patchee->getVA(PatcheeOffset); } -void lld::elf::Patch843419Section::writeTo(uint8_t *buf) { +void lld::elf::Patch843419Section::writeTo(uint8_t *Buf) { // Copy the instruction that we will be replacing with a branch in the // Patchee Section. - write32le(buf, read32le(patchee->data().begin() + patcheeOffset)); + write32le(Buf, read32le(Patchee->data().begin() + PatcheeOffset)); // Apply any relocation transferred from the original PatcheeSection. - // For a SyntheticSection Buf already has outSecOff added, but relocateAlloc - // also adds outSecOff so we need to subtract to avoid double counting. - this->relocateAlloc(buf - outSecOff, buf - outSecOff + getSize()); + // For a SyntheticSection Buf already has OutSecOff added, but relocateAlloc + // also adds OutSecOff so we need to subtract to avoid double counting. + this->relocateAlloc(Buf - OutSecOff, Buf - OutSecOff + getSize()); // Return address is the next instruction after the one we have just copied. - uint64_t s = getLDSTAddr() + 4; - uint64_t p = patchSym->getVA() + 4; - target->relocateOne(buf + 4, R_AARCH64_JUMP26, s - p); + uint64_t S = getLDSTAddr() + 4; + uint64_t P = PatchSym->getVA() + 4; + Target->relocateOne(Buf + 4, R_AARCH64_JUMP26, S - P); } void AArch64Err843419Patcher::init() { // The AArch64 ABI permits data in executable sections. We must avoid scanning // this data as if it were instructions to avoid false matches. We use the // mapping symbols in the InputObjects to identify this data, caching the - // results in sectionMap so we don't have to recalculate it each pass. + // results in SectionMap so we don't have to recalculate it each pass. // The ABI Section 4.5.4 Mapping symbols; defines local symbols that describe // half open intervals [Symbol Value, Next Symbol Value) of code and data // within sections. If there is no next symbol then the half open interval is // [Symbol Value, End of section). The type, code or data, is determined by // the mapping symbol name, $x for code, $d for data. - auto isCodeMapSymbol = [](const Symbol *b) { - return b->getName() == "$x" || b->getName().startswith("$x."); + auto IsCodeMapSymbol = [](const Symbol *B) { + return B->getName() == "$x" || B->getName().startswith("$x."); }; - auto isDataMapSymbol = [](const Symbol *b) { - return b->getName() == "$d" || b->getName().startswith("$d."); + auto IsDataMapSymbol = [](const Symbol *B) { + return B->getName() == "$d" || B->getName().startswith("$d."); }; // Collect mapping symbols for every executable InputSection. - for (InputFile *file : objectFiles) { - auto *f = cast>(file); - for (Symbol *b : f->getLocalSymbols()) { - auto *def = dyn_cast(b); - if (!def) + for (InputFile *File : ObjectFiles) { + auto *F = cast>(File); + for (Symbol *B : F->getLocalSymbols()) { + auto *Def = dyn_cast(B); + if (!Def) continue; - if (!isCodeMapSymbol(def) && !isDataMapSymbol(def)) + if (!IsCodeMapSymbol(Def) && !IsDataMapSymbol(Def)) continue; - if (auto *sec = dyn_cast_or_null(def->section)) - if (sec->flags & SHF_EXECINSTR) - sectionMap[sec].push_back(def); + if (auto *Sec = dyn_cast_or_null(Def->Section)) + if (Sec->Flags & SHF_EXECINSTR) + SectionMap[Sec].push_back(Def); } } // For each InputSection make sure the mapping symbols are in sorted in // ascending order and free from consecutive runs of mapping symbols with // the same type. For example we must remove the redundant $d.1 from $x.0 // $d.0 $d.1 $x.1. - for (auto &kv : sectionMap) { - std::vector &mapSyms = kv.second; - if (mapSyms.size() <= 1) + for (auto &KV : SectionMap) { + std::vector &MapSyms = KV.second; + if (MapSyms.size() <= 1) continue; - llvm::stable_sort(mapSyms, [](const Defined *a, const Defined *b) { - return a->value < b->value; + llvm::stable_sort(MapSyms, [](const Defined *A, const Defined *B) { + return A->Value < B->Value; }); - mapSyms.erase( - std::unique(mapSyms.begin(), mapSyms.end(), - [=](const Defined *a, const Defined *b) { - return (isCodeMapSymbol(a) && isCodeMapSymbol(b)) || - (isDataMapSymbol(a) && isDataMapSymbol(b)); + MapSyms.erase( + std::unique(MapSyms.begin(), MapSyms.end(), + [=](const Defined *A, const Defined *B) { + return (IsCodeMapSymbol(A) && IsCodeMapSymbol(B)) || + (IsDataMapSymbol(A) && IsDataMapSymbol(B)); }), - mapSyms.end()); + MapSyms.end()); } - initialized = true; + Initialized = true; } // Insert the PatchSections we have created back into the @@ -483,60 +483,60 @@ void AArch64Err843419Patcher::init() { // executable sections, although we may need to insert them earlier if the // InputSectionDescription is larger than the maximum branch range. void AArch64Err843419Patcher::insertPatches( - InputSectionDescription &isd, std::vector &patches) { - uint64_t isecLimit; - uint64_t prevIsecLimit = isd.sections.front()->outSecOff; - uint64_t patchUpperBound = prevIsecLimit + target->getThunkSectionSpacing(); - uint64_t outSecAddr = isd.sections.front()->getParent()->addr; + InputSectionDescription &ISD, std::vector &Patches) { + uint64_t ISLimit; + uint64_t PrevISLimit = ISD.Sections.front()->OutSecOff; + uint64_t PatchUpperBound = PrevISLimit + Target->getThunkSectionSpacing(); + uint64_t OutSecAddr = ISD.Sections.front()->getParent()->Addr; - // Set the outSecOff of patches to the place where we want to insert them. + // Set the OutSecOff of patches to the place where we want to insert them. // We use a similar strategy to Thunk placement. Place patches roughly // every multiple of maximum branch range. - auto patchIt = patches.begin(); - auto patchEnd = patches.end(); - for (const InputSection *isec : isd.sections) { - isecLimit = isec->outSecOff + isec->getSize(); - if (isecLimit > patchUpperBound) { - while (patchIt != patchEnd) { - if ((*patchIt)->getLDSTAddr() - outSecAddr >= prevIsecLimit) + auto PatchIt = Patches.begin(); + auto PatchEnd = Patches.end(); + for (const InputSection *IS : ISD.Sections) { + ISLimit = IS->OutSecOff + IS->getSize(); + if (ISLimit > PatchUpperBound) { + while (PatchIt != PatchEnd) { + if ((*PatchIt)->getLDSTAddr() - OutSecAddr >= PrevISLimit) break; - (*patchIt)->outSecOff = prevIsecLimit; - ++patchIt; + (*PatchIt)->OutSecOff = PrevISLimit; + ++PatchIt; } - patchUpperBound = prevIsecLimit + target->getThunkSectionSpacing(); + PatchUpperBound = PrevISLimit + Target->getThunkSectionSpacing(); } - prevIsecLimit = isecLimit; + PrevISLimit = ISLimit; } - for (; patchIt != patchEnd; ++patchIt) { - (*patchIt)->outSecOff = isecLimit; + for (; PatchIt != PatchEnd; ++PatchIt) { + (*PatchIt)->OutSecOff = ISLimit; } - // merge all patch sections. We use the outSecOff assigned above to + // merge all patch sections. We use the OutSecOff assigned above to // determine the insertion point. This is ok as we only merge into an // InputSectionDescription once per pass, and at the end of the pass - // assignAddresses() will recalculate all the outSecOff values. - std::vector tmp; - tmp.reserve(isd.sections.size() + patches.size()); - auto mergeCmp = [](const InputSection *a, const InputSection *b) { - if (a->outSecOff < b->outSecOff) + // assignAddresses() will recalculate all the OutSecOff values. + std::vector Tmp; + Tmp.reserve(ISD.Sections.size() + Patches.size()); + auto MergeCmp = [](const InputSection *A, const InputSection *B) { + if (A->OutSecOff < B->OutSecOff) return true; - if (a->outSecOff == b->outSecOff && isa(a) && - !isa(b)) + if (A->OutSecOff == B->OutSecOff && isa(A) && + !isa(B)) return true; return false; }; - std::merge(isd.sections.begin(), isd.sections.end(), patches.begin(), - patches.end(), std::back_inserter(tmp), mergeCmp); - isd.sections = std::move(tmp); + std::merge(ISD.Sections.begin(), ISD.Sections.end(), Patches.begin(), + Patches.end(), std::back_inserter(Tmp), MergeCmp); + ISD.Sections = std::move(Tmp); } -// Given an erratum sequence that starts at address adrpAddr, with an -// instruction that we need to patch at patcheeOffset from the start of +// Given an erratum sequence that starts at address AdrpAddr, with an +// instruction that we need to patch at PatcheeOffset from the start of // InputSection IS, create a Patch843419 Section and add it to the // Patches that we need to insert. -static void implementPatch(uint64_t adrpAddr, uint64_t patcheeOffset, - InputSection *isec, - std::vector &patches) { +static void implementPatch(uint64_t AdrpAddr, uint64_t PatcheeOffset, + InputSection *IS, + std::vector &Patches) { // There may be a relocation at the same offset that we are patching. There // are four cases that we need to consider. // Case 1: R_AARCH64_JUMP26 branch relocation. We have already patched this @@ -551,29 +551,29 @@ static void implementPatch(uint64_t adrpAddr, uint64_t patcheeOffset, // and replace the relocation with a R_AARCH_JUMP26 branch relocation. // Case 4: No relocation. We must create a new R_AARCH64_JUMP26 branch // relocation at the offset. - auto relIt = llvm::find_if(isec->relocations, [=](const Relocation &r) { - return r.offset == patcheeOffset; + auto RelIt = llvm::find_if(IS->Relocations, [=](const Relocation &R) { + return R.Offset == PatcheeOffset; }); - if (relIt != isec->relocations.end() && - (relIt->type == R_AARCH64_JUMP26 || relIt->expr == R_RELAX_TLS_IE_TO_LE)) + if (RelIt != IS->Relocations.end() && + (RelIt->Type == R_AARCH64_JUMP26 || RelIt->Expr == R_RELAX_TLS_IE_TO_LE)) return; log("detected cortex-a53-843419 erratum sequence starting at " + - utohexstr(adrpAddr) + " in unpatched output."); + utohexstr(AdrpAddr) + " in unpatched output."); - auto *ps = make(isec, patcheeOffset); - patches.push_back(ps); + auto *PS = make(IS, PatcheeOffset); + Patches.push_back(PS); - auto makeRelToPatch = [](uint64_t offset, Symbol *patchSym) { - return Relocation{R_PC, R_AARCH64_JUMP26, offset, 0, patchSym}; + auto MakeRelToPatch = [](uint64_t Offset, Symbol *PatchSym) { + return Relocation{R_PC, R_AARCH64_JUMP26, Offset, 0, PatchSym}; }; - if (relIt != isec->relocations.end()) { - ps->relocations.push_back( - {relIt->expr, relIt->type, 0, relIt->addend, relIt->sym}); - *relIt = makeRelToPatch(patcheeOffset, ps->patchSym); + if (RelIt != IS->Relocations.end()) { + PS->Relocations.push_back( + {RelIt->Expr, RelIt->Type, 0, RelIt->Addend, RelIt->Sym}); + *RelIt = MakeRelToPatch(PatcheeOffset, PS->PatchSym); } else - isec->relocations.push_back(makeRelToPatch(patcheeOffset, ps->patchSym)); + IS->Relocations.push_back(MakeRelToPatch(PatcheeOffset, PS->PatchSym)); } // Scan all the instructions in InputSectionDescription, for each instance of @@ -581,40 +581,40 @@ static void implementPatch(uint64_t adrpAddr, uint64_t patcheeOffset, // Patch843419Sections that need to be applied to ISD. std::vector AArch64Err843419Patcher::patchInputSectionDescription( - InputSectionDescription &isd) { - std::vector patches; - for (InputSection *isec : isd.sections) { + InputSectionDescription &ISD) { + std::vector Patches; + for (InputSection *IS : ISD.Sections) { // LLD doesn't use the erratum sequence in SyntheticSections. - if (isa(isec)) + if (isa(IS)) continue; - // Use sectionMap to make sure we only scan code and not inline data. + // Use SectionMap to make sure we only scan code and not inline data. // We have already sorted MapSyms in ascending order and removed consecutive // mapping symbols of the same type. Our range of executable instructions to - // scan is therefore [codeSym->value, dataSym->value) or [codeSym->value, + // scan is therefore [CodeSym->Value, DataSym->Value) or [CodeSym->Value, // section size). - std::vector &mapSyms = sectionMap[isec]; + std::vector &MapSyms = SectionMap[IS]; - auto codeSym = llvm::find_if(mapSyms, [&](const Defined *ms) { - return ms->getName().startswith("$x"); + auto CodeSym = llvm::find_if(MapSyms, [&](const Defined *MS) { + return MS->getName().startswith("$x"); }); - while (codeSym != mapSyms.end()) { - auto dataSym = std::next(codeSym); - uint64_t off = (*codeSym)->value; - uint64_t limit = - (dataSym == mapSyms.end()) ? isec->data().size() : (*dataSym)->value; + while (CodeSym != MapSyms.end()) { + auto DataSym = std::next(CodeSym); + uint64_t Off = (*CodeSym)->Value; + uint64_t Limit = + (DataSym == MapSyms.end()) ? IS->data().size() : (*DataSym)->Value; - while (off < limit) { - uint64_t startAddr = isec->getVA(off); - if (uint64_t patcheeOffset = scanCortexA53Errata843419(isec, off, limit)) - implementPatch(startAddr, patcheeOffset, isec, patches); + while (Off < Limit) { + uint64_t StartAddr = IS->getVA(Off); + if (uint64_t PatcheeOffset = scanCortexA53Errata843419(IS, Off, Limit)) + implementPatch(StartAddr, PatcheeOffset, IS, Patches); } - if (dataSym == mapSyms.end()) + if (DataSym == MapSyms.end()) break; - codeSym = std::next(dataSym); + CodeSym = std::next(DataSym); } } - return patches; + return Patches; } // For each InputSectionDescription make one pass over the executable sections @@ -630,22 +630,22 @@ AArch64Err843419Patcher::patchInputSectionDescription( // Ouptut and Input Sections may have been changed. // Returns false if no patches were required and no changes were made. bool AArch64Err843419Patcher::createFixes() { - if (initialized == false) + if (Initialized == false) init(); - bool addressesChanged = false; - for (OutputSection *os : outputSections) { - if (!(os->flags & SHF_ALLOC) || !(os->flags & SHF_EXECINSTR)) + bool AddressesChanged = false; + for (OutputSection *OS : OutputSections) { + if (!(OS->Flags & SHF_ALLOC) || !(OS->Flags & SHF_EXECINSTR)) continue; - for (BaseCommand *bc : os->sectionCommands) - if (auto *isd = dyn_cast(bc)) { - std::vector patches = - patchInputSectionDescription(*isd); - if (!patches.empty()) { - insertPatches(*isd, patches); - addressesChanged = true; + for (BaseCommand *BC : OS->SectionCommands) + if (auto *ISD = dyn_cast(BC)) { + std::vector Patches = + patchInputSectionDescription(*ISD); + if (!Patches.empty()) { + insertPatches(*ISD, Patches); + AddressesChanged = true; } } } - return addressesChanged; + return AddressesChanged; } diff --git a/lld/ELF/AArch64ErrataFix.h b/lld/ELF/AArch64ErrataFix.h index 0548b58751ff94..48ddb7c833739a 100644 --- a/lld/ELF/AArch64ErrataFix.h +++ b/lld/ELF/AArch64ErrataFix.h @@ -29,19 +29,19 @@ class AArch64Err843419Patcher { private: std::vector - patchInputSectionDescription(InputSectionDescription &isd); + patchInputSectionDescription(InputSectionDescription &ISD); - void insertPatches(InputSectionDescription &isd, - std::vector &patches); + void insertPatches(InputSectionDescription &ISD, + std::vector &Patches); void init(); - // A cache of the mapping symbols defined by the InputSection sorted in order + // A cache of the mapping symbols defined by the InputSecion sorted in order // of ascending value with redundant symbols removed. These describe // the ranges of code and data in an executable InputSection. - std::map> sectionMap; + std::map> SectionMap; - bool initialized = false; + bool Initialized = false; }; } // namespace elf diff --git a/lld/ELF/Arch/AArch64.cpp b/lld/ELF/Arch/AArch64.cpp index 40f0dd65fe7614..0695ffa9db35d6 100644 --- a/lld/ELF/Arch/AArch64.cpp +++ b/lld/ELF/Arch/AArch64.cpp @@ -23,79 +23,59 @@ using namespace lld::elf; // Page(Expr) is the page address of the expression Expr, defined // as (Expr & ~0xFFF). (This applies even if the machine page size // supported by the platform has a different value.) -uint64_t elf::getAArch64Page(uint64_t expr) { - return expr & ~static_cast(0xFFF); +uint64_t elf::getAArch64Page(uint64_t Expr) { + return Expr & ~static_cast(0xFFF); } namespace { class AArch64 : public TargetInfo { public: AArch64(); - RelExpr getRelExpr(RelType type, const Symbol &s, - const uint8_t *loc) const override; - RelType getDynRel(RelType type) const override; - void writeGotPlt(uint8_t *buf, const Symbol &s) const override; - void writePltHeader(uint8_t *buf) const override; - void writePlt(uint8_t *buf, uint64_t gotPltEntryAddr, uint64_t pltEntryAddr, - int32_t index, unsigned relOff) const override; - bool needsThunk(RelExpr expr, RelType type, const InputFile *file, - uint64_t branchAddr, const Symbol &s) const override; + RelExpr getRelExpr(RelType Type, const Symbol &S, + const uint8_t *Loc) const override; + RelType getDynRel(RelType Type) const override; + void writeGotPlt(uint8_t *Buf, const Symbol &S) const override; + void writePltHeader(uint8_t *Buf) const override; + void writePlt(uint8_t *Buf, uint64_t GotPltEntryAddr, uint64_t PltEntryAddr, + int32_t Index, unsigned RelOff) const override; + bool needsThunk(RelExpr Expr, RelType Type, const InputFile *File, + uint64_t BranchAddr, const Symbol &S) const override; uint32_t getThunkSectionSpacing() const override; - bool inBranchRange(RelType type, uint64_t src, uint64_t dst) const override; - bool usesOnlyLowPageBits(RelType type) const override; - void relocateOne(uint8_t *loc, RelType type, uint64_t val) const override; - RelExpr adjustRelaxExpr(RelType type, const uint8_t *data, - RelExpr expr) const override; - void relaxTlsGdToLe(uint8_t *loc, RelType type, uint64_t val) const override; - void relaxTlsGdToIe(uint8_t *loc, RelType type, uint64_t val) const override; - void relaxTlsIeToLe(uint8_t *loc, RelType type, uint64_t val) const override; + bool inBranchRange(RelType Type, uint64_t Src, uint64_t Dst) const override; + bool usesOnlyLowPageBits(RelType Type) const override; + void relocateOne(uint8_t *Loc, RelType Type, uint64_t Val) const override; + RelExpr adjustRelaxExpr(RelType Type, const uint8_t *Data, + RelExpr Expr) const override; + void relaxTlsGdToLe(uint8_t *Loc, RelType Type, uint64_t Val) const override; + void relaxTlsGdToIe(uint8_t *Loc, RelType Type, uint64_t Val) const override; + void relaxTlsIeToLe(uint8_t *Loc, RelType Type, uint64_t Val) const override; }; } // namespace AArch64::AArch64() { - copyRel = R_AARCH64_COPY; - relativeRel = R_AARCH64_RELATIVE; - iRelativeRel = R_AARCH64_IRELATIVE; - gotRel = R_AARCH64_GLOB_DAT; - noneRel = R_AARCH64_NONE; - pltRel = R_AARCH64_JUMP_SLOT; - symbolicRel = R_AARCH64_ABS64; - tlsDescRel = R_AARCH64_TLSDESC; - tlsGotRel = R_AARCH64_TLS_TPREL64; - pltEntrySize = 16; - pltHeaderSize = 32; - defaultMaxPageSize = 65536; + CopyRel = R_AARCH64_COPY; + RelativeRel = R_AARCH64_RELATIVE; + IRelativeRel = R_AARCH64_IRELATIVE; + GotRel = R_AARCH64_GLOB_DAT; + NoneRel = R_AARCH64_NONE; + PltRel = R_AARCH64_JUMP_SLOT; + SymbolicRel = R_AARCH64_ABS64; + TlsDescRel = R_AARCH64_TLSDESC; + TlsGotRel = R_AARCH64_TLS_TPREL64; + PltEntrySize = 16; + PltHeaderSize = 32; + DefaultMaxPageSize = 65536; // Align to the 2 MiB page size (known as a superpage or huge page). // FreeBSD automatically promotes 2 MiB-aligned allocations. - defaultImageBase = 0x200000; + DefaultImageBase = 0x200000; - needsThunks = true; + NeedsThunks = true; } -RelExpr AArch64::getRelExpr(RelType type, const Symbol &s, - const uint8_t *loc) const { - switch (type) { - case R_AARCH64_ABS16: - case R_AARCH64_ABS32: - case R_AARCH64_ABS64: - case R_AARCH64_ADD_ABS_LO12_NC: - case R_AARCH64_LDST128_ABS_LO12_NC: - case R_AARCH64_LDST16_ABS_LO12_NC: - case R_AARCH64_LDST32_ABS_LO12_NC: - case R_AARCH64_LDST64_ABS_LO12_NC: - case R_AARCH64_LDST8_ABS_LO12_NC: - case R_AARCH64_MOVW_SABS_G0: - case R_AARCH64_MOVW_SABS_G1: - case R_AARCH64_MOVW_SABS_G2: - case R_AARCH64_MOVW_UABS_G0: - case R_AARCH64_MOVW_UABS_G0_NC: - case R_AARCH64_MOVW_UABS_G1: - case R_AARCH64_MOVW_UABS_G1_NC: - case R_AARCH64_MOVW_UABS_G2: - case R_AARCH64_MOVW_UABS_G2_NC: - case R_AARCH64_MOVW_UABS_G3: - return R_ABS; +RelExpr AArch64::getRelExpr(RelType Type, const Symbol &S, + const uint8_t *Loc) const { + switch (Type) { case R_AARCH64_TLSDESC_ADR_PAGE21: return R_AARCH64_TLSDESC_PAGE; case R_AARCH64_TLSDESC_LD64_LO12: @@ -110,11 +90,6 @@ RelExpr AArch64::getRelExpr(RelType type, const Symbol &s, case R_AARCH64_TLSLE_LDST32_TPREL_LO12_NC: case R_AARCH64_TLSLE_LDST64_TPREL_LO12_NC: case R_AARCH64_TLSLE_LDST128_TPREL_LO12_NC: - case R_AARCH64_TLSLE_MOVW_TPREL_G0: - case R_AARCH64_TLSLE_MOVW_TPREL_G0_NC: - case R_AARCH64_TLSLE_MOVW_TPREL_G1: - case R_AARCH64_TLSLE_MOVW_TPREL_G1_NC: - case R_AARCH64_TLSLE_MOVW_TPREL_G2: return R_TLS; case R_AARCH64_CALL26: case R_AARCH64_CONDBR19: @@ -126,16 +101,8 @@ RelExpr AArch64::getRelExpr(RelType type, const Symbol &s, case R_AARCH64_PREL64: case R_AARCH64_ADR_PREL_LO21: case R_AARCH64_LD_PREL_LO19: - case R_AARCH64_MOVW_PREL_G0: - case R_AARCH64_MOVW_PREL_G0_NC: - case R_AARCH64_MOVW_PREL_G1: - case R_AARCH64_MOVW_PREL_G1_NC: - case R_AARCH64_MOVW_PREL_G2: - case R_AARCH64_MOVW_PREL_G2_NC: - case R_AARCH64_MOVW_PREL_G3: return R_PC; case R_AARCH64_ADR_PREL_PG_HI21: - case R_AARCH64_ADR_PREL_PG_HI21_NC: return R_AARCH64_PAGE_PC; case R_AARCH64_LD64_GOT_LO12_NC: case R_AARCH64_TLSIE_LD64_GOTTPREL_LO12_NC: @@ -146,24 +113,22 @@ RelExpr AArch64::getRelExpr(RelType type, const Symbol &s, case R_AARCH64_NONE: return R_NONE; default: - error(getErrorLocation(loc) + "unknown relocation (" + Twine(type) + - ") against symbol " + toString(s)); - return R_NONE; + return R_ABS; } } -RelExpr AArch64::adjustRelaxExpr(RelType type, const uint8_t *data, - RelExpr expr) const { - if (expr == R_RELAX_TLS_GD_TO_IE) { - if (type == R_AARCH64_TLSDESC_ADR_PAGE21) +RelExpr AArch64::adjustRelaxExpr(RelType Type, const uint8_t *Data, + RelExpr Expr) const { + if (Expr == R_RELAX_TLS_GD_TO_IE) { + if (Type == R_AARCH64_TLSDESC_ADR_PAGE21) return R_AARCH64_RELAX_TLS_GD_TO_IE_PAGE_PC; return R_RELAX_TLS_GD_TO_IE_ABS; } - return expr; + return Expr; } -bool AArch64::usesOnlyLowPageBits(RelType type) const { - switch (type) { +bool AArch64::usesOnlyLowPageBits(RelType Type) const { + switch (Type) { default: return false; case R_AARCH64_ADD_ABS_LO12_NC: @@ -180,18 +145,18 @@ bool AArch64::usesOnlyLowPageBits(RelType type) const { } } -RelType AArch64::getDynRel(RelType type) const { - if (type == R_AARCH64_ABS64) - return type; +RelType AArch64::getDynRel(RelType Type) const { + if (Type == R_AARCH64_ABS64) + return Type; return R_AARCH64_NONE; } -void AArch64::writeGotPlt(uint8_t *buf, const Symbol &) const { - write64le(buf, in.plt->getVA()); +void AArch64::writeGotPlt(uint8_t *Buf, const Symbol &) const { + write64le(Buf, In.Plt->getVA()); } -void AArch64::writePltHeader(uint8_t *buf) const { - const uint8_t pltData[] = { +void AArch64::writePltHeader(uint8_t *Buf) const { + const uint8_t PltData[] = { 0xf0, 0x7b, 0xbf, 0xa9, // stp x16, x30, [sp,#-16]! 0x10, 0x00, 0x00, 0x90, // adrp x16, Page(&(.plt.got[2])) 0x11, 0x02, 0x40, 0xf9, // ldr x17, [x16, Offset(&(.plt.got[2]))] @@ -201,42 +166,42 @@ void AArch64::writePltHeader(uint8_t *buf) const { 0x1f, 0x20, 0x03, 0xd5, // nop 0x1f, 0x20, 0x03, 0xd5 // nop }; - memcpy(buf, pltData, sizeof(pltData)); - - uint64_t got = in.gotPlt->getVA(); - uint64_t plt = in.plt->getVA(); - relocateOne(buf + 4, R_AARCH64_ADR_PREL_PG_HI21, - getAArch64Page(got + 16) - getAArch64Page(plt + 4)); - relocateOne(buf + 8, R_AARCH64_LDST64_ABS_LO12_NC, got + 16); - relocateOne(buf + 12, R_AARCH64_ADD_ABS_LO12_NC, got + 16); + memcpy(Buf, PltData, sizeof(PltData)); + + uint64_t Got = In.GotPlt->getVA(); + uint64_t Plt = In.Plt->getVA(); + relocateOne(Buf + 4, R_AARCH64_ADR_PREL_PG_HI21, + getAArch64Page(Got + 16) - getAArch64Page(Plt + 4)); + relocateOne(Buf + 8, R_AARCH64_LDST64_ABS_LO12_NC, Got + 16); + relocateOne(Buf + 12, R_AARCH64_ADD_ABS_LO12_NC, Got + 16); } -void AArch64::writePlt(uint8_t *buf, uint64_t gotPltEntryAddr, - uint64_t pltEntryAddr, int32_t index, - unsigned relOff) const { - const uint8_t inst[] = { +void AArch64::writePlt(uint8_t *Buf, uint64_t GotPltEntryAddr, + uint64_t PltEntryAddr, int32_t Index, + unsigned RelOff) const { + const uint8_t Inst[] = { 0x10, 0x00, 0x00, 0x90, // adrp x16, Page(&(.plt.got[n])) 0x11, 0x02, 0x40, 0xf9, // ldr x17, [x16, Offset(&(.plt.got[n]))] 0x10, 0x02, 0x00, 0x91, // add x16, x16, Offset(&(.plt.got[n])) 0x20, 0x02, 0x1f, 0xd6 // br x17 }; - memcpy(buf, inst, sizeof(inst)); + memcpy(Buf, Inst, sizeof(Inst)); - relocateOne(buf, R_AARCH64_ADR_PREL_PG_HI21, - getAArch64Page(gotPltEntryAddr) - getAArch64Page(pltEntryAddr)); - relocateOne(buf + 4, R_AARCH64_LDST64_ABS_LO12_NC, gotPltEntryAddr); - relocateOne(buf + 8, R_AARCH64_ADD_ABS_LO12_NC, gotPltEntryAddr); + relocateOne(Buf, R_AARCH64_ADR_PREL_PG_HI21, + getAArch64Page(GotPltEntryAddr) - getAArch64Page(PltEntryAddr)); + relocateOne(Buf + 4, R_AARCH64_LDST64_ABS_LO12_NC, GotPltEntryAddr); + relocateOne(Buf + 8, R_AARCH64_ADD_ABS_LO12_NC, GotPltEntryAddr); } -bool AArch64::needsThunk(RelExpr expr, RelType type, const InputFile *file, - uint64_t branchAddr, const Symbol &s) const { +bool AArch64::needsThunk(RelExpr Expr, RelType Type, const InputFile *File, + uint64_t BranchAddr, const Symbol &S) const { // ELF for the ARM 64-bit architecture, section Call and Jump relocations // only permits range extension thunks for R_AARCH64_CALL26 and // R_AARCH64_JUMP26 relocation types. - if (type != R_AARCH64_CALL26 && type != R_AARCH64_JUMP26) + if (Type != R_AARCH64_CALL26 && Type != R_AARCH64_JUMP26) return false; - uint64_t dst = (expr == R_PLT_PC) ? s.getPltVA() : s.getVA(); - return !inBranchRange(type, branchAddr, dst); + uint64_t Dst = (Expr == R_PLT_PC) ? S.getPltVA() : S.getVA(); + return !inBranchRange(Type, BranchAddr, Dst); } uint32_t AArch64::getThunkSectionSpacing() const { @@ -246,92 +211,70 @@ uint32_t AArch64::getThunkSectionSpacing() const { return (128 * 1024 * 1024) - 0x30000; } -bool AArch64::inBranchRange(RelType type, uint64_t src, uint64_t dst) const { - if (type != R_AARCH64_CALL26 && type != R_AARCH64_JUMP26) +bool AArch64::inBranchRange(RelType Type, uint64_t Src, uint64_t Dst) const { + if (Type != R_AARCH64_CALL26 && Type != R_AARCH64_JUMP26) return true; // The AArch64 call and unconditional branch instructions have a range of // +/- 128 MiB. - uint64_t range = 128 * 1024 * 1024; - if (dst > src) { + uint64_t Range = 128 * 1024 * 1024; + if (Dst > Src) { // Immediate of branch is signed. - range -= 4; - return dst - src <= range; + Range -= 4; + return Dst - Src <= Range; } - return src - dst <= range; + return Src - Dst <= Range; } -static void write32AArch64Addr(uint8_t *l, uint64_t imm) { - uint32_t immLo = (imm & 0x3) << 29; - uint32_t immHi = (imm & 0x1FFFFC) << 3; - uint64_t mask = (0x3 << 29) | (0x1FFFFC << 3); - write32le(l, (read32le(l) & ~mask) | immLo | immHi); +static void write32AArch64Addr(uint8_t *L, uint64_t Imm) { + uint32_t ImmLo = (Imm & 0x3) << 29; + uint32_t ImmHi = (Imm & 0x1FFFFC) << 3; + uint64_t Mask = (0x3 << 29) | (0x1FFFFC << 3); + write32le(L, (read32le(L) & ~Mask) | ImmLo | ImmHi); } // Return the bits [Start, End] from Val shifted Start bits. // For instance, getBits(0xF0, 4, 8) returns 0xF. -static uint64_t getBits(uint64_t val, int start, int end) { - uint64_t mask = ((uint64_t)1 << (end + 1 - start)) - 1; - return (val >> start) & mask; +static uint64_t getBits(uint64_t Val, int Start, int End) { + uint64_t Mask = ((uint64_t)1 << (End + 1 - Start)) - 1; + return (Val >> Start) & Mask; } -static void or32le(uint8_t *p, int32_t v) { write32le(p, read32le(p) | v); } +static void or32le(uint8_t *P, int32_t V) { write32le(P, read32le(P) | V); } // Update the immediate field in a AARCH64 ldr, str, and add instruction. -static void or32AArch64Imm(uint8_t *l, uint64_t imm) { - or32le(l, (imm & 0xFFF) << 10); -} - -// Update the immediate field in an AArch64 movk, movn or movz instruction -// for a signed relocation, and update the opcode of a movn or movz instruction -// to match the sign of the operand. -static void writeSMovWImm(uint8_t *loc, uint32_t imm) { - uint32_t inst = read32le(loc); - // Opcode field is bits 30, 29, with 10 = movz, 00 = movn and 11 = movk. - if (!(inst & (1 << 29))) { - // movn or movz. - if (imm & 0x10000) { - // Change opcode to movn, which takes an inverted operand. - imm ^= 0xFFFF; - inst &= ~(1 << 30); - } else { - // Change opcode to movz. - inst |= 1 << 30; - } - } - write32le(loc, inst | ((imm & 0xFFFF) << 5)); +static void or32AArch64Imm(uint8_t *L, uint64_t Imm) { + or32le(L, (Imm & 0xFFF) << 10); } -void AArch64::relocateOne(uint8_t *loc, RelType type, uint64_t val) const { - switch (type) { +void AArch64::relocateOne(uint8_t *Loc, RelType Type, uint64_t Val) const { + switch (Type) { case R_AARCH64_ABS16: case R_AARCH64_PREL16: - checkIntUInt(loc, val, 16, type); - write16le(loc, val); + checkIntUInt(Loc, Val, 16, Type); + write16le(Loc, Val); break; case R_AARCH64_ABS32: case R_AARCH64_PREL32: - checkIntUInt(loc, val, 32, type); - write32le(loc, val); + checkIntUInt(Loc, Val, 32, Type); + write32le(Loc, Val); break; case R_AARCH64_ABS64: case R_AARCH64_PREL64: - write64le(loc, val); + write64le(Loc, Val); break; case R_AARCH64_ADD_ABS_LO12_NC: - or32AArch64Imm(loc, val); + or32AArch64Imm(Loc, Val); break; case R_AARCH64_ADR_GOT_PAGE: case R_AARCH64_ADR_PREL_PG_HI21: case R_AARCH64_TLSIE_ADR_GOTTPREL_PAGE21: case R_AARCH64_TLSDESC_ADR_PAGE21: - checkInt(loc, val, 33, type); - LLVM_FALLTHROUGH; - case R_AARCH64_ADR_PREL_PG_HI21_NC: - write32AArch64Addr(loc, val >> 12); + checkInt(Loc, Val, 33, Type); + write32AArch64Addr(Loc, Val >> 12); break; case R_AARCH64_ADR_PREL_LO21: - checkInt(loc, val, 21, type); - write32AArch64Addr(loc, val); + checkInt(Loc, Val, 21, Type); + write32AArch64Addr(Loc, Val); break; case R_AARCH64_JUMP26: // Normally we would just write the bits of the immediate field, however @@ -341,113 +284,75 @@ void AArch64::relocateOne(uint8_t *loc, RelType type, uint64_t val) const { // opcode and the immediate (0 001 | 01 imm26) we can do this // transformation by placing a R_AARCH64_JUMP26 relocation at the offset of // the instruction we want to patch. - write32le(loc, 0x14000000); + write32le(Loc, 0x14000000); LLVM_FALLTHROUGH; case R_AARCH64_CALL26: - checkInt(loc, val, 28, type); - or32le(loc, (val & 0x0FFFFFFC) >> 2); + checkInt(Loc, Val, 28, Type); + or32le(Loc, (Val & 0x0FFFFFFC) >> 2); break; case R_AARCH64_CONDBR19: case R_AARCH64_LD_PREL_LO19: - checkAlignment(loc, val, 4, type); - checkInt(loc, val, 21, type); - or32le(loc, (val & 0x1FFFFC) << 3); + checkAlignment(Loc, Val, 4, Type); + checkInt(Loc, Val, 21, Type); + or32le(Loc, (Val & 0x1FFFFC) << 3); break; case R_AARCH64_LDST8_ABS_LO12_NC: case R_AARCH64_TLSLE_LDST8_TPREL_LO12_NC: - or32AArch64Imm(loc, getBits(val, 0, 11)); + or32AArch64Imm(Loc, getBits(Val, 0, 11)); break; case R_AARCH64_LDST16_ABS_LO12_NC: case R_AARCH64_TLSLE_LDST16_TPREL_LO12_NC: - checkAlignment(loc, val, 2, type); - or32AArch64Imm(loc, getBits(val, 1, 11)); + checkAlignment(Loc, Val, 2, Type); + or32AArch64Imm(Loc, getBits(Val, 1, 11)); break; case R_AARCH64_LDST32_ABS_LO12_NC: case R_AARCH64_TLSLE_LDST32_TPREL_LO12_NC: - checkAlignment(loc, val, 4, type); - or32AArch64Imm(loc, getBits(val, 2, 11)); + checkAlignment(Loc, Val, 4, Type); + or32AArch64Imm(Loc, getBits(Val, 2, 11)); break; case R_AARCH64_LDST64_ABS_LO12_NC: case R_AARCH64_LD64_GOT_LO12_NC: case R_AARCH64_TLSIE_LD64_GOTTPREL_LO12_NC: case R_AARCH64_TLSLE_LDST64_TPREL_LO12_NC: case R_AARCH64_TLSDESC_LD64_LO12: - checkAlignment(loc, val, 8, type); - or32AArch64Imm(loc, getBits(val, 3, 11)); + checkAlignment(Loc, Val, 8, Type); + or32AArch64Imm(Loc, getBits(Val, 3, 11)); break; case R_AARCH64_LDST128_ABS_LO12_NC: case R_AARCH64_TLSLE_LDST128_TPREL_LO12_NC: - checkAlignment(loc, val, 16, type); - or32AArch64Imm(loc, getBits(val, 4, 11)); + checkAlignment(Loc, Val, 16, Type); + or32AArch64Imm(Loc, getBits(Val, 4, 11)); break; - case R_AARCH64_MOVW_UABS_G0: - checkUInt(loc, val, 16, type); - LLVM_FALLTHROUGH; case R_AARCH64_MOVW_UABS_G0_NC: - or32le(loc, (val & 0xFFFF) << 5); + or32le(Loc, (Val & 0xFFFF) << 5); break; - case R_AARCH64_MOVW_UABS_G1: - checkUInt(loc, val, 32, type); - LLVM_FALLTHROUGH; case R_AARCH64_MOVW_UABS_G1_NC: - or32le(loc, (val & 0xFFFF0000) >> 11); + or32le(Loc, (Val & 0xFFFF0000) >> 11); break; - case R_AARCH64_MOVW_UABS_G2: - checkUInt(loc, val, 48, type); - LLVM_FALLTHROUGH; case R_AARCH64_MOVW_UABS_G2_NC: - or32le(loc, (val & 0xFFFF00000000) >> 27); + or32le(Loc, (Val & 0xFFFF00000000) >> 27); break; case R_AARCH64_MOVW_UABS_G3: - or32le(loc, (val & 0xFFFF000000000000) >> 43); - break; - case R_AARCH64_MOVW_PREL_G0: - case R_AARCH64_MOVW_SABS_G0: - case R_AARCH64_TLSLE_MOVW_TPREL_G0: - checkInt(loc, val, 17, type); - LLVM_FALLTHROUGH; - case R_AARCH64_MOVW_PREL_G0_NC: - case R_AARCH64_TLSLE_MOVW_TPREL_G0_NC: - writeSMovWImm(loc, val); - break; - case R_AARCH64_MOVW_PREL_G1: - case R_AARCH64_MOVW_SABS_G1: - case R_AARCH64_TLSLE_MOVW_TPREL_G1: - checkInt(loc, val, 33, type); - LLVM_FALLTHROUGH; - case R_AARCH64_MOVW_PREL_G1_NC: - case R_AARCH64_TLSLE_MOVW_TPREL_G1_NC: - writeSMovWImm(loc, val >> 16); - break; - case R_AARCH64_MOVW_PREL_G2: - case R_AARCH64_MOVW_SABS_G2: - case R_AARCH64_TLSLE_MOVW_TPREL_G2: - checkInt(loc, val, 49, type); - LLVM_FALLTHROUGH; - case R_AARCH64_MOVW_PREL_G2_NC: - writeSMovWImm(loc, val >> 32); - break; - case R_AARCH64_MOVW_PREL_G3: - writeSMovWImm(loc, val >> 48); + or32le(Loc, (Val & 0xFFFF000000000000) >> 43); break; case R_AARCH64_TSTBR14: - checkInt(loc, val, 16, type); - or32le(loc, (val & 0xFFFC) << 3); + checkInt(Loc, Val, 16, Type); + or32le(Loc, (Val & 0xFFFC) << 3); break; case R_AARCH64_TLSLE_ADD_TPREL_HI12: - checkUInt(loc, val, 24, type); - or32AArch64Imm(loc, val >> 12); + checkUInt(Loc, Val, 24, Type); + or32AArch64Imm(Loc, Val >> 12); break; case R_AARCH64_TLSLE_ADD_TPREL_LO12_NC: case R_AARCH64_TLSDESC_ADD_LO12: - or32AArch64Imm(loc, val); + or32AArch64Imm(Loc, Val); break; default: - llvm_unreachable("unknown relocation"); + error(getErrorLocation(Loc) + "unrecognized relocation " + toString(Type)); } } -void AArch64::relaxTlsGdToLe(uint8_t *loc, RelType type, uint64_t val) const { +void AArch64::relaxTlsGdToLe(uint8_t *Loc, RelType Type, uint64_t Val) const { // TLSDESC Global-Dynamic relocation are in the form: // adrp x0, :tlsdesc:v [R_AARCH64_TLSDESC_ADR_PAGE21] // ldr x1, [x0, #:tlsdesc_lo12:v [R_AARCH64_TLSDESC_LD64_LO12] @@ -459,25 +364,25 @@ void AArch64::relaxTlsGdToLe(uint8_t *loc, RelType type, uint64_t val) const { // movk x0, #0x10 // nop // nop - checkUInt(loc, val, 32, type); + checkUInt(Loc, Val, 32, Type); - switch (type) { + switch (Type) { case R_AARCH64_TLSDESC_ADD_LO12: case R_AARCH64_TLSDESC_CALL: - write32le(loc, 0xd503201f); // nop + write32le(Loc, 0xd503201f); // nop return; case R_AARCH64_TLSDESC_ADR_PAGE21: - write32le(loc, 0xd2a00000 | (((val >> 16) & 0xffff) << 5)); // movz + write32le(Loc, 0xd2a00000 | (((Val >> 16) & 0xffff) << 5)); // movz return; case R_AARCH64_TLSDESC_LD64_LO12: - write32le(loc, 0xf2800000 | ((val & 0xffff) << 5)); // movk + write32le(Loc, 0xf2800000 | ((Val & 0xffff) << 5)); // movk return; default: llvm_unreachable("unsupported relocation for TLS GD to LE relaxation"); } } -void AArch64::relaxTlsGdToIe(uint8_t *loc, RelType type, uint64_t val) const { +void AArch64::relaxTlsGdToIe(uint8_t *Loc, RelType Type, uint64_t Val) const { // TLSDESC Global-Dynamic relocation are in the form: // adrp x0, :tlsdesc:v [R_AARCH64_TLSDESC_ADR_PAGE21] // ldr x1, [x0, #:tlsdesc_lo12:v [R_AARCH64_TLSDESC_LD64_LO12] @@ -490,37 +395,37 @@ void AArch64::relaxTlsGdToIe(uint8_t *loc, RelType type, uint64_t val) const { // nop // nop - switch (type) { + switch (Type) { case R_AARCH64_TLSDESC_ADD_LO12: case R_AARCH64_TLSDESC_CALL: - write32le(loc, 0xd503201f); // nop + write32le(Loc, 0xd503201f); // nop break; case R_AARCH64_TLSDESC_ADR_PAGE21: - write32le(loc, 0x90000000); // adrp - relocateOne(loc, R_AARCH64_TLSIE_ADR_GOTTPREL_PAGE21, val); + write32le(Loc, 0x90000000); // adrp + relocateOne(Loc, R_AARCH64_TLSIE_ADR_GOTTPREL_PAGE21, Val); break; case R_AARCH64_TLSDESC_LD64_LO12: - write32le(loc, 0xf9400000); // ldr - relocateOne(loc, R_AARCH64_TLSIE_LD64_GOTTPREL_LO12_NC, val); + write32le(Loc, 0xf9400000); // ldr + relocateOne(Loc, R_AARCH64_TLSIE_LD64_GOTTPREL_LO12_NC, Val); break; default: llvm_unreachable("unsupported relocation for TLS GD to LE relaxation"); } } -void AArch64::relaxTlsIeToLe(uint8_t *loc, RelType type, uint64_t val) const { - checkUInt(loc, val, 32, type); +void AArch64::relaxTlsIeToLe(uint8_t *Loc, RelType Type, uint64_t Val) const { + checkUInt(Loc, Val, 32, Type); - if (type == R_AARCH64_TLSIE_ADR_GOTTPREL_PAGE21) { + if (Type == R_AARCH64_TLSIE_ADR_GOTTPREL_PAGE21) { // Generate MOVZ. - uint32_t regNo = read32le(loc) & 0x1f; - write32le(loc, (0xd2a00000 | regNo) | (((val >> 16) & 0xffff) << 5)); + uint32_t RegNo = read32le(Loc) & 0x1f; + write32le(Loc, (0xd2a00000 | RegNo) | (((Val >> 16) & 0xffff) << 5)); return; } - if (type == R_AARCH64_TLSIE_LD64_GOTTPREL_LO12_NC) { + if (Type == R_AARCH64_TLSIE_LD64_GOTTPREL_LO12_NC) { // Generate MOVK. - uint32_t regNo = read32le(loc) & 0x1f; - write32le(loc, (0xf2800000 | regNo) | ((val & 0xffff) << 5)); + uint32_t RegNo = read32le(Loc) & 0x1f; + write32le(Loc, (0xf2800000 | RegNo) | ((Val & 0xffff) << 5)); return; } llvm_unreachable("invalid relocation for TLS IE to LE relaxation"); @@ -565,19 +470,19 @@ namespace { class AArch64BtiPac final : public AArch64 { public: AArch64BtiPac(); - void writePltHeader(uint8_t *buf) const override; - void writePlt(uint8_t *buf, uint64_t gotPltEntryAddr, uint64_t pltEntryAddr, - int32_t index, unsigned relOff) const override; + void writePltHeader(uint8_t *Buf) const override; + void writePlt(uint8_t *Buf, uint64_t GotPltEntryAddr, uint64_t PltEntryAddr, + int32_t Index, unsigned RelOff) const override; private: - bool btiHeader; // bti instruction needed in PLT Header - bool btiEntry; // bti instruction needed in PLT Entry - bool pacEntry; // autia1716 instruction needed in PLT Entry + bool BtiHeader; // bti instruction needed in PLT Header + bool BtiEntry; // bti instruction needed in PLT Entry + bool PacEntry; // autia1716 instruction needed in PLT Entry }; } // namespace AArch64BtiPac::AArch64BtiPac() { - btiHeader = (config->andFeatures & GNU_PROPERTY_AARCH64_FEATURE_1_BTI); + BtiHeader = (Config->AndFeatures & GNU_PROPERTY_AARCH64_FEATURE_1_BTI); // A BTI (Branch Target Indicator) Plt Entry is only required if the // address of the PLT entry can be taken by the program, which permits an // indirect jump to the PLT entry. This can happen when the address @@ -585,16 +490,16 @@ AArch64BtiPac::AArch64BtiPac() { // the function in an executable being taken by a shared library. // FIXME: There is a potential optimization to omit the BTI if we detect // that the address of the PLT entry isn't taken. - btiEntry = btiHeader && !config->shared; - pacEntry = (config->andFeatures & GNU_PROPERTY_AARCH64_FEATURE_1_PAC); + BtiEntry = BtiHeader && !Config->Shared; + PacEntry = (Config->AndFeatures & GNU_PROPERTY_AARCH64_FEATURE_1_PAC); - if (btiEntry || pacEntry) - pltEntrySize = 24; + if (BtiEntry || PacEntry) + PltEntrySize = 24; } -void AArch64BtiPac::writePltHeader(uint8_t *buf) const { - const uint8_t btiData[] = { 0x5f, 0x24, 0x03, 0xd5 }; // bti c - const uint8_t pltData[] = { +void AArch64BtiPac::writePltHeader(uint8_t *Buf) const { + const uint8_t BtiData[] = { 0x5f, 0x24, 0x03, 0xd5 }; // bti c + const uint8_t PltData[] = { 0xf0, 0x7b, 0xbf, 0xa9, // stp x16, x30, [sp,#-16]! 0x10, 0x00, 0x00, 0x90, // adrp x16, Page(&(.plt.got[2])) 0x11, 0x02, 0x40, 0xf9, // ldr x17, [x16, Offset(&(.plt.got[2]))] @@ -603,80 +508,80 @@ void AArch64BtiPac::writePltHeader(uint8_t *buf) const { 0x1f, 0x20, 0x03, 0xd5, // nop 0x1f, 0x20, 0x03, 0xd5 // nop }; - const uint8_t nopData[] = { 0x1f, 0x20, 0x03, 0xd5 }; // nop + const uint8_t NopData[] = { 0x1f, 0x20, 0x03, 0xd5 }; // nop - uint64_t got = in.gotPlt->getVA(); - uint64_t plt = in.plt->getVA(); + uint64_t Got = In.GotPlt->getVA(); + uint64_t Plt = In.Plt->getVA(); - if (btiHeader) { - // PltHeader is called indirectly by plt[N]. Prefix pltData with a BTI C + if (BtiHeader) { + // PltHeader is called indirectly by Plt[N]. Prefix PltData with a BTI C // instruction. - memcpy(buf, btiData, sizeof(btiData)); - buf += sizeof(btiData); - plt += sizeof(btiData); + memcpy(Buf, BtiData, sizeof(BtiData)); + Buf += sizeof(BtiData); + Plt += sizeof(BtiData); } - memcpy(buf, pltData, sizeof(pltData)); + memcpy(Buf, PltData, sizeof(PltData)); - relocateOne(buf + 4, R_AARCH64_ADR_PREL_PG_HI21, - getAArch64Page(got + 16) - getAArch64Page(plt + 8)); - relocateOne(buf + 8, R_AARCH64_LDST64_ABS_LO12_NC, got + 16); - relocateOne(buf + 12, R_AARCH64_ADD_ABS_LO12_NC, got + 16); - if (!btiHeader) + relocateOne(Buf + 4, R_AARCH64_ADR_PREL_PG_HI21, + getAArch64Page(Got + 16) - getAArch64Page(Plt + 8)); + relocateOne(Buf + 8, R_AARCH64_LDST64_ABS_LO12_NC, Got + 16); + relocateOne(Buf + 12, R_AARCH64_ADD_ABS_LO12_NC, Got + 16); + if (!BtiHeader) // We didn't add the BTI c instruction so round out size with NOP. - memcpy(buf + sizeof(pltData), nopData, sizeof(nopData)); + memcpy(Buf + sizeof(PltData), NopData, sizeof(NopData)); } -void AArch64BtiPac::writePlt(uint8_t *buf, uint64_t gotPltEntryAddr, - uint64_t pltEntryAddr, int32_t index, - unsigned relOff) const { +void AArch64BtiPac::writePlt(uint8_t *Buf, uint64_t GotPltEntryAddr, + uint64_t PltEntryAddr, int32_t Index, + unsigned RelOff) const { // The PLT entry is of the form: - // [btiData] addrInst (pacBr | stdBr) [nopData] - const uint8_t btiData[] = { 0x5f, 0x24, 0x03, 0xd5 }; // bti c - const uint8_t addrInst[] = { + // [BtiData] AddrInst (PacBr | StdBr) [NopData] + const uint8_t BtiData[] = { 0x5f, 0x24, 0x03, 0xd5 }; // bti c + const uint8_t AddrInst[] = { 0x10, 0x00, 0x00, 0x90, // adrp x16, Page(&(.plt.got[n])) 0x11, 0x02, 0x40, 0xf9, // ldr x17, [x16, Offset(&(.plt.got[n]))] 0x10, 0x02, 0x00, 0x91 // add x16, x16, Offset(&(.plt.got[n])) }; - const uint8_t pacBr[] = { + const uint8_t PacBr[] = { 0x9f, 0x21, 0x03, 0xd5, // autia1716 0x20, 0x02, 0x1f, 0xd6 // br x17 }; - const uint8_t stdBr[] = { + const uint8_t StdBr[] = { 0x20, 0x02, 0x1f, 0xd6, // br x17 0x1f, 0x20, 0x03, 0xd5 // nop }; - const uint8_t nopData[] = { 0x1f, 0x20, 0x03, 0xd5 }; // nop + const uint8_t NopData[] = { 0x1f, 0x20, 0x03, 0xd5 }; // nop - if (btiEntry) { - memcpy(buf, btiData, sizeof(btiData)); - buf += sizeof(btiData); - pltEntryAddr += sizeof(btiData); + if (BtiEntry) { + memcpy(Buf, BtiData, sizeof(BtiData)); + Buf += sizeof(BtiData); + PltEntryAddr += sizeof(BtiData); } - memcpy(buf, addrInst, sizeof(addrInst)); - relocateOne(buf, R_AARCH64_ADR_PREL_PG_HI21, - getAArch64Page(gotPltEntryAddr) - - getAArch64Page(pltEntryAddr)); - relocateOne(buf + 4, R_AARCH64_LDST64_ABS_LO12_NC, gotPltEntryAddr); - relocateOne(buf + 8, R_AARCH64_ADD_ABS_LO12_NC, gotPltEntryAddr); + memcpy(Buf, AddrInst, sizeof(AddrInst)); + relocateOne(Buf, R_AARCH64_ADR_PREL_PG_HI21, + getAArch64Page(GotPltEntryAddr) - + getAArch64Page(PltEntryAddr)); + relocateOne(Buf + 4, R_AARCH64_LDST64_ABS_LO12_NC, GotPltEntryAddr); + relocateOne(Buf + 8, R_AARCH64_ADD_ABS_LO12_NC, GotPltEntryAddr); - if (pacEntry) - memcpy(buf + sizeof(addrInst), pacBr, sizeof(pacBr)); + if (PacEntry) + memcpy(Buf + sizeof(AddrInst), PacBr, sizeof(PacBr)); else - memcpy(buf + sizeof(addrInst), stdBr, sizeof(stdBr)); - if (!btiEntry) + memcpy(Buf + sizeof(AddrInst), StdBr, sizeof(StdBr)); + if (!BtiEntry) // We didn't add the BTI c instruction so round out size with NOP. - memcpy(buf + sizeof(addrInst) + sizeof(stdBr), nopData, sizeof(nopData)); + memcpy(Buf + sizeof(AddrInst) + sizeof(StdBr), NopData, sizeof(NopData)); } static TargetInfo *getTargetInfo() { - if (config->andFeatures & (GNU_PROPERTY_AARCH64_FEATURE_1_BTI | + if (Config->AndFeatures & (GNU_PROPERTY_AARCH64_FEATURE_1_BTI | GNU_PROPERTY_AARCH64_FEATURE_1_PAC)) { - static AArch64BtiPac t; - return &t; + static AArch64BtiPac T; + return &T; } - static AArch64 t; - return &t; + static AArch64 T; + return &T; } TargetInfo *elf::getAArch64TargetInfo() { return getTargetInfo(); } diff --git a/lld/ELF/Arch/AMDGPU.cpp b/lld/ELF/Arch/AMDGPU.cpp index f2e32ca0996d56..4a9c9ab6c88306 100644 --- a/lld/ELF/Arch/AMDGPU.cpp +++ b/lld/ELF/Arch/AMDGPU.cpp @@ -25,63 +25,63 @@ class AMDGPU final : public TargetInfo { public: AMDGPU(); uint32_t calcEFlags() const override; - void relocateOne(uint8_t *loc, RelType type, uint64_t val) const override; - RelExpr getRelExpr(RelType type, const Symbol &s, - const uint8_t *loc) const override; - RelType getDynRel(RelType type) const override; + void relocateOne(uint8_t *Loc, RelType Type, uint64_t Val) const override; + RelExpr getRelExpr(RelType Type, const Symbol &S, + const uint8_t *Loc) const override; + RelType getDynRel(RelType Type) const override; }; } // namespace AMDGPU::AMDGPU() { - relativeRel = R_AMDGPU_RELATIVE64; - gotRel = R_AMDGPU_ABS64; - noneRel = R_AMDGPU_NONE; - symbolicRel = R_AMDGPU_ABS64; + RelativeRel = R_AMDGPU_RELATIVE64; + GotRel = R_AMDGPU_ABS64; + NoneRel = R_AMDGPU_NONE; + SymbolicRel = R_AMDGPU_ABS64; } -static uint32_t getEFlags(InputFile *file) { - return cast>(file)->getObj().getHeader()->e_flags; +static uint32_t getEFlags(InputFile *File) { + return cast>(File)->getObj().getHeader()->e_flags; } uint32_t AMDGPU::calcEFlags() const { - assert(!objectFiles.empty()); - uint32_t ret = getEFlags(objectFiles[0]); + assert(!ObjectFiles.empty()); + uint32_t Ret = getEFlags(ObjectFiles[0]); // Verify that all input files have the same e_flags. - for (InputFile *f : makeArrayRef(objectFiles).slice(1)) { - if (ret == getEFlags(f)) + for (InputFile *F : makeArrayRef(ObjectFiles).slice(1)) { + if (Ret == getEFlags(F)) continue; - error("incompatible e_flags: " + toString(f)); + error("incompatible e_flags: " + toString(F)); return 0; } - return ret; + return Ret; } -void AMDGPU::relocateOne(uint8_t *loc, RelType type, uint64_t val) const { - switch (type) { +void AMDGPU::relocateOne(uint8_t *Loc, RelType Type, uint64_t Val) const { + switch (Type) { case R_AMDGPU_ABS32: case R_AMDGPU_GOTPCREL: case R_AMDGPU_GOTPCREL32_LO: case R_AMDGPU_REL32: case R_AMDGPU_REL32_LO: - write32le(loc, val); + write32le(Loc, Val); break; case R_AMDGPU_ABS64: case R_AMDGPU_REL64: - write64le(loc, val); + write64le(Loc, Val); break; case R_AMDGPU_GOTPCREL32_HI: case R_AMDGPU_REL32_HI: - write32le(loc, val >> 32); + write32le(Loc, Val >> 32); break; default: llvm_unreachable("unknown relocation"); } } -RelExpr AMDGPU::getRelExpr(RelType type, const Symbol &s, - const uint8_t *loc) const { - switch (type) { +RelExpr AMDGPU::getRelExpr(RelType Type, const Symbol &S, + const uint8_t *Loc) const { + switch (Type) { case R_AMDGPU_ABS32: case R_AMDGPU_ABS64: return R_ABS; @@ -95,19 +95,19 @@ RelExpr AMDGPU::getRelExpr(RelType type, const Symbol &s, case R_AMDGPU_GOTPCREL32_HI: return R_GOT_PC; default: - error(getErrorLocation(loc) + "unknown relocation (" + Twine(type) + - ") against symbol " + toString(s)); + error(getErrorLocation(Loc) + "unknown relocation (" + Twine(Type) + + ") against symbol " + toString(S)); return R_NONE; } } -RelType AMDGPU::getDynRel(RelType type) const { - if (type == R_AMDGPU_ABS64) - return type; +RelType AMDGPU::getDynRel(RelType Type) const { + if (Type == R_AMDGPU_ABS64) + return Type; return R_AMDGPU_NONE; } TargetInfo *elf::getAMDGPUTargetInfo() { - static AMDGPU target; - return ⌖ + static AMDGPU Target; + return &Target; } diff --git a/lld/ELF/Arch/ARM.cpp b/lld/ELF/Arch/ARM.cpp index 64adc33c07ae28..61a22ae8d6bb65 100644 --- a/lld/ELF/Arch/ARM.cpp +++ b/lld/ELF/Arch/ARM.cpp @@ -26,62 +26,62 @@ class ARM final : public TargetInfo { public: ARM(); uint32_t calcEFlags() const override; - RelExpr getRelExpr(RelType type, const Symbol &s, - const uint8_t *loc) const override; - RelType getDynRel(RelType type) const override; - int64_t getImplicitAddend(const uint8_t *buf, RelType type) const override; - void writeGotPlt(uint8_t *buf, const Symbol &s) const override; - void writeIgotPlt(uint8_t *buf, const Symbol &s) const override; - void writePltHeader(uint8_t *buf) const override; - void writePlt(uint8_t *buf, uint64_t gotPltEntryAddr, uint64_t pltEntryAddr, - int32_t index, unsigned relOff) const override; - void addPltSymbols(InputSection &isec, uint64_t off) const override; - void addPltHeaderSymbols(InputSection &isd) const override; - bool needsThunk(RelExpr expr, RelType type, const InputFile *file, - uint64_t branchAddr, const Symbol &s) const override; + RelExpr getRelExpr(RelType Type, const Symbol &S, + const uint8_t *Loc) const override; + RelType getDynRel(RelType Type) const override; + int64_t getImplicitAddend(const uint8_t *Buf, RelType Type) const override; + void writeGotPlt(uint8_t *Buf, const Symbol &S) const override; + void writeIgotPlt(uint8_t *Buf, const Symbol &S) const override; + void writePltHeader(uint8_t *Buf) const override; + void writePlt(uint8_t *Buf, uint64_t GotPltEntryAddr, uint64_t PltEntryAddr, + int32_t Index, unsigned RelOff) const override; + void addPltSymbols(InputSection &IS, uint64_t Off) const override; + void addPltHeaderSymbols(InputSection &ISD) const override; + bool needsThunk(RelExpr Expr, RelType Type, const InputFile *File, + uint64_t BranchAddr, const Symbol &S) const override; uint32_t getThunkSectionSpacing() const override; - bool inBranchRange(RelType type, uint64_t src, uint64_t dst) const override; - void relocateOne(uint8_t *loc, RelType type, uint64_t val) const override; + bool inBranchRange(RelType Type, uint64_t Src, uint64_t Dst) const override; + void relocateOne(uint8_t *Loc, RelType Type, uint64_t Val) const override; }; } // namespace ARM::ARM() { - copyRel = R_ARM_COPY; - relativeRel = R_ARM_RELATIVE; - iRelativeRel = R_ARM_IRELATIVE; - gotRel = R_ARM_GLOB_DAT; - noneRel = R_ARM_NONE; - pltRel = R_ARM_JUMP_SLOT; - symbolicRel = R_ARM_ABS32; - tlsGotRel = R_ARM_TLS_TPOFF32; - tlsModuleIndexRel = R_ARM_TLS_DTPMOD32; - tlsOffsetRel = R_ARM_TLS_DTPOFF32; - gotBaseSymInGotPlt = false; - pltEntrySize = 16; - pltHeaderSize = 32; - trapInstr = {0xd4, 0xd4, 0xd4, 0xd4}; - needsThunks = true; + CopyRel = R_ARM_COPY; + RelativeRel = R_ARM_RELATIVE; + IRelativeRel = R_ARM_IRELATIVE; + GotRel = R_ARM_GLOB_DAT; + NoneRel = R_ARM_NONE; + PltRel = R_ARM_JUMP_SLOT; + SymbolicRel = R_ARM_ABS32; + TlsGotRel = R_ARM_TLS_TPOFF32; + TlsModuleIndexRel = R_ARM_TLS_DTPMOD32; + TlsOffsetRel = R_ARM_TLS_DTPOFF32; + GotBaseSymInGotPlt = false; + PltEntrySize = 16; + PltHeaderSize = 32; + TrapInstr = {0xd4, 0xd4, 0xd4, 0xd4}; + NeedsThunks = true; } uint32_t ARM::calcEFlags() const { // The ABIFloatType is used by loaders to detect the floating point calling // convention. - uint32_t abiFloatType = 0; - if (config->armVFPArgs == ARMVFPArgKind::Base || - config->armVFPArgs == ARMVFPArgKind::Default) - abiFloatType = EF_ARM_ABI_FLOAT_SOFT; - else if (config->armVFPArgs == ARMVFPArgKind::VFP) - abiFloatType = EF_ARM_ABI_FLOAT_HARD; + uint32_t ABIFloatType = 0; + if (Config->ARMVFPArgs == ARMVFPArgKind::Base || + Config->ARMVFPArgs == ARMVFPArgKind::Default) + ABIFloatType = EF_ARM_ABI_FLOAT_SOFT; + else if (Config->ARMVFPArgs == ARMVFPArgKind::VFP) + ABIFloatType = EF_ARM_ABI_FLOAT_HARD; // We don't currently use any features incompatible with EF_ARM_EABI_VER5, // but we don't have any firm guarantees of conformance. Linux AArch64 // kernels (as of 2016) require an EABI version to be set. - return EF_ARM_EABI_VER5 | abiFloatType; + return EF_ARM_EABI_VER5 | ABIFloatType; } -RelExpr ARM::getRelExpr(RelType type, const Symbol &s, - const uint8_t *loc) const { - switch (type) { +RelExpr ARM::getRelExpr(RelType Type, const Symbol &S, + const uint8_t *Loc) const { + switch (Type) { case R_ARM_THM_JUMP11: return R_PC; case R_ARM_CALL: @@ -106,11 +106,11 @@ RelExpr ARM::getRelExpr(RelType type, const Symbol &s, case R_ARM_SBREL32: return R_ARM_SBREL; case R_ARM_TARGET1: - return config->target1Rel ? R_PC : R_ABS; + return Config->Target1Rel ? R_PC : R_ABS; case R_ARM_TARGET2: - if (config->target2 == Target2Policy::Rel) + if (Config->Target2 == Target2Policy::Rel) return R_PC; - if (config->target2 == Target2Policy::Abs) + if (Config->Target2 == Target2Policy::Abs) return R_ABS; return R_GOT_PC; case R_ARM_TLS_GD32: @@ -143,25 +143,25 @@ RelExpr ARM::getRelExpr(RelType type, const Symbol &s, } } -RelType ARM::getDynRel(RelType type) const { - if ((type == R_ARM_ABS32) || (type == R_ARM_TARGET1 && !config->target1Rel)) +RelType ARM::getDynRel(RelType Type) const { + if ((Type == R_ARM_ABS32) || (Type == R_ARM_TARGET1 && !Config->Target1Rel)) return R_ARM_ABS32; return R_ARM_NONE; } -void ARM::writeGotPlt(uint8_t *buf, const Symbol &) const { - write32le(buf, in.plt->getVA()); +void ARM::writeGotPlt(uint8_t *Buf, const Symbol &) const { + write32le(Buf, In.Plt->getVA()); } -void ARM::writeIgotPlt(uint8_t *buf, const Symbol &s) const { +void ARM::writeIgotPlt(uint8_t *Buf, const Symbol &S) const { // An ARM entry is the address of the ifunc resolver function. - write32le(buf, s.getVA()); + write32le(Buf, S.getVA()); } // Long form PLT Header that does not have any restrictions on the displacement // of the .plt from the .plt.got. -static void writePltHeaderLong(uint8_t *buf) { - const uint8_t pltData[] = { +static void writePltHeaderLong(uint8_t *Buf) { + const uint8_t PltData[] = { 0x04, 0xe0, 0x2d, 0xe5, // str lr, [sp,#-4]! 0x04, 0xe0, 0x9f, 0xe5, // ldr lr, L2 0x0e, 0xe0, 0x8f, 0xe0, // L1: add lr, pc, lr @@ -170,128 +170,128 @@ static void writePltHeaderLong(uint8_t *buf) { 0xd4, 0xd4, 0xd4, 0xd4, // Pad to 32-byte boundary 0xd4, 0xd4, 0xd4, 0xd4, // Pad to 32-byte boundary 0xd4, 0xd4, 0xd4, 0xd4}; - memcpy(buf, pltData, sizeof(pltData)); - uint64_t gotPlt = in.gotPlt->getVA(); - uint64_t l1 = in.plt->getVA() + 8; - write32le(buf + 16, gotPlt - l1 - 8); + memcpy(Buf, PltData, sizeof(PltData)); + uint64_t GotPlt = In.GotPlt->getVA(); + uint64_t L1 = In.Plt->getVA() + 8; + write32le(Buf + 16, GotPlt - L1 - 8); } // The default PLT header requires the .plt.got to be within 128 Mb of the // .plt in the positive direction. -void ARM::writePltHeader(uint8_t *buf) const { +void ARM::writePltHeader(uint8_t *Buf) const { // Use a similar sequence to that in writePlt(), the difference is the calling // conventions mean we use lr instead of ip. The PLT entry is responsible for // saving lr on the stack, the dynamic loader is responsible for reloading // it. - const uint32_t pltData[] = { + const uint32_t PltData[] = { 0xe52de004, // L1: str lr, [sp,#-4]! 0xe28fe600, // add lr, pc, #0x0NN00000 &(.got.plt - L1 - 4) 0xe28eea00, // add lr, lr, #0x000NN000 &(.got.plt - L1 - 4) 0xe5bef000, // ldr pc, [lr, #0x00000NNN] &(.got.plt -L1 - 4) }; - uint64_t offset = in.gotPlt->getVA() - in.plt->getVA() - 4; - if (!llvm::isUInt<27>(offset)) { + uint64_t Offset = In.GotPlt->getVA() - In.Plt->getVA() - 4; + if (!llvm::isUInt<27>(Offset)) { // We cannot encode the Offset, use the long form. - writePltHeaderLong(buf); + writePltHeaderLong(Buf); return; } - write32le(buf + 0, pltData[0]); - write32le(buf + 4, pltData[1] | ((offset >> 20) & 0xff)); - write32le(buf + 8, pltData[2] | ((offset >> 12) & 0xff)); - write32le(buf + 12, pltData[3] | (offset & 0xfff)); - memcpy(buf + 16, trapInstr.data(), 4); // Pad to 32-byte boundary - memcpy(buf + 20, trapInstr.data(), 4); - memcpy(buf + 24, trapInstr.data(), 4); - memcpy(buf + 28, trapInstr.data(), 4); + write32le(Buf + 0, PltData[0]); + write32le(Buf + 4, PltData[1] | ((Offset >> 20) & 0xff)); + write32le(Buf + 8, PltData[2] | ((Offset >> 12) & 0xff)); + write32le(Buf + 12, PltData[3] | (Offset & 0xfff)); + memcpy(Buf + 16, TrapInstr.data(), 4); // Pad to 32-byte boundary + memcpy(Buf + 20, TrapInstr.data(), 4); + memcpy(Buf + 24, TrapInstr.data(), 4); + memcpy(Buf + 28, TrapInstr.data(), 4); } -void ARM::addPltHeaderSymbols(InputSection &isec) const { - addSyntheticLocal("$a", STT_NOTYPE, 0, 0, isec); - addSyntheticLocal("$d", STT_NOTYPE, 16, 0, isec); +void ARM::addPltHeaderSymbols(InputSection &IS) const { + addSyntheticLocal("$a", STT_NOTYPE, 0, 0, IS); + addSyntheticLocal("$d", STT_NOTYPE, 16, 0, IS); } // Long form PLT entries that do not have any restrictions on the displacement // of the .plt from the .plt.got. -static void writePltLong(uint8_t *buf, uint64_t gotPltEntryAddr, - uint64_t pltEntryAddr, int32_t index, - unsigned relOff) { - const uint8_t pltData[] = { +static void writePltLong(uint8_t *Buf, uint64_t GotPltEntryAddr, + uint64_t PltEntryAddr, int32_t Index, + unsigned RelOff) { + const uint8_t PltData[] = { 0x04, 0xc0, 0x9f, 0xe5, // ldr ip, L2 0x0f, 0xc0, 0x8c, 0xe0, // L1: add ip, ip, pc 0x00, 0xf0, 0x9c, 0xe5, // ldr pc, [ip] 0x00, 0x00, 0x00, 0x00, // L2: .word Offset(&(.plt.got) - L1 - 8 }; - memcpy(buf, pltData, sizeof(pltData)); - uint64_t l1 = pltEntryAddr + 4; - write32le(buf + 12, gotPltEntryAddr - l1 - 8); + memcpy(Buf, PltData, sizeof(PltData)); + uint64_t L1 = PltEntryAddr + 4; + write32le(Buf + 12, GotPltEntryAddr - L1 - 8); } // The default PLT entries require the .plt.got to be within 128 Mb of the // .plt in the positive direction. -void ARM::writePlt(uint8_t *buf, uint64_t gotPltEntryAddr, - uint64_t pltEntryAddr, int32_t index, - unsigned relOff) const { +void ARM::writePlt(uint8_t *Buf, uint64_t GotPltEntryAddr, + uint64_t PltEntryAddr, int32_t Index, + unsigned RelOff) const { // The PLT entry is similar to the example given in Appendix A of ELF for // the Arm Architecture. Instead of using the Group Relocations to find the // optimal rotation for the 8-bit immediate used in the add instructions we // hard code the most compact rotations for simplicity. This saves a load // instruction over the long plt sequences. - const uint32_t pltData[] = { + const uint32_t PltData[] = { 0xe28fc600, // L1: add ip, pc, #0x0NN00000 Offset(&(.plt.got) - L1 - 8 0xe28cca00, // add ip, ip, #0x000NN000 Offset(&(.plt.got) - L1 - 8 0xe5bcf000, // ldr pc, [ip, #0x00000NNN] Offset(&(.plt.got) - L1 - 8 }; - uint64_t offset = gotPltEntryAddr - pltEntryAddr - 8; - if (!llvm::isUInt<27>(offset)) { + uint64_t Offset = GotPltEntryAddr - PltEntryAddr - 8; + if (!llvm::isUInt<27>(Offset)) { // We cannot encode the Offset, use the long form. - writePltLong(buf, gotPltEntryAddr, pltEntryAddr, index, relOff); + writePltLong(Buf, GotPltEntryAddr, PltEntryAddr, Index, RelOff); return; } - write32le(buf + 0, pltData[0] | ((offset >> 20) & 0xff)); - write32le(buf + 4, pltData[1] | ((offset >> 12) & 0xff)); - write32le(buf + 8, pltData[2] | (offset & 0xfff)); - memcpy(buf + 12, trapInstr.data(), 4); // Pad to 16-byte boundary + write32le(Buf + 0, PltData[0] | ((Offset >> 20) & 0xff)); + write32le(Buf + 4, PltData[1] | ((Offset >> 12) & 0xff)); + write32le(Buf + 8, PltData[2] | (Offset & 0xfff)); + memcpy(Buf + 12, TrapInstr.data(), 4); // Pad to 16-byte boundary } -void ARM::addPltSymbols(InputSection &isec, uint64_t off) const { - addSyntheticLocal("$a", STT_NOTYPE, off, 0, isec); - addSyntheticLocal("$d", STT_NOTYPE, off + 12, 0, isec); +void ARM::addPltSymbols(InputSection &IS, uint64_t Off) const { + addSyntheticLocal("$a", STT_NOTYPE, Off, 0, IS); + addSyntheticLocal("$d", STT_NOTYPE, Off + 12, 0, IS); } -bool ARM::needsThunk(RelExpr expr, RelType type, const InputFile *file, - uint64_t branchAddr, const Symbol &s) const { +bool ARM::needsThunk(RelExpr Expr, RelType Type, const InputFile *File, + uint64_t BranchAddr, const Symbol &S) const { // If S is an undefined weak symbol and does not have a PLT entry then it // will be resolved as a branch to the next instruction. - if (s.isUndefWeak() && !s.isInPlt()) + if (S.isUndefWeak() && !S.isInPlt()) return false; // A state change from ARM to Thumb and vice versa must go through an // interworking thunk if the relocation type is not R_ARM_CALL or // R_ARM_THM_CALL. - switch (type) { + switch (Type) { case R_ARM_PC24: case R_ARM_PLT32: case R_ARM_JUMP24: // Source is ARM, all PLT entries are ARM so no interworking required. // Otherwise we need to interwork if Symbol has bit 0 set (Thumb). - if (expr == R_PC && ((s.getVA() & 1) == 1)) + if (Expr == R_PC && ((S.getVA() & 1) == 1)) return true; LLVM_FALLTHROUGH; case R_ARM_CALL: { - uint64_t dst = (expr == R_PLT_PC) ? s.getPltVA() : s.getVA(); - return !inBranchRange(type, branchAddr, dst); + uint64_t Dst = (Expr == R_PLT_PC) ? S.getPltVA() : S.getVA(); + return !inBranchRange(Type, BranchAddr, Dst); } case R_ARM_THM_JUMP19: case R_ARM_THM_JUMP24: // Source is Thumb, all PLT entries are ARM so interworking is required. // Otherwise we need to interwork if Symbol has bit 0 clear (ARM). - if (expr == R_PLT_PC || ((s.getVA() & 1) == 0)) + if (Expr == R_PLT_PC || ((S.getVA() & 1) == 0)) return true; LLVM_FALLTHROUGH; case R_ARM_THM_CALL: { - uint64_t dst = (expr == R_PLT_PC) ? s.getPltVA() : s.getVA(); - return !inBranchRange(type, branchAddr, dst); + uint64_t Dst = (Expr == R_PLT_PC) ? S.getPltVA() : S.getVA(); + return !inBranchRange(Type, BranchAddr, Dst); } } return false; @@ -299,13 +299,13 @@ bool ARM::needsThunk(RelExpr expr, RelType type, const InputFile *file, uint32_t ARM::getThunkSectionSpacing() const { // The placing of pre-created ThunkSections is controlled by the value - // thunkSectionSpacing returned by getThunkSectionSpacing(). The aim is to + // ThunkSectionSpacing returned by getThunkSectionSpacing(). The aim is to // place the ThunkSection such that all branches from the InputSections // prior to the ThunkSection can reach a Thunk placed at the end of the // ThunkSection. Graphically: - // | up to thunkSectionSpacing .text input sections | + // | up to ThunkSectionSpacing .text input sections | // | ThunkSection | - // | up to thunkSectionSpacing .text input sections | + // | up to ThunkSectionSpacing .text input sections | // | ThunkSection | // Pre-created ThunkSections are spaced roughly 16MiB apart on ARMv7. This @@ -316,66 +316,66 @@ uint32_t ARM::getThunkSectionSpacing() const { // Thumb B.W range +/- 1MiB // If a branch cannot reach a pre-created ThunkSection a new one will be // created so we can handle the rare cases of a Thumb 2 conditional branch. - // We intentionally use a lower size for thunkSectionSpacing than the maximum + // We intentionally use a lower size for ThunkSectionSpacing than the maximum // branch range so the end of the ThunkSection is more likely to be within // range of the branch instruction that is furthest away. The value we shorten - // thunkSectionSpacing by is set conservatively to allow us to create 16,384 + // ThunkSectionSpacing by is set conservatively to allow us to create 16,384 // 12 byte Thunks at any offset in a ThunkSection without risk of a branch to // one of the Thunks going out of range. - // On Arm the thunkSectionSpacing depends on the range of the Thumb Branch + // On Arm the ThunkSectionSpacing depends on the range of the Thumb Branch // range. On earlier Architectures such as ARMv4, ARMv5 and ARMv6 (except // ARMv6T2) the range is +/- 4MiB. - return (config->armJ1J2BranchEncoding) ? 0x1000000 - 0x30000 + return (Config->ARMJ1J2BranchEncoding) ? 0x1000000 - 0x30000 : 0x400000 - 0x7500; } -bool ARM::inBranchRange(RelType type, uint64_t src, uint64_t dst) const { - uint64_t range; - uint64_t instrSize; +bool ARM::inBranchRange(RelType Type, uint64_t Src, uint64_t Dst) const { + uint64_t Range; + uint64_t InstrSize; - switch (type) { + switch (Type) { case R_ARM_PC24: case R_ARM_PLT32: case R_ARM_JUMP24: case R_ARM_CALL: - range = 0x2000000; - instrSize = 4; + Range = 0x2000000; + InstrSize = 4; break; case R_ARM_THM_JUMP19: - range = 0x100000; - instrSize = 2; + Range = 0x100000; + InstrSize = 2; break; case R_ARM_THM_JUMP24: case R_ARM_THM_CALL: - range = config->armJ1J2BranchEncoding ? 0x1000000 : 0x400000; - instrSize = 2; + Range = Config->ARMJ1J2BranchEncoding ? 0x1000000 : 0x400000; + InstrSize = 2; break; default: return true; } // PC at Src is 2 instructions ahead, immediate of branch is signed - if (src > dst) - range -= 2 * instrSize; + if (Src > Dst) + Range -= 2 * InstrSize; else - range += instrSize; + Range += InstrSize; - if ((dst & 0x1) == 0) + if ((Dst & 0x1) == 0) // Destination is ARM, if ARM caller then Src is already 4-byte aligned. // If Thumb Caller (BLX) the Src address has bottom 2 bits cleared to ensure // destination will be 4 byte aligned. - src &= ~0x3; + Src &= ~0x3; else // Bit 0 == 1 denotes Thumb state, it is not part of the range - dst &= ~0x1; + Dst &= ~0x1; - uint64_t distance = (src > dst) ? src - dst : dst - src; - return distance <= range; + uint64_t Distance = (Src > Dst) ? Src - Dst : Dst - Src; + return Distance <= Range; } -void ARM::relocateOne(uint8_t *loc, RelType type, uint64_t val) const { - switch (type) { +void ARM::relocateOne(uint8_t *Loc, RelType Type, uint64_t Val) const { + switch (Type) { case R_ARM_ABS32: case R_ARM_BASE_PREL: case R_ARM_GOTOFF32: @@ -393,132 +393,132 @@ void ARM::relocateOne(uint8_t *loc, RelType type, uint64_t val) const { case R_ARM_TLS_LE32: case R_ARM_TLS_TPOFF32: case R_ARM_TLS_DTPOFF32: - write32le(loc, val); + write32le(Loc, Val); break; case R_ARM_PREL31: - checkInt(loc, val, 31, type); - write32le(loc, (read32le(loc) & 0x80000000) | (val & ~0x80000000)); + checkInt(Loc, Val, 31, Type); + write32le(Loc, (read32le(Loc) & 0x80000000) | (Val & ~0x80000000)); break; case R_ARM_CALL: // R_ARM_CALL is used for BL and BLX instructions, depending on the // value of bit 0 of Val, we must select a BL or BLX instruction - if (val & 1) { + if (Val & 1) { // If bit 0 of Val is 1 the target is Thumb, we must select a BLX. // The BLX encoding is 0xfa:H:imm24 where Val = imm24:H:'1' - checkInt(loc, val, 26, type); - write32le(loc, 0xfa000000 | // opcode - ((val & 2) << 23) | // H - ((val >> 2) & 0x00ffffff)); // imm24 + checkInt(Loc, Val, 26, Type); + write32le(Loc, 0xfa000000 | // opcode + ((Val & 2) << 23) | // H + ((Val >> 2) & 0x00ffffff)); // imm24 break; } - if ((read32le(loc) & 0xfe000000) == 0xfa000000) + if ((read32le(Loc) & 0xfe000000) == 0xfa000000) // BLX (always unconditional) instruction to an ARM Target, select an // unconditional BL. - write32le(loc, 0xeb000000 | (read32le(loc) & 0x00ffffff)); + write32le(Loc, 0xeb000000 | (read32le(Loc) & 0x00ffffff)); // fall through as BL encoding is shared with B LLVM_FALLTHROUGH; case R_ARM_JUMP24: case R_ARM_PC24: case R_ARM_PLT32: - checkInt(loc, val, 26, type); - write32le(loc, (read32le(loc) & ~0x00ffffff) | ((val >> 2) & 0x00ffffff)); + checkInt(Loc, Val, 26, Type); + write32le(Loc, (read32le(Loc) & ~0x00ffffff) | ((Val >> 2) & 0x00ffffff)); break; case R_ARM_THM_JUMP11: - checkInt(loc, val, 12, type); - write16le(loc, (read32le(loc) & 0xf800) | ((val >> 1) & 0x07ff)); + checkInt(Loc, Val, 12, Type); + write16le(Loc, (read32le(Loc) & 0xf800) | ((Val >> 1) & 0x07ff)); break; case R_ARM_THM_JUMP19: // Encoding T3: Val = S:J2:J1:imm6:imm11:0 - checkInt(loc, val, 21, type); - write16le(loc, - (read16le(loc) & 0xfbc0) | // opcode cond - ((val >> 10) & 0x0400) | // S - ((val >> 12) & 0x003f)); // imm6 - write16le(loc + 2, + checkInt(Loc, Val, 21, Type); + write16le(Loc, + (read16le(Loc) & 0xfbc0) | // opcode cond + ((Val >> 10) & 0x0400) | // S + ((Val >> 12) & 0x003f)); // imm6 + write16le(Loc + 2, 0x8000 | // opcode - ((val >> 8) & 0x0800) | // J2 - ((val >> 5) & 0x2000) | // J1 - ((val >> 1) & 0x07ff)); // imm11 + ((Val >> 8) & 0x0800) | // J2 + ((Val >> 5) & 0x2000) | // J1 + ((Val >> 1) & 0x07ff)); // imm11 break; case R_ARM_THM_CALL: // R_ARM_THM_CALL is used for BL and BLX instructions, depending on the // value of bit 0 of Val, we must select a BL or BLX instruction - if ((val & 1) == 0) { + if ((Val & 1) == 0) { // Ensure BLX destination is 4-byte aligned. As BLX instruction may // only be two byte aligned. This must be done before overflow check - val = alignTo(val, 4); + Val = alignTo(Val, 4); } // Bit 12 is 0 for BLX, 1 for BL - write16le(loc + 2, (read16le(loc + 2) & ~0x1000) | (val & 1) << 12); - if (!config->armJ1J2BranchEncoding) { + write16le(Loc + 2, (read16le(Loc + 2) & ~0x1000) | (Val & 1) << 12); + if (!Config->ARMJ1J2BranchEncoding) { // Older Arm architectures do not support R_ARM_THM_JUMP24 and have // different encoding rules and range due to J1 and J2 always being 1. - checkInt(loc, val, 23, type); - write16le(loc, + checkInt(Loc, Val, 23, Type); + write16le(Loc, 0xf000 | // opcode - ((val >> 12) & 0x07ff)); // imm11 - write16le(loc + 2, - (read16le(loc + 2) & 0xd000) | // opcode + ((Val >> 12) & 0x07ff)); // imm11 + write16le(Loc + 2, + (read16le(Loc + 2) & 0xd000) | // opcode 0x2800 | // J1 == J2 == 1 - ((val >> 1) & 0x07ff)); // imm11 + ((Val >> 1) & 0x07ff)); // imm11 break; } // Fall through as rest of encoding is the same as B.W LLVM_FALLTHROUGH; case R_ARM_THM_JUMP24: // Encoding B T4, BL T1, BLX T2: Val = S:I1:I2:imm10:imm11:0 - checkInt(loc, val, 25, type); - write16le(loc, + checkInt(Loc, Val, 25, Type); + write16le(Loc, 0xf000 | // opcode - ((val >> 14) & 0x0400) | // S - ((val >> 12) & 0x03ff)); // imm10 - write16le(loc + 2, - (read16le(loc + 2) & 0xd000) | // opcode - (((~(val >> 10)) ^ (val >> 11)) & 0x2000) | // J1 - (((~(val >> 11)) ^ (val >> 13)) & 0x0800) | // J2 - ((val >> 1) & 0x07ff)); // imm11 + ((Val >> 14) & 0x0400) | // S + ((Val >> 12) & 0x03ff)); // imm10 + write16le(Loc + 2, + (read16le(Loc + 2) & 0xd000) | // opcode + (((~(Val >> 10)) ^ (Val >> 11)) & 0x2000) | // J1 + (((~(Val >> 11)) ^ (Val >> 13)) & 0x0800) | // J2 + ((Val >> 1) & 0x07ff)); // imm11 break; case R_ARM_MOVW_ABS_NC: case R_ARM_MOVW_PREL_NC: - write32le(loc, (read32le(loc) & ~0x000f0fff) | ((val & 0xf000) << 4) | - (val & 0x0fff)); + write32le(Loc, (read32le(Loc) & ~0x000f0fff) | ((Val & 0xf000) << 4) | + (Val & 0x0fff)); break; case R_ARM_MOVT_ABS: case R_ARM_MOVT_PREL: - write32le(loc, (read32le(loc) & ~0x000f0fff) | - (((val >> 16) & 0xf000) << 4) | ((val >> 16) & 0xfff)); + write32le(Loc, (read32le(Loc) & ~0x000f0fff) | + (((Val >> 16) & 0xf000) << 4) | ((Val >> 16) & 0xfff)); break; case R_ARM_THM_MOVT_ABS: case R_ARM_THM_MOVT_PREL: // Encoding T1: A = imm4:i:imm3:imm8 - write16le(loc, + write16le(Loc, 0xf2c0 | // opcode - ((val >> 17) & 0x0400) | // i - ((val >> 28) & 0x000f)); // imm4 - write16le(loc + 2, - (read16le(loc + 2) & 0x8f00) | // opcode - ((val >> 12) & 0x7000) | // imm3 - ((val >> 16) & 0x00ff)); // imm8 + ((Val >> 17) & 0x0400) | // i + ((Val >> 28) & 0x000f)); // imm4 + write16le(Loc + 2, + (read16le(Loc + 2) & 0x8f00) | // opcode + ((Val >> 12) & 0x7000) | // imm3 + ((Val >> 16) & 0x00ff)); // imm8 break; case R_ARM_THM_MOVW_ABS_NC: case R_ARM_THM_MOVW_PREL_NC: // Encoding T3: A = imm4:i:imm3:imm8 - write16le(loc, + write16le(Loc, 0xf240 | // opcode - ((val >> 1) & 0x0400) | // i - ((val >> 12) & 0x000f)); // imm4 - write16le(loc + 2, - (read16le(loc + 2) & 0x8f00) | // opcode - ((val << 4) & 0x7000) | // imm3 - (val & 0x00ff)); // imm8 + ((Val >> 1) & 0x0400) | // i + ((Val >> 12) & 0x000f)); // imm4 + write16le(Loc + 2, + (read16le(Loc + 2) & 0x8f00) | // opcode + ((Val << 4) & 0x7000) | // imm3 + (Val & 0x00ff)); // imm8 break; default: - error(getErrorLocation(loc) + "unrecognized relocation " + toString(type)); + error(getErrorLocation(Loc) + "unrecognized relocation " + toString(Type)); } } -int64_t ARM::getImplicitAddend(const uint8_t *buf, RelType type) const { - switch (type) { +int64_t ARM::getImplicitAddend(const uint8_t *Buf, RelType Type) const { + switch (Type) { default: return 0; case R_ARM_ABS32: @@ -534,47 +534,47 @@ int64_t ARM::getImplicitAddend(const uint8_t *buf, RelType type) const { case R_ARM_TLS_LDO32: case R_ARM_TLS_IE32: case R_ARM_TLS_LE32: - return SignExtend64<32>(read32le(buf)); + return SignExtend64<32>(read32le(Buf)); case R_ARM_PREL31: - return SignExtend64<31>(read32le(buf)); + return SignExtend64<31>(read32le(Buf)); case R_ARM_CALL: case R_ARM_JUMP24: case R_ARM_PC24: case R_ARM_PLT32: - return SignExtend64<26>(read32le(buf) << 2); + return SignExtend64<26>(read32le(Buf) << 2); case R_ARM_THM_JUMP11: - return SignExtend64<12>(read16le(buf) << 1); + return SignExtend64<12>(read16le(Buf) << 1); case R_ARM_THM_JUMP19: { // Encoding T3: A = S:J2:J1:imm10:imm6:0 - uint16_t hi = read16le(buf); - uint16_t lo = read16le(buf + 2); - return SignExtend64<20>(((hi & 0x0400) << 10) | // S - ((lo & 0x0800) << 8) | // J2 - ((lo & 0x2000) << 5) | // J1 - ((hi & 0x003f) << 12) | // imm6 - ((lo & 0x07ff) << 1)); // imm11:0 + uint16_t Hi = read16le(Buf); + uint16_t Lo = read16le(Buf + 2); + return SignExtend64<20>(((Hi & 0x0400) << 10) | // S + ((Lo & 0x0800) << 8) | // J2 + ((Lo & 0x2000) << 5) | // J1 + ((Hi & 0x003f) << 12) | // imm6 + ((Lo & 0x07ff) << 1)); // imm11:0 } case R_ARM_THM_CALL: - if (!config->armJ1J2BranchEncoding) { + if (!Config->ARMJ1J2BranchEncoding) { // Older Arm architectures do not support R_ARM_THM_JUMP24 and have // different encoding rules and range due to J1 and J2 always being 1. - uint16_t hi = read16le(buf); - uint16_t lo = read16le(buf + 2); - return SignExtend64<22>(((hi & 0x7ff) << 12) | // imm11 - ((lo & 0x7ff) << 1)); // imm11:0 + uint16_t Hi = read16le(Buf); + uint16_t Lo = read16le(Buf + 2); + return SignExtend64<22>(((Hi & 0x7ff) << 12) | // imm11 + ((Lo & 0x7ff) << 1)); // imm11:0 break; } LLVM_FALLTHROUGH; case R_ARM_THM_JUMP24: { // Encoding B T4, BL T1, BLX T2: A = S:I1:I2:imm10:imm11:0 // I1 = NOT(J1 EOR S), I2 = NOT(J2 EOR S) - uint16_t hi = read16le(buf); - uint16_t lo = read16le(buf + 2); - return SignExtend64<24>(((hi & 0x0400) << 14) | // S - (~((lo ^ (hi << 3)) << 10) & 0x00800000) | // I1 - (~((lo ^ (hi << 1)) << 11) & 0x00400000) | // I2 - ((hi & 0x003ff) << 12) | // imm0 - ((lo & 0x007ff) << 1)); // imm11:0 + uint16_t Hi = read16le(Buf); + uint16_t Lo = read16le(Buf + 2); + return SignExtend64<24>(((Hi & 0x0400) << 14) | // S + (~((Lo ^ (Hi << 3)) << 10) & 0x00800000) | // I1 + (~((Lo ^ (Hi << 1)) << 11) & 0x00400000) | // I2 + ((Hi & 0x003ff) << 12) | // imm0 + ((Lo & 0x007ff) << 1)); // imm11:0 } // ELF for the ARM Architecture 4.6.1.1 the implicit addend for MOVW and // MOVT is in the range -32768 <= A < 32768 @@ -582,25 +582,25 @@ int64_t ARM::getImplicitAddend(const uint8_t *buf, RelType type) const { case R_ARM_MOVT_ABS: case R_ARM_MOVW_PREL_NC: case R_ARM_MOVT_PREL: { - uint64_t val = read32le(buf) & 0x000f0fff; - return SignExtend64<16>(((val & 0x000f0000) >> 4) | (val & 0x00fff)); + uint64_t Val = read32le(Buf) & 0x000f0fff; + return SignExtend64<16>(((Val & 0x000f0000) >> 4) | (Val & 0x00fff)); } case R_ARM_THM_MOVW_ABS_NC: case R_ARM_THM_MOVT_ABS: case R_ARM_THM_MOVW_PREL_NC: case R_ARM_THM_MOVT_PREL: { // Encoding T3: A = imm4:i:imm3:imm8 - uint16_t hi = read16le(buf); - uint16_t lo = read16le(buf + 2); - return SignExtend64<16>(((hi & 0x000f) << 12) | // imm4 - ((hi & 0x0400) << 1) | // i - ((lo & 0x7000) >> 4) | // imm3 - (lo & 0x00ff)); // imm8 + uint16_t Hi = read16le(Buf); + uint16_t Lo = read16le(Buf + 2); + return SignExtend64<16>(((Hi & 0x000f) << 12) | // imm4 + ((Hi & 0x0400) << 1) | // i + ((Lo & 0x7000) >> 4) | // imm3 + (Lo & 0x00ff)); // imm8 } } } TargetInfo *elf::getARMTargetInfo() { - static ARM target; - return ⌖ + static ARM Target; + return &Target; } diff --git a/lld/ELF/Arch/AVR.cpp b/lld/ELF/Arch/AVR.cpp index 869f0fe0c52579..5a573238d6d015 100644 --- a/lld/ELF/Arch/AVR.cpp +++ b/lld/ELF/Arch/AVR.cpp @@ -43,34 +43,34 @@ namespace { class AVR final : public TargetInfo { public: AVR(); - RelExpr getRelExpr(RelType type, const Symbol &s, - const uint8_t *loc) const override; - void relocateOne(uint8_t *loc, RelType type, uint64_t val) const override; + RelExpr getRelExpr(RelType Type, const Symbol &S, + const uint8_t *Loc) const override; + void relocateOne(uint8_t *Loc, RelType Type, uint64_t Val) const override; }; } // namespace -AVR::AVR() { noneRel = R_AVR_NONE; } +AVR::AVR() { NoneRel = R_AVR_NONE; } -RelExpr AVR::getRelExpr(RelType type, const Symbol &s, - const uint8_t *loc) const { +RelExpr AVR::getRelExpr(RelType Type, const Symbol &S, + const uint8_t *Loc) const { return R_ABS; } -void AVR::relocateOne(uint8_t *loc, RelType type, uint64_t val) const { - switch (type) { +void AVR::relocateOne(uint8_t *Loc, RelType Type, uint64_t Val) const { + switch (Type) { case R_AVR_CALL: { - uint16_t hi = val >> 17; - uint16_t lo = val >> 1; - write16le(loc, read16le(loc) | ((hi >> 1) << 4) | (hi & 1)); - write16le(loc + 2, lo); + uint16_t Hi = Val >> 17; + uint16_t Lo = Val >> 1; + write16le(Loc, read16le(Loc) | ((Hi >> 1) << 4) | (Hi & 1)); + write16le(Loc + 2, Lo); break; } default: - error(getErrorLocation(loc) + "unrecognized relocation " + toString(type)); + error(getErrorLocation(Loc) + "unrecognized relocation " + toString(Type)); } } TargetInfo *elf::getAVRTargetInfo() { - static AVR target; - return ⌖ + static AVR Target; + return &Target; } diff --git a/lld/ELF/Arch/Hexagon.cpp b/lld/ELF/Arch/Hexagon.cpp index 355ba9de4b97eb..1ebadc9a4227ee 100644 --- a/lld/ELF/Arch/Hexagon.cpp +++ b/lld/ELF/Arch/Hexagon.cpp @@ -27,80 +27,65 @@ class Hexagon final : public TargetInfo { public: Hexagon(); uint32_t calcEFlags() const override; - RelExpr getRelExpr(RelType type, const Symbol &s, - const uint8_t *loc) const override; - RelType getDynRel(RelType type) const override; - void relocateOne(uint8_t *loc, RelType type, uint64_t val) const override; - void writePltHeader(uint8_t *buf) const override; - void writePlt(uint8_t *buf, uint64_t gotPltEntryAddr, uint64_t pltEntryAddr, - int32_t index, unsigned relOff) const override; + RelExpr getRelExpr(RelType Type, const Symbol &S, + const uint8_t *Loc) const override; + void relocateOne(uint8_t *Loc, RelType Type, uint64_t Val) const override; + void writePltHeader(uint8_t *Buf) const override; + void writePlt(uint8_t *Buf, uint64_t GotPltEntryAddr, uint64_t PltEntryAddr, + int32_t Index, unsigned RelOff) const override; }; } // namespace Hexagon::Hexagon() { - pltRel = R_HEX_JMP_SLOT; - relativeRel = R_HEX_RELATIVE; - gotRel = R_HEX_GLOB_DAT; - symbolicRel = R_HEX_32; + PltRel = R_HEX_JMP_SLOT; + RelativeRel = R_HEX_RELATIVE; + GotRel = R_HEX_GLOB_DAT; + SymbolicRel = R_HEX_32; // The zero'th GOT entry is reserved for the address of _DYNAMIC. The // next 3 are reserved for the dynamic loader. - gotPltHeaderEntriesNum = 4; + GotPltHeaderEntriesNum = 4; - pltEntrySize = 16; - pltHeaderSize = 32; + PltEntrySize = 16; + PltHeaderSize = 32; // Hexagon Linux uses 64K pages by default. - defaultMaxPageSize = 0x10000; - noneRel = R_HEX_NONE; + DefaultMaxPageSize = 0x10000; + NoneRel = R_HEX_NONE; } uint32_t Hexagon::calcEFlags() const { - assert(!objectFiles.empty()); + assert(!ObjectFiles.empty()); // The architecture revision must always be equal to or greater than // greatest revision in the list of inputs. - uint32_t ret = 0; - for (InputFile *f : objectFiles) { - uint32_t eflags = cast>(f)->getObj().getHeader()->e_flags; - if (eflags > ret) - ret = eflags; + uint32_t Ret = 0; + for (InputFile *F : ObjectFiles) { + uint32_t EFlags = cast>(F)->getObj().getHeader()->e_flags; + if (EFlags > Ret) + Ret = EFlags; } - return ret; + return Ret; } -static uint32_t applyMask(uint32_t mask, uint32_t data) { - uint32_t result = 0; - size_t off = 0; +static uint32_t applyMask(uint32_t Mask, uint32_t Data) { + uint32_t Result = 0; + size_t Off = 0; - for (size_t bit = 0; bit != 32; ++bit) { - uint32_t valBit = (data >> off) & 1; - uint32_t maskBit = (mask >> bit) & 1; - if (maskBit) { - result |= (valBit << bit); - ++off; + for (size_t Bit = 0; Bit != 32; ++Bit) { + uint32_t ValBit = (Data >> Off) & 1; + uint32_t MaskBit = (Mask >> Bit) & 1; + if (MaskBit) { + Result |= (ValBit << Bit); + ++Off; } } - return result; + return Result; } -RelExpr Hexagon::getRelExpr(RelType type, const Symbol &s, - const uint8_t *loc) const { - switch (type) { - case R_HEX_NONE: - return R_NONE; - case R_HEX_6_X: - case R_HEX_8_X: - case R_HEX_9_X: - case R_HEX_10_X: - case R_HEX_11_X: - case R_HEX_12_X: - case R_HEX_16_X: - case R_HEX_32: - case R_HEX_32_6_X: - case R_HEX_HI16: - case R_HEX_LO16: - return R_ABS; +RelExpr Hexagon::getRelExpr(RelType Type, const Symbol &S, + const uint8_t *Loc) const { + switch (Type) { case R_HEX_B9_PCREL: case R_HEX_B9_PCREL_X: case R_HEX_B13_PCREL: @@ -114,33 +99,25 @@ RelExpr Hexagon::getRelExpr(RelType type, const Symbol &s, case R_HEX_B22_PCREL_X: case R_HEX_B32_PCREL_X: return R_PLT_PC; - case R_HEX_GOTREL_11_X: - case R_HEX_GOTREL_16_X: - case R_HEX_GOTREL_32_6_X: - case R_HEX_GOTREL_HI16: - case R_HEX_GOTREL_LO16: - return R_GOTPLTREL; case R_HEX_GOT_11_X: case R_HEX_GOT_16_X: case R_HEX_GOT_32_6_X: - return R_GOTPLT; + return R_HEXAGON_GOT; default: - error(getErrorLocation(loc) + "unknown relocation (" + Twine(type) + - ") against symbol " + toString(s)); - return R_NONE; + return R_ABS; } } -static uint32_t findMaskR6(uint32_t insn) { +static uint32_t findMaskR6(uint32_t Insn) { // There are (arguably too) many relocation masks for the DSP's // R_HEX_6_X type. The table below is used to select the correct mask // for the given instruction. struct InstructionMask { - uint32_t cmpMask; - uint32_t relocMask; + uint32_t CmpMask; + uint32_t RelocMask; }; - static const InstructionMask r6[] = { + static const InstructionMask R6[] = { {0x38000000, 0x0000201f}, {0x39000000, 0x0000201f}, {0x3e000000, 0x00001f80}, {0x3f000000, 0x00001f80}, {0x40000000, 0x000020f8}, {0x41000000, 0x000007e0}, @@ -158,128 +135,124 @@ static uint32_t findMaskR6(uint32_t insn) { // Duplex forms have a fixed mask and parse bits 15:14 are always // zero. Non-duplex insns will always have at least one bit set in the // parse field. - if ((0xC000 & insn) == 0x0) + if ((0xC000 & Insn) == 0x0) return 0x03f00000; - for (InstructionMask i : r6) - if ((0xff000000 & insn) == i.cmpMask) - return i.relocMask; + for (InstructionMask I : R6) + if ((0xff000000 & Insn) == I.CmpMask) + return I.RelocMask; error("unrecognized instruction for R_HEX_6 relocation: 0x" + - utohexstr(insn)); + utohexstr(Insn)); return 0; } -static uint32_t findMaskR8(uint32_t insn) { - if ((0xff000000 & insn) == 0xde000000) +static uint32_t findMaskR8(uint32_t Insn) { + if ((0xff000000 & Insn) == 0xde000000) return 0x00e020e8; - if ((0xff000000 & insn) == 0x3c000000) + if ((0xff000000 & Insn) == 0x3c000000) return 0x0000207f; return 0x00001fe0; } -static uint32_t findMaskR11(uint32_t insn) { - if ((0xff000000 & insn) == 0xa1000000) +static uint32_t findMaskR11(uint32_t Insn) { + if ((0xff000000 & Insn) == 0xa1000000) return 0x060020ff; return 0x06003fe0; } -static uint32_t findMaskR16(uint32_t insn) { - if ((0xff000000 & insn) == 0x48000000) +static uint32_t findMaskR16(uint32_t Insn) { + if ((0xff000000 & Insn) == 0x48000000) return 0x061f20ff; - if ((0xff000000 & insn) == 0x49000000) + if ((0xff000000 & Insn) == 0x49000000) return 0x061f3fe0; - if ((0xff000000 & insn) == 0x78000000) + if ((0xff000000 & Insn) == 0x78000000) return 0x00df3fe0; - if ((0xff000000 & insn) == 0xb0000000) + if ((0xff000000 & Insn) == 0xb0000000) return 0x0fe03fe0; error("unrecognized instruction for R_HEX_16_X relocation: 0x" + - utohexstr(insn)); + utohexstr(Insn)); return 0; } -static void or32le(uint8_t *p, int32_t v) { write32le(p, read32le(p) | v); } +static void or32le(uint8_t *P, int32_t V) { write32le(P, read32le(P) | V); } -void Hexagon::relocateOne(uint8_t *loc, RelType type, uint64_t val) const { - switch (type) { +void Hexagon::relocateOne(uint8_t *Loc, RelType Type, uint64_t Val) const { + switch (Type) { case R_HEX_NONE: break; case R_HEX_6_PCREL_X: case R_HEX_6_X: - or32le(loc, applyMask(findMaskR6(read32le(loc)), val)); + or32le(Loc, applyMask(findMaskR6(read32le(Loc)), Val)); break; case R_HEX_8_X: - or32le(loc, applyMask(findMaskR8(read32le(loc)), val)); + or32le(Loc, applyMask(findMaskR8(read32le(Loc)), Val)); break; case R_HEX_9_X: - or32le(loc, applyMask(0x00003fe0, val & 0x3f)); + or32le(Loc, applyMask(0x00003fe0, Val & 0x3f)); break; case R_HEX_10_X: - or32le(loc, applyMask(0x00203fe0, val & 0x3f)); + or32le(Loc, applyMask(0x00203fe0, Val & 0x3f)); break; case R_HEX_11_X: case R_HEX_GOT_11_X: - case R_HEX_GOTREL_11_X: - or32le(loc, applyMask(findMaskR11(read32le(loc)), val & 0x3f)); + or32le(Loc, applyMask(findMaskR11(read32le(Loc)), Val & 0x3f)); break; case R_HEX_12_X: - or32le(loc, applyMask(0x000007e0, val)); + or32le(Loc, applyMask(0x000007e0, Val)); break; case R_HEX_16_X: // These relocs only have 6 effective bits. case R_HEX_GOT_16_X: - case R_HEX_GOTREL_16_X: - or32le(loc, applyMask(findMaskR16(read32le(loc)), val & 0x3f)); + or32le(Loc, applyMask(findMaskR16(read32le(Loc)), Val & 0x3f)); break; case R_HEX_32: case R_HEX_32_PCREL: - or32le(loc, val); + or32le(Loc, Val); break; case R_HEX_32_6_X: case R_HEX_GOT_32_6_X: - case R_HEX_GOTREL_32_6_X: - or32le(loc, applyMask(0x0fff3fff, val >> 6)); + or32le(Loc, applyMask(0x0fff3fff, Val >> 6)); break; case R_HEX_B9_PCREL: - or32le(loc, applyMask(0x003000fe, val >> 2)); + or32le(Loc, applyMask(0x003000fe, Val >> 2)); break; case R_HEX_B9_PCREL_X: - or32le(loc, applyMask(0x003000fe, val & 0x3f)); + or32le(Loc, applyMask(0x003000fe, Val & 0x3f)); break; case R_HEX_B13_PCREL: - or32le(loc, applyMask(0x00202ffe, val >> 2)); + or32le(Loc, applyMask(0x00202ffe, Val >> 2)); break; case R_HEX_B15_PCREL: - or32le(loc, applyMask(0x00df20fe, val >> 2)); + or32le(Loc, applyMask(0x00df20fe, Val >> 2)); break; case R_HEX_B15_PCREL_X: - or32le(loc, applyMask(0x00df20fe, val & 0x3f)); + or32le(Loc, applyMask(0x00df20fe, Val & 0x3f)); break; case R_HEX_B22_PCREL: case R_HEX_PLT_B22_PCREL: - or32le(loc, applyMask(0x1ff3ffe, val >> 2)); + or32le(Loc, applyMask(0x1ff3ffe, Val >> 2)); break; case R_HEX_B22_PCREL_X: - or32le(loc, applyMask(0x1ff3ffe, val & 0x3f)); + or32le(Loc, applyMask(0x1ff3ffe, Val & 0x3f)); break; case R_HEX_B32_PCREL_X: - or32le(loc, applyMask(0x0fff3fff, val >> 6)); + or32le(Loc, applyMask(0x0fff3fff, Val >> 6)); break; - case R_HEX_GOTREL_HI16: case R_HEX_HI16: - or32le(loc, applyMask(0x00c03fff, val >> 16)); + or32le(Loc, applyMask(0x00c03fff, Val >> 16)); break; - case R_HEX_GOTREL_LO16: case R_HEX_LO16: - or32le(loc, applyMask(0x00c03fff, val)); + or32le(Loc, applyMask(0x00c03fff, Val)); break; default: - llvm_unreachable("unknown relocation"); + error(getErrorLocation(Loc) + "unrecognized relocation " + toString(Type)); + break; } } -void Hexagon::writePltHeader(uint8_t *buf) const { - const uint8_t pltData[] = { +void Hexagon::writePltHeader(uint8_t *Buf) const { + const uint8_t PltData[] = { 0x00, 0x40, 0x00, 0x00, // { immext (#0) 0x1c, 0xc0, 0x49, 0x6a, // r28 = add (pc, ##GOT0@PCREL) } # @GOT0 0x0e, 0x42, 0x9c, 0xe2, // { r14 -= add (r28, #16) # offset of GOTn @@ -289,36 +262,30 @@ void Hexagon::writePltHeader(uint8_t *buf) const { 0x00, 0xc0, 0x9c, 0x52, // jumpr r28 } # call dynamic linker 0x0c, 0xdb, 0x00, 0x54, // trap0(#0xdb) # bring plt0 into 16byte alignment }; - memcpy(buf, pltData, sizeof(pltData)); + memcpy(Buf, PltData, sizeof(PltData)); // Offset from PLT0 to the GOT. - uint64_t off = in.gotPlt->getVA() - in.plt->getVA(); - relocateOne(buf, R_HEX_B32_PCREL_X, off); - relocateOne(buf + 4, R_HEX_6_PCREL_X, off); + uint64_t Off = In.GotPlt->getVA() - In.Plt->getVA(); + relocateOne(Buf, R_HEX_B32_PCREL_X, Off); + relocateOne(Buf + 4, R_HEX_6_PCREL_X, Off); } -void Hexagon::writePlt(uint8_t *buf, uint64_t gotPltEntryAddr, - uint64_t pltEntryAddr, int32_t index, - unsigned relOff) const { - const uint8_t inst[] = { +void Hexagon::writePlt(uint8_t *Buf, uint64_t GotPltEntryAddr, + uint64_t PltEntryAddr, int32_t Index, + unsigned RelOff) const { + const uint8_t Inst[] = { 0x00, 0x40, 0x00, 0x00, // { immext (#0) 0x0e, 0xc0, 0x49, 0x6a, // r14 = add (pc, ##GOTn@PCREL) } 0x1c, 0xc0, 0x8e, 0x91, // r28 = memw (r14) 0x00, 0xc0, 0x9c, 0x52, // jumpr r28 }; - memcpy(buf, inst, sizeof(inst)); - - relocateOne(buf, R_HEX_B32_PCREL_X, gotPltEntryAddr - pltEntryAddr); - relocateOne(buf + 4, R_HEX_6_PCREL_X, gotPltEntryAddr - pltEntryAddr); -} + memcpy(Buf, Inst, sizeof(Inst)); -RelType Hexagon::getDynRel(RelType type) const { - if (type == R_HEX_32) - return type; - return R_HEX_NONE; + relocateOne(Buf, R_HEX_B32_PCREL_X, GotPltEntryAddr - PltEntryAddr); + relocateOne(Buf + 4, R_HEX_6_PCREL_X, GotPltEntryAddr - PltEntryAddr); } TargetInfo *elf::getHexagonTargetInfo() { - static Hexagon target; - return ⌖ + static Hexagon Target; + return &Target; } diff --git a/lld/ELF/Arch/MSP430.cpp b/lld/ELF/Arch/MSP430.cpp index 90664396c85ea0..0f0b5662ec8410 100644 --- a/lld/ELF/Arch/MSP430.cpp +++ b/lld/ELF/Arch/MSP430.cpp @@ -33,20 +33,20 @@ namespace { class MSP430 final : public TargetInfo { public: MSP430(); - RelExpr getRelExpr(RelType type, const Symbol &s, - const uint8_t *loc) const override; - void relocateOne(uint8_t *loc, RelType type, uint64_t val) const override; + RelExpr getRelExpr(RelType Type, const Symbol &S, + const uint8_t *Loc) const override; + void relocateOne(uint8_t *Loc, RelType Type, uint64_t Val) const override; }; } // namespace MSP430::MSP430() { // mov.b #0, r3 - trapInstr = {0x43, 0x43, 0x43, 0x43}; + TrapInstr = {0x43, 0x43, 0x43, 0x43}; } -RelExpr MSP430::getRelExpr(RelType type, const Symbol &s, - const uint8_t *loc) const { - switch (type) { +RelExpr MSP430::getRelExpr(RelType Type, const Symbol &S, + const uint8_t *Loc) const { + switch (Type) { case R_MSP430_10_PCREL: case R_MSP430_16_PCREL: case R_MSP430_16_PCREL_BYTE: @@ -59,35 +59,35 @@ RelExpr MSP430::getRelExpr(RelType type, const Symbol &s, } } -void MSP430::relocateOne(uint8_t *loc, RelType type, uint64_t val) const { - switch (type) { +void MSP430::relocateOne(uint8_t *Loc, RelType Type, uint64_t Val) const { + switch (Type) { case R_MSP430_8: - checkIntUInt(loc, val, 8, type); - *loc = val; + checkIntUInt(Loc, Val, 8, Type); + *Loc = Val; break; case R_MSP430_16: case R_MSP430_16_PCREL: case R_MSP430_16_BYTE: case R_MSP430_16_PCREL_BYTE: - checkIntUInt(loc, val, 16, type); - write16le(loc, val); + checkIntUInt(Loc, Val, 16, Type); + write16le(Loc, Val); break; case R_MSP430_32: - checkIntUInt(loc, val, 32, type); - write32le(loc, val); + checkIntUInt(Loc, Val, 32, Type); + write32le(Loc, Val); break; case R_MSP430_10_PCREL: { - int16_t offset = ((int16_t)val >> 1) - 1; - checkInt(loc, offset, 10, type); - write16le(loc, (read16le(loc) & 0xFC00) | (offset & 0x3FF)); + int16_t Offset = ((int16_t)Val >> 1) - 1; + checkInt(Loc, Offset, 10, Type); + write16le(Loc, (read16le(Loc) & 0xFC00) | (Offset & 0x3FF)); break; } default: - error(getErrorLocation(loc) + "unrecognized relocation " + toString(type)); + error(getErrorLocation(Loc) + "unrecognized relocation " + toString(Type)); } } TargetInfo *elf::getMSP430TargetInfo() { - static MSP430 target; - return ⌖ + static MSP430 Target; + return &Target; } diff --git a/lld/ELF/Arch/Mips.cpp b/lld/ELF/Arch/Mips.cpp index d218cf224d4db5..18fc6968f5d167 100644 --- a/lld/ELF/Arch/Mips.cpp +++ b/lld/ELF/Arch/Mips.cpp @@ -28,47 +28,47 @@ template class MIPS final : public TargetInfo { public: MIPS(); uint32_t calcEFlags() const override; - RelExpr getRelExpr(RelType type, const Symbol &s, - const uint8_t *loc) const override; - int64_t getImplicitAddend(const uint8_t *buf, RelType type) const override; - RelType getDynRel(RelType type) const override; - void writeGotPlt(uint8_t *buf, const Symbol &s) const override; - void writePltHeader(uint8_t *buf) const override; - void writePlt(uint8_t *buf, uint64_t gotPltEntryAddr, uint64_t pltEntryAddr, - int32_t index, unsigned relOff) const override; - bool needsThunk(RelExpr expr, RelType type, const InputFile *file, - uint64_t branchAddr, const Symbol &s) const override; - void relocateOne(uint8_t *loc, RelType type, uint64_t val) const override; - bool usesOnlyLowPageBits(RelType type) const override; + RelExpr getRelExpr(RelType Type, const Symbol &S, + const uint8_t *Loc) const override; + int64_t getImplicitAddend(const uint8_t *Buf, RelType Type) const override; + RelType getDynRel(RelType Type) const override; + void writeGotPlt(uint8_t *Buf, const Symbol &S) const override; + void writePltHeader(uint8_t *Buf) const override; + void writePlt(uint8_t *Buf, uint64_t GotPltEntryAddr, uint64_t PltEntryAddr, + int32_t Index, unsigned RelOff) const override; + bool needsThunk(RelExpr Expr, RelType Type, const InputFile *File, + uint64_t BranchAddr, const Symbol &S) const override; + void relocateOne(uint8_t *Loc, RelType Type, uint64_t Val) const override; + bool usesOnlyLowPageBits(RelType Type) const override; }; } // namespace template MIPS::MIPS() { - gotPltHeaderEntriesNum = 2; - defaultMaxPageSize = 65536; - gotBaseSymInGotPlt = false; - pltEntrySize = 16; - pltHeaderSize = 32; - copyRel = R_MIPS_COPY; - noneRel = R_MIPS_NONE; - pltRel = R_MIPS_JUMP_SLOT; - needsThunks = true; + GotPltHeaderEntriesNum = 2; + DefaultMaxPageSize = 65536; + GotBaseSymInGotPlt = false; + PltEntrySize = 16; + PltHeaderSize = 32; + CopyRel = R_MIPS_COPY; + NoneRel = R_MIPS_NONE; + PltRel = R_MIPS_JUMP_SLOT; + NeedsThunks = true; // Set `sigrie 1` as a trap instruction. - write32(trapInstr.data(), 0x04170001); + write32(TrapInstr.data(), 0x04170001); if (ELFT::Is64Bits) { - relativeRel = (R_MIPS_64 << 8) | R_MIPS_REL32; - symbolicRel = R_MIPS_64; - tlsGotRel = R_MIPS_TLS_TPREL64; - tlsModuleIndexRel = R_MIPS_TLS_DTPMOD64; - tlsOffsetRel = R_MIPS_TLS_DTPREL64; + RelativeRel = (R_MIPS_64 << 8) | R_MIPS_REL32; + SymbolicRel = R_MIPS_64; + TlsGotRel = R_MIPS_TLS_TPREL64; + TlsModuleIndexRel = R_MIPS_TLS_DTPMOD64; + TlsOffsetRel = R_MIPS_TLS_DTPREL64; } else { - relativeRel = R_MIPS_REL32; - symbolicRel = R_MIPS_32; - tlsGotRel = R_MIPS_TLS_TPREL32; - tlsModuleIndexRel = R_MIPS_TLS_DTPMOD32; - tlsOffsetRel = R_MIPS_TLS_DTPREL32; + RelativeRel = R_MIPS_REL32; + SymbolicRel = R_MIPS_32; + TlsGotRel = R_MIPS_TLS_TPREL32; + TlsModuleIndexRel = R_MIPS_TLS_DTPMOD32; + TlsOffsetRel = R_MIPS_TLS_DTPREL32; } } @@ -77,13 +77,13 @@ template uint32_t MIPS::calcEFlags() const { } template -RelExpr MIPS::getRelExpr(RelType type, const Symbol &s, - const uint8_t *loc) const { +RelExpr MIPS::getRelExpr(RelType Type, const Symbol &S, + const uint8_t *Loc) const { // See comment in the calculateMipsRelChain. - if (ELFT::Is64Bits || config->mipsN32Abi) - type &= 0xff; + if (ELFT::Is64Bits || Config->MipsN32Abi) + Type &= 0xff; - switch (type) { + switch (Type) { case R_MIPS_JALR: case R_MICROMIPS_JALR: return R_HINT; @@ -107,9 +107,9 @@ RelExpr MIPS::getRelExpr(RelType type, const Symbol &s, // offset between start of function and 'gp' value which by default // equal to the start of .got section. In that case we consider these // relocations as relative. - if (&s == ElfSym::mipsGpDisp) + if (&S == ElfSym::MipsGpDisp) return R_MIPS_GOT_GP_PC; - if (&s == ElfSym::mipsLocalGp) + if (&S == ElfSym::MipsLocalGp) return R_MIPS_GOT_GP; LLVM_FALLTHROUGH; case R_MIPS_32: @@ -120,16 +120,15 @@ RelExpr MIPS::getRelExpr(RelType type, const Symbol &s, case R_MIPS_TLS_DTPREL_LO16: case R_MIPS_TLS_DTPREL32: case R_MIPS_TLS_DTPREL64: - case R_MICROMIPS_TLS_DTPREL_HI16: - case R_MICROMIPS_TLS_DTPREL_LO16: - return R_ABS; case R_MIPS_TLS_TPREL_HI16: case R_MIPS_TLS_TPREL_LO16: case R_MIPS_TLS_TPREL32: case R_MIPS_TLS_TPREL64: + case R_MICROMIPS_TLS_DTPREL_HI16: + case R_MICROMIPS_TLS_DTPREL_LO16: case R_MICROMIPS_TLS_TPREL_HI16: case R_MICROMIPS_TLS_TPREL_LO16: - return R_TLS; + return R_ABS; case R_MIPS_PC32: case R_MIPS_PC16: case R_MIPS_PC19_S2: @@ -147,7 +146,7 @@ RelExpr MIPS::getRelExpr(RelType type, const Symbol &s, return R_PC; case R_MIPS_GOT16: case R_MICROMIPS_GOT16: - if (s.isLocal()) + if (S.isLocal()) return R_MIPS_GOT_LOCAL_PAGE; LLVM_FALLTHROUGH; case R_MIPS_CALL16: @@ -176,213 +175,213 @@ RelExpr MIPS::getRelExpr(RelType type, const Symbol &s, case R_MIPS_NONE: return R_NONE; default: - error(getErrorLocation(loc) + "unknown relocation (" + Twine(type) + - ") against symbol " + toString(s)); + error(getErrorLocation(Loc) + "unknown relocation (" + Twine(Type) + + ") against symbol " + toString(S)); return R_NONE; } } -template RelType MIPS::getDynRel(RelType type) const { - if (type == symbolicRel) - return type; +template RelType MIPS::getDynRel(RelType Type) const { + if (Type == SymbolicRel) + return Type; return R_MIPS_NONE; } template -void MIPS::writeGotPlt(uint8_t *buf, const Symbol &) const { - uint64_t va = in.plt->getVA(); +void MIPS::writeGotPlt(uint8_t *Buf, const Symbol &) const { + uint64_t VA = In.Plt->getVA(); if (isMicroMips()) - va |= 1; - write32(buf, va); + VA |= 1; + write32(Buf, VA); } -template static uint32_t readShuffle(const uint8_t *loc) { +template static uint32_t readShuffle(const uint8_t *Loc) { // The major opcode of a microMIPS instruction needs to appear // in the first 16-bit word (lowest address) for efficient hardware // decode so that it knows if the instruction is 16-bit or 32-bit // as early as possible. To do so, little-endian binaries keep 16-bit // words in a big-endian order. That is why we have to swap these // words to get a correct value. - uint32_t v = read32(loc); + uint32_t V = read32(Loc); if (E == support::little) - return (v << 16) | (v >> 16); - return v; + return (V << 16) | (V >> 16); + return V; } template -static void writeValue(uint8_t *loc, uint64_t v, uint8_t bitsSize, - uint8_t shift) { - uint32_t instr = read32(loc); - uint32_t mask = 0xffffffff >> (32 - bitsSize); - uint32_t data = (instr & ~mask) | ((v >> shift) & mask); - write32(loc, data); +static void writeValue(uint8_t *Loc, uint64_t V, uint8_t BitsSize, + uint8_t Shift) { + uint32_t Instr = read32(Loc); + uint32_t Mask = 0xffffffff >> (32 - BitsSize); + uint32_t Data = (Instr & ~Mask) | ((V >> Shift) & Mask); + write32(Loc, Data); } template -static void writeShuffleValue(uint8_t *loc, uint64_t v, uint8_t bitsSize, - uint8_t shift) { +static void writeShuffleValue(uint8_t *Loc, uint64_t V, uint8_t BitsSize, + uint8_t Shift) { // See comments in readShuffle for purpose of this code. - uint16_t *words = (uint16_t *)loc; + uint16_t *Words = (uint16_t *)Loc; if (E == support::little) - std::swap(words[0], words[1]); + std::swap(Words[0], Words[1]); - writeValue(loc, v, bitsSize, shift); + writeValue(Loc, V, BitsSize, Shift); if (E == support::little) - std::swap(words[0], words[1]); + std::swap(Words[0], Words[1]); } template -static void writeMicroRelocation16(uint8_t *loc, uint64_t v, uint8_t bitsSize, - uint8_t shift) { - uint16_t instr = read16(loc); - uint16_t mask = 0xffff >> (16 - bitsSize); - uint16_t data = (instr & ~mask) | ((v >> shift) & mask); - write16(loc, data); +static void writeMicroRelocation16(uint8_t *Loc, uint64_t V, uint8_t BitsSize, + uint8_t Shift) { + uint16_t Instr = read16(Loc); + uint16_t Mask = 0xffff >> (16 - BitsSize); + uint16_t Data = (Instr & ~Mask) | ((V >> Shift) & Mask); + write16(Loc, Data); } -template void MIPS::writePltHeader(uint8_t *buf) const { - const endianness e = ELFT::TargetEndianness; +template void MIPS::writePltHeader(uint8_t *Buf) const { + const endianness E = ELFT::TargetEndianness; if (isMicroMips()) { - uint64_t gotPlt = in.gotPlt->getVA(); - uint64_t plt = in.plt->getVA(); + uint64_t GotPlt = In.GotPlt->getVA(); + uint64_t Plt = In.Plt->getVA(); // Overwrite trap instructions written by Writer::writeTrapInstr. - memset(buf, 0, pltHeaderSize); - - write16(buf, isMipsR6() ? 0x7860 : 0x7980); // addiupc v1, (GOTPLT) - . - write16(buf + 4, 0xff23); // lw $25, 0($3) - write16(buf + 8, 0x0535); // subu16 $2, $2, $3 - write16(buf + 10, 0x2525); // srl16 $2, $2, 2 - write16(buf + 12, 0x3302); // addiu $24, $2, -2 - write16(buf + 14, 0xfffe); - write16(buf + 16, 0x0dff); // move $15, $31 + memset(Buf, 0, PltHeaderSize); + + write16(Buf, isMipsR6() ? 0x7860 : 0x7980); // addiupc v1, (GOTPLT) - . + write16(Buf + 4, 0xff23); // lw $25, 0($3) + write16(Buf + 8, 0x0535); // subu16 $2, $2, $3 + write16(Buf + 10, 0x2525); // srl16 $2, $2, 2 + write16(Buf + 12, 0x3302); // addiu $24, $2, -2 + write16(Buf + 14, 0xfffe); + write16(Buf + 16, 0x0dff); // move $15, $31 if (isMipsR6()) { - write16(buf + 18, 0x0f83); // move $28, $3 - write16(buf + 20, 0x472b); // jalrc $25 - write16(buf + 22, 0x0c00); // nop - relocateOne(buf, R_MICROMIPS_PC19_S2, gotPlt - plt); + write16(Buf + 18, 0x0f83); // move $28, $3 + write16(Buf + 20, 0x472b); // jalrc $25 + write16(Buf + 22, 0x0c00); // nop + relocateOne(Buf, R_MICROMIPS_PC19_S2, GotPlt - Plt); } else { - write16(buf + 18, 0x45f9); // jalrc $25 - write16(buf + 20, 0x0f83); // move $28, $3 - write16(buf + 22, 0x0c00); // nop - relocateOne(buf, R_MICROMIPS_PC23_S2, gotPlt - plt); + write16(Buf + 18, 0x45f9); // jalrc $25 + write16(Buf + 20, 0x0f83); // move $28, $3 + write16(Buf + 22, 0x0c00); // nop + relocateOne(Buf, R_MICROMIPS_PC23_S2, GotPlt - Plt); } return; } - if (config->mipsN32Abi) { - write32(buf, 0x3c0e0000); // lui $14, %hi(&GOTPLT[0]) - write32(buf + 4, 0x8dd90000); // lw $25, %lo(&GOTPLT[0])($14) - write32(buf + 8, 0x25ce0000); // addiu $14, $14, %lo(&GOTPLT[0]) - write32(buf + 12, 0x030ec023); // subu $24, $24, $14 - write32(buf + 16, 0x03e07825); // move $15, $31 - write32(buf + 20, 0x0018c082); // srl $24, $24, 2 + if (Config->MipsN32Abi) { + write32(Buf, 0x3c0e0000); // lui $14, %hi(&GOTPLT[0]) + write32(Buf + 4, 0x8dd90000); // lw $25, %lo(&GOTPLT[0])($14) + write32(Buf + 8, 0x25ce0000); // addiu $14, $14, %lo(&GOTPLT[0]) + write32(Buf + 12, 0x030ec023); // subu $24, $24, $14 + write32(Buf + 16, 0x03e07825); // move $15, $31 + write32(Buf + 20, 0x0018c082); // srl $24, $24, 2 } else if (ELFT::Is64Bits) { - write32(buf, 0x3c0e0000); // lui $14, %hi(&GOTPLT[0]) - write32(buf + 4, 0xddd90000); // ld $25, %lo(&GOTPLT[0])($14) - write32(buf + 8, 0x25ce0000); // addiu $14, $14, %lo(&GOTPLT[0]) - write32(buf + 12, 0x030ec023); // subu $24, $24, $14 - write32(buf + 16, 0x03e07825); // move $15, $31 - write32(buf + 20, 0x0018c0c2); // srl $24, $24, 3 + write32(Buf, 0x3c0e0000); // lui $14, %hi(&GOTPLT[0]) + write32(Buf + 4, 0xddd90000); // ld $25, %lo(&GOTPLT[0])($14) + write32(Buf + 8, 0x25ce0000); // addiu $14, $14, %lo(&GOTPLT[0]) + write32(Buf + 12, 0x030ec023); // subu $24, $24, $14 + write32(Buf + 16, 0x03e07825); // move $15, $31 + write32(Buf + 20, 0x0018c0c2); // srl $24, $24, 3 } else { - write32(buf, 0x3c1c0000); // lui $28, %hi(&GOTPLT[0]) - write32(buf + 4, 0x8f990000); // lw $25, %lo(&GOTPLT[0])($28) - write32(buf + 8, 0x279c0000); // addiu $28, $28, %lo(&GOTPLT[0]) - write32(buf + 12, 0x031cc023); // subu $24, $24, $28 - write32(buf + 16, 0x03e07825); // move $15, $31 - write32(buf + 20, 0x0018c082); // srl $24, $24, 2 + write32(Buf, 0x3c1c0000); // lui $28, %hi(&GOTPLT[0]) + write32(Buf + 4, 0x8f990000); // lw $25, %lo(&GOTPLT[0])($28) + write32(Buf + 8, 0x279c0000); // addiu $28, $28, %lo(&GOTPLT[0]) + write32(Buf + 12, 0x031cc023); // subu $24, $24, $28 + write32(Buf + 16, 0x03e07825); // move $15, $31 + write32(Buf + 20, 0x0018c082); // srl $24, $24, 2 } - uint32_t jalrInst = config->zHazardplt ? 0x0320fc09 : 0x0320f809; - write32(buf + 24, jalrInst); // jalr.hb $25 or jalr $25 - write32(buf + 28, 0x2718fffe); // subu $24, $24, 2 + uint32_t JalrInst = Config->ZHazardplt ? 0x0320fc09 : 0x0320f809; + write32(Buf + 24, JalrInst); // jalr.hb $25 or jalr $25 + write32(Buf + 28, 0x2718fffe); // subu $24, $24, 2 - uint64_t gotPlt = in.gotPlt->getVA(); - writeValue(buf, gotPlt + 0x8000, 16, 16); - writeValue(buf + 4, gotPlt, 16, 0); - writeValue(buf + 8, gotPlt, 16, 0); + uint64_t GotPlt = In.GotPlt->getVA(); + writeValue(Buf, GotPlt + 0x8000, 16, 16); + writeValue(Buf + 4, GotPlt, 16, 0); + writeValue(Buf + 8, GotPlt, 16, 0); } template -void MIPS::writePlt(uint8_t *buf, uint64_t gotPltEntryAddr, - uint64_t pltEntryAddr, int32_t index, - unsigned relOff) const { - const endianness e = ELFT::TargetEndianness; +void MIPS::writePlt(uint8_t *Buf, uint64_t GotPltEntryAddr, + uint64_t PltEntryAddr, int32_t Index, + unsigned RelOff) const { + const endianness E = ELFT::TargetEndianness; if (isMicroMips()) { // Overwrite trap instructions written by Writer::writeTrapInstr. - memset(buf, 0, pltEntrySize); + memset(Buf, 0, PltEntrySize); if (isMipsR6()) { - write16(buf, 0x7840); // addiupc $2, (GOTPLT) - . - write16(buf + 4, 0xff22); // lw $25, 0($2) - write16(buf + 8, 0x0f02); // move $24, $2 - write16(buf + 10, 0x4723); // jrc $25 / jr16 $25 - relocateOne(buf, R_MICROMIPS_PC19_S2, gotPltEntryAddr - pltEntryAddr); + write16(Buf, 0x7840); // addiupc $2, (GOTPLT) - . + write16(Buf + 4, 0xff22); // lw $25, 0($2) + write16(Buf + 8, 0x0f02); // move $24, $2 + write16(Buf + 10, 0x4723); // jrc $25 / jr16 $25 + relocateOne(Buf, R_MICROMIPS_PC19_S2, GotPltEntryAddr - PltEntryAddr); } else { - write16(buf, 0x7900); // addiupc $2, (GOTPLT) - . - write16(buf + 4, 0xff22); // lw $25, 0($2) - write16(buf + 8, 0x4599); // jrc $25 / jr16 $25 - write16(buf + 10, 0x0f02); // move $24, $2 - relocateOne(buf, R_MICROMIPS_PC23_S2, gotPltEntryAddr - pltEntryAddr); + write16(Buf, 0x7900); // addiupc $2, (GOTPLT) - . + write16(Buf + 4, 0xff22); // lw $25, 0($2) + write16(Buf + 8, 0x4599); // jrc $25 / jr16 $25 + write16(Buf + 10, 0x0f02); // move $24, $2 + relocateOne(Buf, R_MICROMIPS_PC23_S2, GotPltEntryAddr - PltEntryAddr); } return; } - uint32_t loadInst = ELFT::Is64Bits ? 0xddf90000 : 0x8df90000; - uint32_t jrInst = isMipsR6() ? (config->zHazardplt ? 0x03200409 : 0x03200009) - : (config->zHazardplt ? 0x03200408 : 0x03200008); - uint32_t addInst = ELFT::Is64Bits ? 0x65f80000 : 0x25f80000; - - write32(buf, 0x3c0f0000); // lui $15, %hi(.got.plt entry) - write32(buf + 4, loadInst); // l[wd] $25, %lo(.got.plt entry)($15) - write32(buf + 8, jrInst); // jr $25 / jr.hb $25 - write32(buf + 12, addInst); // [d]addiu $24, $15, %lo(.got.plt entry) - writeValue(buf, gotPltEntryAddr + 0x8000, 16, 16); - writeValue(buf + 4, gotPltEntryAddr, 16, 0); - writeValue(buf + 12, gotPltEntryAddr, 16, 0); + uint32_t LoadInst = ELFT::Is64Bits ? 0xddf90000 : 0x8df90000; + uint32_t JrInst = isMipsR6() ? (Config->ZHazardplt ? 0x03200409 : 0x03200009) + : (Config->ZHazardplt ? 0x03200408 : 0x03200008); + uint32_t AddInst = ELFT::Is64Bits ? 0x65f80000 : 0x25f80000; + + write32(Buf, 0x3c0f0000); // lui $15, %hi(.got.plt entry) + write32(Buf + 4, LoadInst); // l[wd] $25, %lo(.got.plt entry)($15) + write32(Buf + 8, JrInst); // jr $25 / jr.hb $25 + write32(Buf + 12, AddInst); // [d]addiu $24, $15, %lo(.got.plt entry) + writeValue(Buf, GotPltEntryAddr + 0x8000, 16, 16); + writeValue(Buf + 4, GotPltEntryAddr, 16, 0); + writeValue(Buf + 12, GotPltEntryAddr, 16, 0); } template -bool MIPS::needsThunk(RelExpr expr, RelType type, const InputFile *file, - uint64_t branchAddr, const Symbol &s) const { +bool MIPS::needsThunk(RelExpr Expr, RelType Type, const InputFile *File, + uint64_t BranchAddr, const Symbol &S) const { // Any MIPS PIC code function is invoked with its address in register $t9. // So if we have a branch instruction from non-PIC code to the PIC one // we cannot make the jump directly and need to create a small stubs // to save the target function address. // See page 3-38 ftp://www.linux-mips.org/pub/linux/mips/doc/ABI/mipsabi.pdf - if (type != R_MIPS_26 && type != R_MIPS_PC26_S2 && - type != R_MICROMIPS_26_S1 && type != R_MICROMIPS_PC26_S1) + if (Type != R_MIPS_26 && Type != R_MIPS_PC26_S2 && + Type != R_MICROMIPS_26_S1 && Type != R_MICROMIPS_PC26_S1) return false; - auto *f = dyn_cast_or_null>(file); - if (!f) + auto *F = dyn_cast_or_null>(File); + if (!F) return false; // If current file has PIC code, LA25 stub is not required. - if (f->getObj().getHeader()->e_flags & EF_MIPS_PIC) + if (F->getObj().getHeader()->e_flags & EF_MIPS_PIC) return false; - auto *d = dyn_cast(&s); + auto *D = dyn_cast(&S); // LA25 is required if target file has PIC code // or target symbol is a PIC symbol. - return d && isMipsPIC(d); + return D && isMipsPIC(D); } template -int64_t MIPS::getImplicitAddend(const uint8_t *buf, RelType type) const { - const endianness e = ELFT::TargetEndianness; - switch (type) { +int64_t MIPS::getImplicitAddend(const uint8_t *Buf, RelType Type) const { + const endianness E = ELFT::TargetEndianness; + switch (Type) { case R_MIPS_32: case R_MIPS_GPREL32: case R_MIPS_TLS_DTPREL32: case R_MIPS_TLS_TPREL32: - return SignExtend64<32>(read32(buf)); + return SignExtend64<32>(read32(Buf)); case R_MIPS_26: // FIXME (simon): If the relocation target symbol is not a PLT entry // we should use another expression for calculation: // ((A << 2) | (P & 0xf0000000)) >> 2 - return SignExtend64<28>(read32(buf) << 2); + return SignExtend64<28>(read32(Buf) << 2); case R_MIPS_GOT16: case R_MIPS_HI16: case R_MIPS_PCHI16: - return SignExtend64<16>(read32(buf)) << 16; + return SignExtend64<16>(read32(Buf)) << 16; case R_MIPS_GPREL16: case R_MIPS_LO16: case R_MIPS_PCLO16: @@ -390,54 +389,54 @@ int64_t MIPS::getImplicitAddend(const uint8_t *buf, RelType type) const { case R_MIPS_TLS_DTPREL_LO16: case R_MIPS_TLS_TPREL_HI16: case R_MIPS_TLS_TPREL_LO16: - return SignExtend64<16>(read32(buf)); + return SignExtend64<16>(read32(Buf)); case R_MICROMIPS_GOT16: case R_MICROMIPS_HI16: - return SignExtend64<16>(readShuffle(buf)) << 16; + return SignExtend64<16>(readShuffle(Buf)) << 16; case R_MICROMIPS_GPREL16: case R_MICROMIPS_LO16: case R_MICROMIPS_TLS_DTPREL_HI16: case R_MICROMIPS_TLS_DTPREL_LO16: case R_MICROMIPS_TLS_TPREL_HI16: case R_MICROMIPS_TLS_TPREL_LO16: - return SignExtend64<16>(readShuffle(buf)); + return SignExtend64<16>(readShuffle(Buf)); case R_MICROMIPS_GPREL7_S2: - return SignExtend64<9>(readShuffle(buf) << 2); + return SignExtend64<9>(readShuffle(Buf) << 2); case R_MIPS_PC16: - return SignExtend64<18>(read32(buf) << 2); + return SignExtend64<18>(read32(Buf) << 2); case R_MIPS_PC19_S2: - return SignExtend64<21>(read32(buf) << 2); + return SignExtend64<21>(read32(Buf) << 2); case R_MIPS_PC21_S2: - return SignExtend64<23>(read32(buf) << 2); + return SignExtend64<23>(read32(Buf) << 2); case R_MIPS_PC26_S2: - return SignExtend64<28>(read32(buf) << 2); + return SignExtend64<28>(read32(Buf) << 2); case R_MIPS_PC32: - return SignExtend64<32>(read32(buf)); + return SignExtend64<32>(read32(Buf)); case R_MICROMIPS_26_S1: - return SignExtend64<27>(readShuffle(buf) << 1); + return SignExtend64<27>(readShuffle(Buf) << 1); case R_MICROMIPS_PC7_S1: - return SignExtend64<8>(read16(buf) << 1); + return SignExtend64<8>(read16(Buf) << 1); case R_MICROMIPS_PC10_S1: - return SignExtend64<11>(read16(buf) << 1); + return SignExtend64<11>(read16(Buf) << 1); case R_MICROMIPS_PC16_S1: - return SignExtend64<17>(readShuffle(buf) << 1); + return SignExtend64<17>(readShuffle(Buf) << 1); case R_MICROMIPS_PC18_S3: - return SignExtend64<21>(readShuffle(buf) << 3); + return SignExtend64<21>(readShuffle(Buf) << 3); case R_MICROMIPS_PC19_S2: - return SignExtend64<21>(readShuffle(buf) << 2); + return SignExtend64<21>(readShuffle(Buf) << 2); case R_MICROMIPS_PC21_S1: - return SignExtend64<22>(readShuffle(buf) << 1); + return SignExtend64<22>(readShuffle(Buf) << 1); case R_MICROMIPS_PC23_S2: - return SignExtend64<25>(readShuffle(buf) << 2); + return SignExtend64<25>(readShuffle(Buf) << 2); case R_MICROMIPS_PC26_S1: - return SignExtend64<27>(readShuffle(buf) << 1); + return SignExtend64<27>(readShuffle(Buf) << 1); default: return 0; } } static std::pair -calculateMipsRelChain(uint8_t *loc, RelType type, uint64_t val) { +calculateMipsRelChain(uint8_t *Loc, RelType Type, uint64_t Val) { // MIPS N64 ABI packs multiple relocations into the single relocation // record. In general, all up to three relocations can have arbitrary // types. In fact, Clang and GCC uses only a few combinations. For now, @@ -450,57 +449,57 @@ calculateMipsRelChain(uint8_t *loc, RelType type, uint64_t val) { // relocations used to modify result of the first one: extend it to // 64-bit, extract high or low part etc. For details, see part 2.9 Relocation // at the https://dmz-portal.mips.com/mw/images/8/82/007-4658-001.pdf - RelType type2 = (type >> 8) & 0xff; - RelType type3 = (type >> 16) & 0xff; - if (type2 == R_MIPS_NONE && type3 == R_MIPS_NONE) - return std::make_pair(type, val); - if (type2 == R_MIPS_64 && type3 == R_MIPS_NONE) - return std::make_pair(type2, val); - if (type2 == R_MIPS_SUB && (type3 == R_MIPS_HI16 || type3 == R_MIPS_LO16)) - return std::make_pair(type3, -val); - error(getErrorLocation(loc) + "unsupported relocations combination " + - Twine(type)); - return std::make_pair(type & 0xff, val); + RelType Type2 = (Type >> 8) & 0xff; + RelType Type3 = (Type >> 16) & 0xff; + if (Type2 == R_MIPS_NONE && Type3 == R_MIPS_NONE) + return std::make_pair(Type, Val); + if (Type2 == R_MIPS_64 && Type3 == R_MIPS_NONE) + return std::make_pair(Type2, Val); + if (Type2 == R_MIPS_SUB && (Type3 == R_MIPS_HI16 || Type3 == R_MIPS_LO16)) + return std::make_pair(Type3, -Val); + error(getErrorLocation(Loc) + "unsupported relocations combination " + + Twine(Type)); + return std::make_pair(Type & 0xff, Val); } -static bool isBranchReloc(RelType type) { - return type == R_MIPS_26 || type == R_MIPS_PC26_S2 || - type == R_MIPS_PC21_S2 || type == R_MIPS_PC16; +static bool isBranchReloc(RelType Type) { + return Type == R_MIPS_26 || Type == R_MIPS_PC26_S2 || + Type == R_MIPS_PC21_S2 || Type == R_MIPS_PC16; } -static bool isMicroBranchReloc(RelType type) { - return type == R_MICROMIPS_26_S1 || type == R_MICROMIPS_PC16_S1 || - type == R_MICROMIPS_PC10_S1 || type == R_MICROMIPS_PC7_S1; +static bool isMicroBranchReloc(RelType Type) { + return Type == R_MICROMIPS_26_S1 || Type == R_MICROMIPS_PC16_S1 || + Type == R_MICROMIPS_PC10_S1 || Type == R_MICROMIPS_PC7_S1; } template -static uint64_t fixupCrossModeJump(uint8_t *loc, RelType type, uint64_t val) { +static uint64_t fixupCrossModeJump(uint8_t *Loc, RelType Type, uint64_t Val) { // Here we need to detect jump/branch from regular MIPS code // to a microMIPS target and vice versa. In that cases jump // instructions need to be replaced by their "cross-mode" // equivalents. - const endianness e = ELFT::TargetEndianness; - bool isMicroTgt = val & 0x1; - bool isCrossJump = (isMicroTgt && isBranchReloc(type)) || - (!isMicroTgt && isMicroBranchReloc(type)); - if (!isCrossJump) - return val; - - switch (type) { + const endianness E = ELFT::TargetEndianness; + bool IsMicroTgt = Val & 0x1; + bool IsCrossJump = (IsMicroTgt && isBranchReloc(Type)) || + (!IsMicroTgt && isMicroBranchReloc(Type)); + if (!IsCrossJump) + return Val; + + switch (Type) { case R_MIPS_26: { - uint32_t inst = read32(loc) >> 26; - if (inst == 0x3 || inst == 0x1d) { // JAL or JALX - writeValue(loc, 0x1d << 26, 32, 0); - return val; + uint32_t Inst = read32(Loc) >> 26; + if (Inst == 0x3 || Inst == 0x1d) { // JAL or JALX + writeValue(Loc, 0x1d << 26, 32, 0); + return Val; } break; } case R_MICROMIPS_26_S1: { - uint32_t inst = readShuffle(loc) >> 26; - if (inst == 0x3d || inst == 0x3c) { // JAL32 or JALX32 - val >>= 1; - writeShuffleValue(loc, 0x3c << 26, 32, 0); - return val; + uint32_t Inst = readShuffle(Loc) >> 26; + if (Inst == 0x3d || Inst == 0x3c) { // JAL32 or JALX32 + Val >>= 1; + writeShuffleValue(Loc, 0x3c << 26, 32, 0); + return Val; } break; } @@ -516,63 +515,68 @@ static uint64_t fixupCrossModeJump(uint8_t *loc, RelType type, uint64_t val) { llvm_unreachable("unexpected jump/branch relocation"); } - error(getErrorLocation(loc) + + error(getErrorLocation(Loc) + "unsupported jump/branch instruction between ISA modes referenced by " + - toString(type) + " relocation"); - return val; + toString(Type) + " relocation"); + return Val; } template -void MIPS::relocateOne(uint8_t *loc, RelType type, uint64_t val) const { - const endianness e = ELFT::TargetEndianness; +void MIPS::relocateOne(uint8_t *Loc, RelType Type, uint64_t Val) const { + const endianness E = ELFT::TargetEndianness; - if (ELFT::Is64Bits || config->mipsN32Abi) - std::tie(type, val) = calculateMipsRelChain(loc, type, val); + if (ELFT::Is64Bits || Config->MipsN32Abi) + std::tie(Type, Val) = calculateMipsRelChain(Loc, Type, Val); // Detect cross-mode jump/branch and fix instruction. - val = fixupCrossModeJump(loc, type, val); + Val = fixupCrossModeJump(Loc, Type, Val); // Thread pointer and DRP offsets from the start of TLS data area. // https://www.linux-mips.org/wiki/NPTL - if (type == R_MIPS_TLS_DTPREL_HI16 || type == R_MIPS_TLS_DTPREL_LO16 || - type == R_MIPS_TLS_DTPREL32 || type == R_MIPS_TLS_DTPREL64 || - type == R_MICROMIPS_TLS_DTPREL_HI16 || - type == R_MICROMIPS_TLS_DTPREL_LO16) { - val -= 0x8000; + if (Type == R_MIPS_TLS_DTPREL_HI16 || Type == R_MIPS_TLS_DTPREL_LO16 || + Type == R_MIPS_TLS_DTPREL32 || Type == R_MIPS_TLS_DTPREL64 || + Type == R_MICROMIPS_TLS_DTPREL_HI16 || + Type == R_MICROMIPS_TLS_DTPREL_LO16) { + Val -= 0x8000; + } else if (Type == R_MIPS_TLS_TPREL_HI16 || Type == R_MIPS_TLS_TPREL_LO16 || + Type == R_MIPS_TLS_TPREL32 || Type == R_MIPS_TLS_TPREL64 || + Type == R_MICROMIPS_TLS_TPREL_HI16 || + Type == R_MICROMIPS_TLS_TPREL_LO16) { + Val -= 0x7000; } - switch (type) { + switch (Type) { case R_MIPS_32: case R_MIPS_GPREL32: case R_MIPS_TLS_DTPREL32: case R_MIPS_TLS_TPREL32: - write32(loc, val); + write32(Loc, Val); break; case R_MIPS_64: case R_MIPS_TLS_DTPREL64: case R_MIPS_TLS_TPREL64: - write64(loc, val); + write64(Loc, Val); break; case R_MIPS_26: - writeValue(loc, val, 26, 2); + writeValue(Loc, Val, 26, 2); break; case R_MIPS_GOT16: // The R_MIPS_GOT16 relocation's value in "relocatable" linking mode // is updated addend (not a GOT index). In that case write high 16 bits // to store a correct addend value. - if (config->relocatable) { - writeValue(loc, val + 0x8000, 16, 16); + if (Config->Relocatable) { + writeValue(Loc, Val + 0x8000, 16, 16); } else { - checkInt(loc, val, 16, type); - writeValue(loc, val, 16, 0); + checkInt(Loc, Val, 16, Type); + writeValue(Loc, Val, 16, 0); } break; case R_MICROMIPS_GOT16: - if (config->relocatable) { - writeShuffleValue(loc, val + 0x8000, 16, 16); + if (Config->Relocatable) { + writeShuffleValue(Loc, Val + 0x8000, 16, 16); } else { - checkInt(loc, val, 16, type); - writeShuffleValue(loc, val, 16, 0); + checkInt(Loc, Val, 16, Type); + writeShuffleValue(Loc, Val, 16, 0); } break; case R_MIPS_CALL16: @@ -582,7 +586,7 @@ void MIPS::relocateOne(uint8_t *loc, RelType type, uint64_t val) const { case R_MIPS_TLS_GD: case R_MIPS_TLS_GOTTPREL: case R_MIPS_TLS_LDM: - checkInt(loc, val, 16, type); + checkInt(Loc, Val, 16, Type); LLVM_FALLTHROUGH; case R_MIPS_CALL_LO16: case R_MIPS_GOT_LO16: @@ -591,13 +595,13 @@ void MIPS::relocateOne(uint8_t *loc, RelType type, uint64_t val) const { case R_MIPS_PCLO16: case R_MIPS_TLS_DTPREL_LO16: case R_MIPS_TLS_TPREL_LO16: - writeValue(loc, val, 16, 0); + writeValue(Loc, Val, 16, 0); break; case R_MICROMIPS_GPREL16: case R_MICROMIPS_TLS_GD: case R_MICROMIPS_TLS_LDM: - checkInt(loc, val, 16, type); - writeShuffleValue(loc, val, 16, 0); + checkInt(Loc, Val, 16, Type); + writeShuffleValue(Loc, Val, 16, 0); break; case R_MICROMIPS_CALL16: case R_MICROMIPS_CALL_LO16: @@ -605,11 +609,11 @@ void MIPS::relocateOne(uint8_t *loc, RelType type, uint64_t val) const { case R_MICROMIPS_TLS_DTPREL_LO16: case R_MICROMIPS_TLS_GOTTPREL: case R_MICROMIPS_TLS_TPREL_LO16: - writeShuffleValue(loc, val, 16, 0); + writeShuffleValue(Loc, Val, 16, 0); break; case R_MICROMIPS_GPREL7_S2: - checkInt(loc, val, 7, type); - writeShuffleValue(loc, val, 7, 2); + checkInt(Loc, Val, 7, Type); + writeShuffleValue(Loc, Val, 7, 2); break; case R_MIPS_CALL_HI16: case R_MIPS_GOT_HI16: @@ -617,113 +621,113 @@ void MIPS::relocateOne(uint8_t *loc, RelType type, uint64_t val) const { case R_MIPS_PCHI16: case R_MIPS_TLS_DTPREL_HI16: case R_MIPS_TLS_TPREL_HI16: - writeValue(loc, val + 0x8000, 16, 16); + writeValue(Loc, Val + 0x8000, 16, 16); break; case R_MICROMIPS_CALL_HI16: case R_MICROMIPS_GOT_HI16: case R_MICROMIPS_HI16: case R_MICROMIPS_TLS_DTPREL_HI16: case R_MICROMIPS_TLS_TPREL_HI16: - writeShuffleValue(loc, val + 0x8000, 16, 16); + writeShuffleValue(Loc, Val + 0x8000, 16, 16); break; case R_MIPS_HIGHER: - writeValue(loc, val + 0x80008000, 16, 32); + writeValue(Loc, Val + 0x80008000, 16, 32); break; case R_MIPS_HIGHEST: - writeValue(loc, val + 0x800080008000, 16, 48); + writeValue(Loc, Val + 0x800080008000, 16, 48); break; case R_MIPS_JALR: case R_MICROMIPS_JALR: // Ignore this optimization relocation for now break; case R_MIPS_PC16: - checkAlignment(loc, val, 4, type); - checkInt(loc, val, 18, type); - writeValue(loc, val, 16, 2); + checkAlignment(Loc, Val, 4, Type); + checkInt(Loc, Val, 18, Type); + writeValue(Loc, Val, 16, 2); break; case R_MIPS_PC19_S2: - checkAlignment(loc, val, 4, type); - checkInt(loc, val, 21, type); - writeValue(loc, val, 19, 2); + checkAlignment(Loc, Val, 4, Type); + checkInt(Loc, Val, 21, Type); + writeValue(Loc, Val, 19, 2); break; case R_MIPS_PC21_S2: - checkAlignment(loc, val, 4, type); - checkInt(loc, val, 23, type); - writeValue(loc, val, 21, 2); + checkAlignment(Loc, Val, 4, Type); + checkInt(Loc, Val, 23, Type); + writeValue(Loc, Val, 21, 2); break; case R_MIPS_PC26_S2: - checkAlignment(loc, val, 4, type); - checkInt(loc, val, 28, type); - writeValue(loc, val, 26, 2); + checkAlignment(Loc, Val, 4, Type); + checkInt(Loc, Val, 28, Type); + writeValue(Loc, Val, 26, 2); break; case R_MIPS_PC32: - writeValue(loc, val, 32, 0); + writeValue(Loc, Val, 32, 0); break; case R_MICROMIPS_26_S1: case R_MICROMIPS_PC26_S1: - checkInt(loc, val, 27, type); - writeShuffleValue(loc, val, 26, 1); + checkInt(Loc, Val, 27, Type); + writeShuffleValue(Loc, Val, 26, 1); break; case R_MICROMIPS_PC7_S1: - checkInt(loc, val, 8, type); - writeMicroRelocation16(loc, val, 7, 1); + checkInt(Loc, Val, 8, Type); + writeMicroRelocation16(Loc, Val, 7, 1); break; case R_MICROMIPS_PC10_S1: - checkInt(loc, val, 11, type); - writeMicroRelocation16(loc, val, 10, 1); + checkInt(Loc, Val, 11, Type); + writeMicroRelocation16(Loc, Val, 10, 1); break; case R_MICROMIPS_PC16_S1: - checkInt(loc, val, 17, type); - writeShuffleValue(loc, val, 16, 1); + checkInt(Loc, Val, 17, Type); + writeShuffleValue(Loc, Val, 16, 1); break; case R_MICROMIPS_PC18_S3: - checkInt(loc, val, 21, type); - writeShuffleValue(loc, val, 18, 3); + checkInt(Loc, Val, 21, Type); + writeShuffleValue(Loc, Val, 18, 3); break; case R_MICROMIPS_PC19_S2: - checkInt(loc, val, 21, type); - writeShuffleValue(loc, val, 19, 2); + checkInt(Loc, Val, 21, Type); + writeShuffleValue(Loc, Val, 19, 2); break; case R_MICROMIPS_PC21_S1: - checkInt(loc, val, 22, type); - writeShuffleValue(loc, val, 21, 1); + checkInt(Loc, Val, 22, Type); + writeShuffleValue(Loc, Val, 21, 1); break; case R_MICROMIPS_PC23_S2: - checkInt(loc, val, 25, type); - writeShuffleValue(loc, val, 23, 2); + checkInt(Loc, Val, 25, Type); + writeShuffleValue(Loc, Val, 23, 2); break; default: llvm_unreachable("unknown relocation"); } } -template bool MIPS::usesOnlyLowPageBits(RelType type) const { - return type == R_MIPS_LO16 || type == R_MIPS_GOT_OFST || - type == R_MICROMIPS_LO16; +template bool MIPS::usesOnlyLowPageBits(RelType Type) const { + return Type == R_MIPS_LO16 || Type == R_MIPS_GOT_OFST || + Type == R_MICROMIPS_LO16; } // Return true if the symbol is a PIC function. -template bool elf::isMipsPIC(const Defined *sym) { - if (!sym->isFunc()) +template bool elf::isMipsPIC(const Defined *Sym) { + if (!Sym->isFunc()) return false; - if (sym->stOther & STO_MIPS_PIC) + if (Sym->StOther & STO_MIPS_PIC) return true; - if (!sym->section) + if (!Sym->Section) return false; - ObjFile *file = - cast(sym->section)->template getFile(); - if (!file) + ObjFile *File = + cast(Sym->Section)->template getFile(); + if (!File) return false; - return file->getObj().getHeader()->e_flags & EF_MIPS_PIC; + return File->getObj().getHeader()->e_flags & EF_MIPS_PIC; } template TargetInfo *elf::getMipsTargetInfo() { - static MIPS target; - return ⌖ + static MIPS Target; + return &Target; } template TargetInfo *elf::getMipsTargetInfo(); diff --git a/lld/ELF/Arch/MipsArchTree.cpp b/lld/ELF/Arch/MipsArchTree.cpp index f745a87a263774..0d3ed41c8e178d 100644 --- a/lld/ELF/Arch/MipsArchTree.cpp +++ b/lld/ELF/Arch/MipsArchTree.cpp @@ -28,18 +28,18 @@ using namespace lld::elf; namespace { struct ArchTreeEdge { - uint32_t child; - uint32_t parent; + uint32_t Child; + uint32_t Parent; }; struct FileFlags { - InputFile *file; - uint32_t flags; + InputFile *File; + uint32_t Flags; }; } // namespace -static StringRef getAbiName(uint32_t flags) { - switch (flags) { +static StringRef getAbiName(uint32_t Flags) { + switch (Flags) { case 0: return "n64"; case EF_MIPS_ABI2: @@ -57,76 +57,76 @@ static StringRef getAbiName(uint32_t flags) { } } -static StringRef getNanName(bool isNan2008) { - return isNan2008 ? "2008" : "legacy"; +static StringRef getNanName(bool IsNan2008) { + return IsNan2008 ? "2008" : "legacy"; } -static StringRef getFpName(bool isFp64) { return isFp64 ? "64" : "32"; } +static StringRef getFpName(bool IsFp64) { return IsFp64 ? "64" : "32"; } -static void checkFlags(ArrayRef files) { - assert(!files.empty() && "expected non-empty file list"); +static void checkFlags(ArrayRef Files) { + assert(!Files.empty() && "expected non-empty file list"); - uint32_t abi = files[0].flags & (EF_MIPS_ABI | EF_MIPS_ABI2); - bool nan = files[0].flags & EF_MIPS_NAN2008; - bool fp = files[0].flags & EF_MIPS_FP64; + uint32_t ABI = Files[0].Flags & (EF_MIPS_ABI | EF_MIPS_ABI2); + bool Nan = Files[0].Flags & EF_MIPS_NAN2008; + bool Fp = Files[0].Flags & EF_MIPS_FP64; - for (const FileFlags &f : files) { - if (config->is64 && f.flags & EF_MIPS_MICROMIPS) - error(toString(f.file) + ": microMIPS 64-bit is not supported"); + for (const FileFlags &F : Files) { + if (Config->Is64 && F.Flags & EF_MIPS_MICROMIPS) + error(toString(F.File) + ": microMIPS 64-bit is not supported"); - uint32_t abi2 = f.flags & (EF_MIPS_ABI | EF_MIPS_ABI2); - if (abi != abi2) - error(toString(f.file) + ": ABI '" + getAbiName(abi2) + - "' is incompatible with target ABI '" + getAbiName(abi) + "'"); + uint32_t ABI2 = F.Flags & (EF_MIPS_ABI | EF_MIPS_ABI2); + if (ABI != ABI2) + error(toString(F.File) + ": ABI '" + getAbiName(ABI2) + + "' is incompatible with target ABI '" + getAbiName(ABI) + "'"); - bool nan2 = f.flags & EF_MIPS_NAN2008; - if (nan != nan2) - error(toString(f.file) + ": -mnan=" + getNanName(nan2) + - " is incompatible with target -mnan=" + getNanName(nan)); + bool Nan2 = F.Flags & EF_MIPS_NAN2008; + if (Nan != Nan2) + error(toString(F.File) + ": -mnan=" + getNanName(Nan2) + + " is incompatible with target -mnan=" + getNanName(Nan)); - bool fp2 = f.flags & EF_MIPS_FP64; - if (fp != fp2) - error(toString(f.file) + ": -mfp" + getFpName(fp2) + - " is incompatible with target -mfp" + getFpName(fp)); + bool Fp2 = F.Flags & EF_MIPS_FP64; + if (Fp != Fp2) + error(toString(F.File) + ": -mfp" + getFpName(Fp2) + + " is incompatible with target -mfp" + getFpName(Fp)); } } -static uint32_t getMiscFlags(ArrayRef files) { - uint32_t ret = 0; - for (const FileFlags &f : files) - ret |= f.flags & +static uint32_t getMiscFlags(ArrayRef Files) { + uint32_t Ret = 0; + for (const FileFlags &F : Files) + Ret |= F.Flags & (EF_MIPS_ABI | EF_MIPS_ABI2 | EF_MIPS_ARCH_ASE | EF_MIPS_NOREORDER | EF_MIPS_MICROMIPS | EF_MIPS_NAN2008 | EF_MIPS_32BITMODE); - return ret; + return Ret; } -static uint32_t getPicFlags(ArrayRef files) { +static uint32_t getPicFlags(ArrayRef Files) { // Check PIC/non-PIC compatibility. - bool isPic = files[0].flags & (EF_MIPS_PIC | EF_MIPS_CPIC); - for (const FileFlags &f : files.slice(1)) { - bool isPic2 = f.flags & (EF_MIPS_PIC | EF_MIPS_CPIC); - if (isPic && !isPic2) - warn(toString(f.file) + + bool IsPic = Files[0].Flags & (EF_MIPS_PIC | EF_MIPS_CPIC); + for (const FileFlags &F : Files.slice(1)) { + bool IsPic2 = F.Flags & (EF_MIPS_PIC | EF_MIPS_CPIC); + if (IsPic && !IsPic2) + warn(toString(F.File) + ": linking non-abicalls code with abicalls code " + - toString(files[0].file)); - if (!isPic && isPic2) - warn(toString(f.file) + + toString(Files[0].File)); + if (!IsPic && IsPic2) + warn(toString(F.File) + ": linking abicalls code with non-abicalls code " + - toString(files[0].file)); + toString(Files[0].File)); } // Compute the result PIC/non-PIC flag. - uint32_t ret = files[0].flags & (EF_MIPS_PIC | EF_MIPS_CPIC); - for (const FileFlags &f : files.slice(1)) - ret &= f.flags & (EF_MIPS_PIC | EF_MIPS_CPIC); + uint32_t Ret = Files[0].Flags & (EF_MIPS_PIC | EF_MIPS_CPIC); + for (const FileFlags &F : Files.slice(1)) + Ret &= F.Flags & (EF_MIPS_PIC | EF_MIPS_CPIC); // PIC code is inherently CPIC and may not set CPIC flag explicitly. - if (ret & EF_MIPS_PIC) - ret |= EF_MIPS_CPIC; - return ret; + if (Ret & EF_MIPS_PIC) + Ret |= EF_MIPS_CPIC; + return Ret; } -static ArchTreeEdge archTree[] = { +static ArchTreeEdge ArchTree[] = { // MIPS32R6 and MIPS64R6 are not compatible with other extensions // MIPS64R2 extensions. {EF_MIPS_ARCH_64R2 | EF_MIPS_MACH_OCTEON3, EF_MIPS_ARCH_64R2}, @@ -166,25 +166,25 @@ static ArchTreeEdge archTree[] = { {EF_MIPS_ARCH_2, EF_MIPS_ARCH_1}, }; -static bool isArchMatched(uint32_t newFlags, uint32_t res) { - if (newFlags == res) +static bool isArchMatched(uint32_t New, uint32_t Res) { + if (New == Res) return true; - if (newFlags == EF_MIPS_ARCH_32 && isArchMatched(EF_MIPS_ARCH_64, res)) + if (New == EF_MIPS_ARCH_32 && isArchMatched(EF_MIPS_ARCH_64, Res)) return true; - if (newFlags == EF_MIPS_ARCH_32R2 && isArchMatched(EF_MIPS_ARCH_64R2, res)) + if (New == EF_MIPS_ARCH_32R2 && isArchMatched(EF_MIPS_ARCH_64R2, Res)) return true; - for (const auto &edge : archTree) { - if (res == edge.child) { - res = edge.parent; - if (res == newFlags) + for (const auto &Edge : ArchTree) { + if (Res == Edge.Child) { + Res = Edge.Parent; + if (Res == New) return true; } } return false; } -static StringRef getMachName(uint32_t flags) { - switch (flags & EF_MIPS_MACH) { +static StringRef getMachName(uint32_t Flags) { + switch (Flags & EF_MIPS_MACH) { case EF_MIPS_MACH_NONE: return ""; case EF_MIPS_MACH_3900: @@ -228,8 +228,8 @@ static StringRef getMachName(uint32_t flags) { } } -static StringRef getArchName(uint32_t flags) { - switch (flags & EF_MIPS_ARCH) { +static StringRef getArchName(uint32_t Flags) { + switch (Flags & EF_MIPS_ARCH) { case EF_MIPS_ARCH_1: return "mips1"; case EF_MIPS_ARCH_2: @@ -257,12 +257,12 @@ static StringRef getArchName(uint32_t flags) { } } -static std::string getFullArchName(uint32_t flags) { - StringRef arch = getArchName(flags); - StringRef mach = getMachName(flags); - if (mach.empty()) - return arch.str(); - return (arch + " (" + mach + ")").str(); +static std::string getFullArchName(uint32_t Flags) { + StringRef Arch = getArchName(Flags); + StringRef Mach = getMachName(Flags); + if (Mach.empty()) + return Arch.str(); + return (Arch + " (" + Mach + ")").str(); } // There are (arguably too) many MIPS ISAs out there. Their relationships @@ -274,55 +274,55 @@ static std::string getFullArchName(uint32_t flags) { // Output file gets EF_MIPS_ARCH_2 flag. From the other side mips3 and mips32 // are incompatible because nor mips3 is a parent for misp32, nor mips32 // is a parent for mips3. -static uint32_t getArchFlags(ArrayRef files) { - uint32_t ret = files[0].flags & (EF_MIPS_ARCH | EF_MIPS_MACH); +static uint32_t getArchFlags(ArrayRef Files) { + uint32_t Ret = Files[0].Flags & (EF_MIPS_ARCH | EF_MIPS_MACH); - for (const FileFlags &f : files.slice(1)) { - uint32_t newFlags = f.flags & (EF_MIPS_ARCH | EF_MIPS_MACH); + for (const FileFlags &F : Files.slice(1)) { + uint32_t New = F.Flags & (EF_MIPS_ARCH | EF_MIPS_MACH); // Check ISA compatibility. - if (isArchMatched(newFlags, ret)) + if (isArchMatched(New, Ret)) continue; - if (!isArchMatched(ret, newFlags)) { - error("incompatible target ISA:\n>>> " + toString(files[0].file) + ": " + - getFullArchName(ret) + "\n>>> " + toString(f.file) + ": " + - getFullArchName(newFlags)); + if (!isArchMatched(Ret, New)) { + error("incompatible target ISA:\n>>> " + toString(Files[0].File) + ": " + + getFullArchName(Ret) + "\n>>> " + toString(F.File) + ": " + + getFullArchName(New)); return 0; } - ret = newFlags; + Ret = New; } - return ret; + return Ret; } template uint32_t elf::calcMipsEFlags() { - std::vector v; - for (InputFile *f : objectFiles) - v.push_back({f, cast>(f)->getObj().getHeader()->e_flags}); - if (v.empty()) + std::vector V; + for (InputFile *F : ObjectFiles) + V.push_back({F, cast>(F)->getObj().getHeader()->e_flags}); + if (V.empty()) return 0; - checkFlags(v); - return getMiscFlags(v) | getPicFlags(v) | getArchFlags(v); + checkFlags(V); + return getMiscFlags(V) | getPicFlags(V) | getArchFlags(V); } -static int compareMipsFpAbi(uint8_t fpA, uint8_t fpB) { - if (fpA == fpB) +static int compareMipsFpAbi(uint8_t FpA, uint8_t FpB) { + if (FpA == FpB) return 0; - if (fpB == Mips::Val_GNU_MIPS_ABI_FP_ANY) + if (FpB == Mips::Val_GNU_MIPS_ABI_FP_ANY) return 1; - if (fpB == Mips::Val_GNU_MIPS_ABI_FP_64A && - fpA == Mips::Val_GNU_MIPS_ABI_FP_64) + if (FpB == Mips::Val_GNU_MIPS_ABI_FP_64A && + FpA == Mips::Val_GNU_MIPS_ABI_FP_64) return 1; - if (fpB != Mips::Val_GNU_MIPS_ABI_FP_XX) + if (FpB != Mips::Val_GNU_MIPS_ABI_FP_XX) return -1; - if (fpA == Mips::Val_GNU_MIPS_ABI_FP_DOUBLE || - fpA == Mips::Val_GNU_MIPS_ABI_FP_64 || - fpA == Mips::Val_GNU_MIPS_ABI_FP_64A) + if (FpA == Mips::Val_GNU_MIPS_ABI_FP_DOUBLE || + FpA == Mips::Val_GNU_MIPS_ABI_FP_64 || + FpA == Mips::Val_GNU_MIPS_ABI_FP_64A) return 1; return -1; } -static StringRef getMipsFpAbiName(uint8_t fpAbi) { - switch (fpAbi) { +static StringRef getMipsFpAbiName(uint8_t FpAbi) { + switch (FpAbi) { case Mips::Val_GNU_MIPS_ABI_FP_ANY: return "any"; case Mips::Val_GNU_MIPS_ABI_FP_DOUBLE: @@ -344,43 +344,43 @@ static StringRef getMipsFpAbiName(uint8_t fpAbi) { } } -uint8_t elf::getMipsFpAbiFlag(uint8_t oldFlag, uint8_t newFlag, - StringRef fileName) { - if (compareMipsFpAbi(newFlag, oldFlag) >= 0) - return newFlag; - if (compareMipsFpAbi(oldFlag, newFlag) < 0) - error(fileName + ": floating point ABI '" + getMipsFpAbiName(newFlag) + +uint8_t elf::getMipsFpAbiFlag(uint8_t OldFlag, uint8_t NewFlag, + StringRef FileName) { + if (compareMipsFpAbi(NewFlag, OldFlag) >= 0) + return NewFlag; + if (compareMipsFpAbi(OldFlag, NewFlag) < 0) + error(FileName + ": floating point ABI '" + getMipsFpAbiName(NewFlag) + "' is incompatible with target floating point ABI '" + - getMipsFpAbiName(oldFlag) + "'"); - return oldFlag; + getMipsFpAbiName(OldFlag) + "'"); + return OldFlag; } -template static bool isN32Abi(const InputFile *f) { - if (auto *ef = dyn_cast(f)) - return ef->template getObj().getHeader()->e_flags & EF_MIPS_ABI2; +template static bool isN32Abi(const InputFile *F) { + if (auto *EF = dyn_cast(F)) + return EF->template getObj().getHeader()->e_flags & EF_MIPS_ABI2; return false; } -bool elf::isMipsN32Abi(const InputFile *f) { - switch (config->ekind) { +bool elf::isMipsN32Abi(const InputFile *F) { + switch (Config->EKind) { case ELF32LEKind: - return isN32Abi(f); + return isN32Abi(F); case ELF32BEKind: - return isN32Abi(f); + return isN32Abi(F); case ELF64LEKind: - return isN32Abi(f); + return isN32Abi(F); case ELF64BEKind: - return isN32Abi(f); + return isN32Abi(F); default: llvm_unreachable("unknown Config->EKind"); } } -bool elf::isMicroMips() { return config->eflags & EF_MIPS_MICROMIPS; } +bool elf::isMicroMips() { return Config->EFlags & EF_MIPS_MICROMIPS; } bool elf::isMipsR6() { - uint32_t arch = config->eflags & EF_MIPS_ARCH; - return arch == EF_MIPS_ARCH_32R6 || arch == EF_MIPS_ARCH_64R6; + uint32_t Arch = Config->EFlags & EF_MIPS_ARCH; + return Arch == EF_MIPS_ARCH_32R6 || Arch == EF_MIPS_ARCH_64R6; } template uint32_t elf::calcMipsEFlags(); diff --git a/lld/ELF/Arch/PPC.cpp b/lld/ELF/Arch/PPC.cpp index cf4ad40499268c..de2c1ee7f9e118 100644 --- a/lld/ELF/Arch/PPC.cpp +++ b/lld/ELF/Arch/PPC.cpp @@ -23,45 +23,45 @@ namespace { class PPC final : public TargetInfo { public: PPC(); - RelExpr getRelExpr(RelType type, const Symbol &s, - const uint8_t *loc) const override; - RelType getDynRel(RelType type) const override; - void writeGotHeader(uint8_t *buf) const override; - void writePltHeader(uint8_t *buf) const override { + RelExpr getRelExpr(RelType Type, const Symbol &S, + const uint8_t *Loc) const override; + RelType getDynRel(RelType Type) const override; + void writeGotHeader(uint8_t *Buf) const override; + void writePltHeader(uint8_t *Buf) const override { llvm_unreachable("should call writePPC32GlinkSection() instead"); } - void writePlt(uint8_t *buf, uint64_t gotPltEntryAddr, uint64_t pltEntryAddr, - int32_t index, unsigned relOff) const override { + void writePlt(uint8_t *Buf, uint64_t GotPltEntryAddr, uint64_t PltEntryAddr, + int32_t Index, unsigned RelOff) const override { llvm_unreachable("should call writePPC32GlinkSection() instead"); } - void writeGotPlt(uint8_t *buf, const Symbol &s) const override; - bool needsThunk(RelExpr expr, RelType relocType, const InputFile *file, - uint64_t branchAddr, const Symbol &s) const override; + void writeGotPlt(uint8_t *Buf, const Symbol &S) const override; + bool needsThunk(RelExpr Expr, RelType RelocType, const InputFile *File, + uint64_t BranchAddr, const Symbol &S) const override; uint32_t getThunkSectionSpacing() const override; - bool inBranchRange(RelType type, uint64_t src, uint64_t dst) const override; - void relocateOne(uint8_t *loc, RelType type, uint64_t val) const override; - RelExpr adjustRelaxExpr(RelType type, const uint8_t *data, - RelExpr expr) const override; - int getTlsGdRelaxSkip(RelType type) const override; - void relaxTlsGdToIe(uint8_t *loc, RelType type, uint64_t val) const override; - void relaxTlsGdToLe(uint8_t *loc, RelType type, uint64_t val) const override; - void relaxTlsLdToLe(uint8_t *loc, RelType type, uint64_t val) const override; - void relaxTlsIeToLe(uint8_t *loc, RelType type, uint64_t val) const override; + bool inBranchRange(RelType Type, uint64_t Src, uint64_t Dst) const override; + void relocateOne(uint8_t *Loc, RelType Type, uint64_t Val) const override; + RelExpr adjustRelaxExpr(RelType Type, const uint8_t *Data, + RelExpr Expr) const override; + int getTlsGdRelaxSkip(RelType Type) const override; + void relaxTlsGdToIe(uint8_t *Loc, RelType Type, uint64_t Val) const override; + void relaxTlsGdToLe(uint8_t *Loc, RelType Type, uint64_t Val) const override; + void relaxTlsLdToLe(uint8_t *Loc, RelType Type, uint64_t Val) const override; + void relaxTlsIeToLe(uint8_t *Loc, RelType Type, uint64_t Val) const override; }; } // namespace -static uint16_t lo(uint32_t v) { return v; } -static uint16_t ha(uint32_t v) { return (v + 0x8000) >> 16; } +static uint16_t lo(uint32_t V) { return V; } +static uint16_t ha(uint32_t V) { return (V + 0x8000) >> 16; } -static uint32_t readFromHalf16(const uint8_t *loc) { - return read32(config->isLE ? loc : loc - 2); +static uint32_t readFromHalf16(const uint8_t *Loc) { + return read32(Config->IsLE ? Loc : Loc - 2); } -static void writeFromHalf16(uint8_t *loc, uint32_t insn) { - write32(config->isLE ? loc : loc - 2, insn); +static void writeFromHalf16(uint8_t *Loc, uint32_t Insn) { + write32(Config->IsLE ? Loc : Loc - 2, Insn); } -void elf::writePPC32GlinkSection(uint8_t *buf, size_t numEntries) { +void elf::writePPC32GlinkSection(uint8_t *Buf, size_t NumEntries) { // On PPC Secure PLT ABI, bl foo@plt jumps to a call stub, which loads an // absolute address from a specific .plt slot (usually called .got.plt on // other targets) and jumps there. @@ -72,131 +72,124 @@ void elf::writePPC32GlinkSection(uint8_t *buf, size_t numEntries) { // instruction in .glink, filled in by PPC::writeGotPlt(). // Write N `b PLTresolve` first. - for (size_t i = 0; i != numEntries; ++i) - write32(buf + 4 * i, 0x48000000 | 4 * (numEntries - i)); - buf += 4 * numEntries; + for (size_t I = 0; I != NumEntries; ++I) + write32(Buf + 4 * I, 0x48000000 | 4 * (NumEntries - I)); + Buf += 4 * NumEntries; // Then write PLTresolve(), which has two forms: PIC and non-PIC. PLTresolve() // computes the PLT index (by computing the distance from the landing b to // itself) and calls _dl_runtime_resolve() (in glibc). - uint32_t got = in.got->getVA(); - uint32_t glink = in.plt->getVA(); // VA of .glink - const uint8_t *end = buf + 64; - if (config->isPic) { - uint32_t afterBcl = in.plt->getSize() - target->pltHeaderSize + 12; - uint32_t gotBcl = got + 4 - (glink + afterBcl); - write32(buf + 0, 0x3d6b0000 | ha(afterBcl)); // addis r11,r11,1f-glink@ha - write32(buf + 4, 0x7c0802a6); // mflr r0 - write32(buf + 8, 0x429f0005); // bcl 20,30,.+4 - write32(buf + 12, 0x396b0000 | lo(afterBcl)); // 1: addi r11,r11,1b-.glink@l - write32(buf + 16, 0x7d8802a6); // mflr r12 - write32(buf + 20, 0x7c0803a6); // mtlr r0 - write32(buf + 24, 0x7d6c5850); // sub r11,r11,r12 - write32(buf + 28, 0x3d8c0000 | ha(gotBcl)); // addis 12,12,GOT+4-1b@ha - if (ha(gotBcl) == ha(gotBcl + 4)) { - write32(buf + 32, 0x800c0000 | lo(gotBcl)); // lwz r0,r12,GOT+4-1b@l(r12) - write32(buf + 36, - 0x818c0000 | lo(gotBcl + 4)); // lwz r12,r12,GOT+8-1b@l(r12) + uint32_t GOT = In.Got->getVA(); + uint32_t Glink = In.Plt->getVA(); // VA of .glink + const uint8_t *End = Buf + 64; + if (Config->Pic) { + uint32_t AfterBcl = In.Plt->getSize() - Target->PltHeaderSize + 12; + uint32_t GotBcl = GOT + 4 - (Glink + AfterBcl); + write32(Buf + 0, 0x3d6b0000 | ha(AfterBcl)); // addis r11,r11,1f-glink@ha + write32(Buf + 4, 0x7c0802a6); // mflr r0 + write32(Buf + 8, 0x429f0005); // bcl 20,30,.+4 + write32(Buf + 12, 0x396b0000 | lo(AfterBcl)); // 1: addi r11,r11,1b-.glink@l + write32(Buf + 16, 0x7d8802a6); // mflr r12 + write32(Buf + 20, 0x7c0803a6); // mtlr r0 + write32(Buf + 24, 0x7d6c5850); // sub r11,r11,r12 + write32(Buf + 28, 0x3d8c0000 | ha(GotBcl)); // addis 12,12,GOT+4-1b@ha + if (ha(GotBcl) == ha(GotBcl + 4)) { + write32(Buf + 32, 0x800c0000 | lo(GotBcl)); // lwz r0,r12,GOT+4-1b@l(r12) + write32(Buf + 36, + 0x818c0000 | lo(GotBcl + 4)); // lwz r12,r12,GOT+8-1b@l(r12) } else { - write32(buf + 32, 0x840c0000 | lo(gotBcl)); // lwzu r0,r12,GOT+4-1b@l(r12) - write32(buf + 36, 0x818c0000 | 4); // lwz r12,r12,4(r12) + write32(Buf + 32, 0x840c0000 | lo(GotBcl)); // lwzu r0,r12,GOT+4-1b@l(r12) + write32(Buf + 36, 0x818c0000 | 4); // lwz r12,r12,4(r12) } - write32(buf + 40, 0x7c0903a6); // mtctr 0 - write32(buf + 44, 0x7c0b5a14); // add r0,11,11 - write32(buf + 48, 0x7d605a14); // add r11,0,11 - write32(buf + 52, 0x4e800420); // bctr - buf += 56; + write32(Buf + 40, 0x7c0903a6); // mtctr 0 + write32(Buf + 44, 0x7c0b5a14); // add r0,11,11 + write32(Buf + 48, 0x7d605a14); // add r11,0,11 + write32(Buf + 52, 0x4e800420); // bctr + Buf += 56; } else { - write32(buf + 0, 0x3d800000 | ha(got + 4)); // lis r12,GOT+4@ha - write32(buf + 4, 0x3d6b0000 | ha(-glink)); // addis r11,r11,-Glink@ha - if (ha(got + 4) == ha(got + 8)) - write32(buf + 8, 0x800c0000 | lo(got + 4)); // lwz r0,GOT+4@l(r12) + write32(Buf + 0, 0x3d800000 | ha(GOT + 4)); // lis r12,GOT+4@ha + write32(Buf + 4, 0x3d6b0000 | ha(-Glink)); // addis r11,r11,-Glink@ha + if (ha(GOT + 4) == ha(GOT + 8)) + write32(Buf + 8, 0x800c0000 | lo(GOT + 4)); // lwz r0,GOT+4@l(r12) else - write32(buf + 8, 0x840c0000 | lo(got + 4)); // lwzu r0,GOT+4@l(r12) - write32(buf + 12, 0x396b0000 | lo(-glink)); // addi r11,r11,-Glink@l - write32(buf + 16, 0x7c0903a6); // mtctr r0 - write32(buf + 20, 0x7c0b5a14); // add r0,r11,r11 - if (ha(got + 4) == ha(got + 8)) - write32(buf + 24, 0x818c0000 | lo(got + 8)); // lwz r12,GOT+8@ha(r12) + write32(Buf + 8, 0x840c0000 | lo(GOT + 4)); // lwzu r0,GOT+4@l(r12) + write32(Buf + 12, 0x396b0000 | lo(-Glink)); // addi r11,r11,-Glink@l + write32(Buf + 16, 0x7c0903a6); // mtctr r0 + write32(Buf + 20, 0x7c0b5a14); // add r0,r11,r11 + if (ha(GOT + 4) == ha(GOT + 8)) + write32(Buf + 24, 0x818c0000 | lo(GOT + 8)); // lwz r12,GOT+8@ha(r12) else - write32(buf + 24, 0x818c0000 | 4); // lwz r12,4(r12) - write32(buf + 28, 0x7d605a14); // add r11,r0,r11 - write32(buf + 32, 0x4e800420); // bctr - buf += 36; + write32(Buf + 24, 0x818c0000 | 4); // lwz r12,4(r12) + write32(Buf + 28, 0x7d605a14); // add r11,r0,r11 + write32(Buf + 32, 0x4e800420); // bctr + Buf += 36; } // Pad with nop. They should not be executed. - for (; buf < end; buf += 4) - write32(buf, 0x60000000); + for (; Buf < End; Buf += 4) + write32(Buf, 0x60000000); } PPC::PPC() { - gotRel = R_PPC_GLOB_DAT; - noneRel = R_PPC_NONE; - pltRel = R_PPC_JMP_SLOT; - relativeRel = R_PPC_RELATIVE; - iRelativeRel = R_PPC_IRELATIVE; - symbolicRel = R_PPC_ADDR32; - gotBaseSymInGotPlt = false; - gotHeaderEntriesNum = 3; - gotPltHeaderEntriesNum = 0; - pltHeaderSize = 64; // size of PLTresolve in .glink - pltEntrySize = 4; + GotRel = R_PPC_GLOB_DAT; + NoneRel = R_PPC_NONE; + PltRel = R_PPC_JMP_SLOT; + RelativeRel = R_PPC_RELATIVE; + IRelativeRel = R_PPC_IRELATIVE; + SymbolicRel = R_PPC_ADDR32; + GotBaseSymInGotPlt = false; + GotHeaderEntriesNum = 3; + GotPltHeaderEntriesNum = 0; + PltHeaderSize = 64; // size of PLTresolve in .glink + PltEntrySize = 4; - needsThunks = true; + NeedsThunks = true; - tlsModuleIndexRel = R_PPC_DTPMOD32; - tlsOffsetRel = R_PPC_DTPREL32; - tlsGotRel = R_PPC_TPREL32; + TlsModuleIndexRel = R_PPC_DTPMOD32; + TlsOffsetRel = R_PPC_DTPREL32; + TlsGotRel = R_PPC_TPREL32; - defaultMaxPageSize = 65536; - defaultImageBase = 0x10000000; + DefaultMaxPageSize = 65536; + DefaultImageBase = 0x10000000; - write32(trapInstr.data(), 0x7fe00008); + write32(TrapInstr.data(), 0x7fe00008); } -void PPC::writeGotHeader(uint8_t *buf) const { +void PPC::writeGotHeader(uint8_t *Buf) const { // _GLOBAL_OFFSET_TABLE_[0] = _DYNAMIC // glibc stores _dl_runtime_resolve in _GLOBAL_OFFSET_TABLE_[1], // link_map in _GLOBAL_OFFSET_TABLE_[2]. - write32(buf, mainPart->dynamic->getVA()); + write32(Buf, Main->Dynamic->getVA()); } -void PPC::writeGotPlt(uint8_t *buf, const Symbol &s) const { +void PPC::writeGotPlt(uint8_t *Buf, const Symbol &S) const { // Address of the symbol resolver stub in .glink . - write32(buf, in.plt->getVA() + 4 * s.pltIndex); + write32(Buf, In.Plt->getVA() + 4 * S.PltIndex); } -bool PPC::needsThunk(RelExpr expr, RelType type, const InputFile *file, - uint64_t branchAddr, const Symbol &s) const { - if (type != R_PPC_REL24 && type != R_PPC_PLTREL24) +bool PPC::needsThunk(RelExpr Expr, RelType Type, const InputFile *File, + uint64_t BranchAddr, const Symbol &S) const { + if (Type != R_PPC_REL24 && Type != R_PPC_PLTREL24) return false; - if (s.isInPlt()) + if (S.isInPlt()) return true; - if (s.isUndefWeak()) + if (S.isUndefWeak()) return false; - return !(expr == R_PC && PPC::inBranchRange(type, branchAddr, s.getVA())); + return !(Expr == R_PC && PPC::inBranchRange(Type, BranchAddr, S.getVA())); } uint32_t PPC::getThunkSectionSpacing() const { return 0x2000000; } -bool PPC::inBranchRange(RelType type, uint64_t src, uint64_t dst) const { - uint64_t offset = dst - src; - if (type == R_PPC_REL24 || type == R_PPC_PLTREL24) - return isInt<26>(offset); +bool PPC::inBranchRange(RelType Type, uint64_t Src, uint64_t Dst) const { + uint64_t Offset = Dst - Src; + if (Type == R_PPC_REL24 || Type == R_PPC_PLTREL24) + return isInt<26>(Offset); llvm_unreachable("unsupported relocation type used in branch"); } -RelExpr PPC::getRelExpr(RelType type, const Symbol &s, - const uint8_t *loc) const { - switch (type) { - case R_PPC_NONE: - return R_NONE; - case R_PPC_ADDR16_HA: - case R_PPC_ADDR16_HI: - case R_PPC_ADDR16_LO: - case R_PPC_ADDR32: - return R_ABS; +RelExpr PPC::getRelExpr(RelType Type, const Symbol &S, + const uint8_t *Loc) const { + switch (Type) { case R_PPC_DTPREL16: case R_PPC_DTPREL16_HA: case R_PPC_DTPREL16_HI: @@ -234,51 +227,49 @@ RelExpr PPC::getRelExpr(RelType type, const Symbol &s, case R_PPC_TPREL16_HI: return R_TLS; default: - error(getErrorLocation(loc) + "unknown relocation (" + Twine(type) + - ") against symbol " + toString(s)); - return R_NONE; + return R_ABS; } } -RelType PPC::getDynRel(RelType type) const { - if (type == R_PPC_ADDR32) - return type; +RelType PPC::getDynRel(RelType Type) const { + if (Type == R_PPC_ADDR32) + return Type; return R_PPC_NONE; } -static std::pair fromDTPREL(RelType type, uint64_t val) { - uint64_t dtpBiasedVal = val - 0x8000; - switch (type) { +static std::pair fromDTPREL(RelType Type, uint64_t Val) { + uint64_t DTPBiasedVal = Val - 0x8000; + switch (Type) { case R_PPC_DTPREL16: - return {R_PPC64_ADDR16, dtpBiasedVal}; + return {R_PPC64_ADDR16, DTPBiasedVal}; case R_PPC_DTPREL16_HA: - return {R_PPC_ADDR16_HA, dtpBiasedVal}; + return {R_PPC_ADDR16_HA, DTPBiasedVal}; case R_PPC_DTPREL16_HI: - return {R_PPC_ADDR16_HI, dtpBiasedVal}; + return {R_PPC_ADDR16_HI, DTPBiasedVal}; case R_PPC_DTPREL16_LO: - return {R_PPC_ADDR16_LO, dtpBiasedVal}; + return {R_PPC_ADDR16_LO, DTPBiasedVal}; case R_PPC_DTPREL32: - return {R_PPC_ADDR32, dtpBiasedVal}; + return {R_PPC_ADDR32, DTPBiasedVal}; default: - return {type, val}; + return {Type, Val}; } } -void PPC::relocateOne(uint8_t *loc, RelType type, uint64_t val) const { - RelType newType; - std::tie(newType, val) = fromDTPREL(type, val); - switch (newType) { +void PPC::relocateOne(uint8_t *Loc, RelType Type, uint64_t Val) const { + RelType NewType; + std::tie(NewType, Val) = fromDTPREL(Type, Val); + switch (NewType) { case R_PPC_ADDR16: - checkIntUInt(loc, val, 16, type); - write16(loc, val); + checkIntUInt(Loc, Val, 16, Type); + write16(Loc, Val); break; case R_PPC_GOT16: case R_PPC_GOT_TLSGD16: case R_PPC_GOT_TLSLD16: case R_PPC_GOT_TPREL16: case R_PPC_TPREL16: - checkInt(loc, val, 16, type); - write16(loc, val); + checkInt(Loc, Val, 16, Type); + write16(Loc, Val); break; case R_PPC_ADDR16_HA: case R_PPC_DTPREL16_HA: @@ -287,7 +278,7 @@ void PPC::relocateOne(uint8_t *loc, RelType type, uint64_t val) const { case R_PPC_GOT_TPREL16_HA: case R_PPC_REL16_HA: case R_PPC_TPREL16_HA: - write16(loc, ha(val)); + write16(Loc, ha(Val)); break; case R_PPC_ADDR16_HI: case R_PPC_DTPREL16_HI: @@ -296,7 +287,7 @@ void PPC::relocateOne(uint8_t *loc, RelType type, uint64_t val) const { case R_PPC_GOT_TPREL16_HI: case R_PPC_REL16_HI: case R_PPC_TPREL16_HI: - write16(loc, val >> 16); + write16(Loc, Val >> 16); break; case R_PPC_ADDR16_LO: case R_PPC_DTPREL16_LO: @@ -305,43 +296,43 @@ void PPC::relocateOne(uint8_t *loc, RelType type, uint64_t val) const { case R_PPC_GOT_TPREL16_LO: case R_PPC_REL16_LO: case R_PPC_TPREL16_LO: - write16(loc, val); + write16(Loc, Val); break; case R_PPC_ADDR32: case R_PPC_REL32: - write32(loc, val); + write32(Loc, Val); break; case R_PPC_REL14: { - uint32_t mask = 0x0000FFFC; - checkInt(loc, val, 16, type); - checkAlignment(loc, val, 4, type); - write32(loc, (read32(loc) & ~mask) | (val & mask)); + uint32_t Mask = 0x0000FFFC; + checkInt(Loc, Val, 16, Type); + checkAlignment(Loc, Val, 4, Type); + write32(Loc, (read32(Loc) & ~Mask) | (Val & Mask)); break; } case R_PPC_REL24: case R_PPC_LOCAL24PC: case R_PPC_PLTREL24: { - uint32_t mask = 0x03FFFFFC; - checkInt(loc, val, 26, type); - checkAlignment(loc, val, 4, type); - write32(loc, (read32(loc) & ~mask) | (val & mask)); + uint32_t Mask = 0x03FFFFFC; + checkInt(Loc, Val, 26, Type); + checkAlignment(Loc, Val, 4, Type); + write32(Loc, (read32(Loc) & ~Mask) | (Val & Mask)); break; } default: - llvm_unreachable("unknown relocation"); + error(getErrorLocation(Loc) + "unrecognized relocation " + toString(Type)); } } -RelExpr PPC::adjustRelaxExpr(RelType type, const uint8_t *data, - RelExpr expr) const { - if (expr == R_RELAX_TLS_GD_TO_IE) +RelExpr PPC::adjustRelaxExpr(RelType Type, const uint8_t *Data, + RelExpr Expr) const { + if (Expr == R_RELAX_TLS_GD_TO_IE) return R_RELAX_TLS_GD_TO_IE_GOT_OFF; - if (expr == R_RELAX_TLS_LD_TO_LE) + if (Expr == R_RELAX_TLS_LD_TO_LE) return R_RELAX_TLS_LD_TO_LE_ABS; - return expr; + return Expr; } -int PPC::getTlsGdRelaxSkip(RelType type) const { +int PPC::getTlsGdRelaxSkip(RelType Type) const { // A __tls_get_addr call instruction is marked with 2 relocations: // // R_PPC_TLSGD / R_PPC_TLSLD: marker relocation @@ -350,84 +341,84 @@ int PPC::getTlsGdRelaxSkip(RelType type) const { // After the relaxation we no longer call __tls_get_addr and should skip both // relocations to not create a false dependence on __tls_get_addr being // defined. - if (type == R_PPC_TLSGD || type == R_PPC_TLSLD) + if (Type == R_PPC_TLSGD || Type == R_PPC_TLSLD) return 2; return 1; } -void PPC::relaxTlsGdToIe(uint8_t *loc, RelType type, uint64_t val) const { - switch (type) { +void PPC::relaxTlsGdToIe(uint8_t *Loc, RelType Type, uint64_t Val) const { + switch (Type) { case R_PPC_GOT_TLSGD16: { // addi rT, rA, x@got@tlsgd --> lwz rT, x@got@tprel(rA) - uint32_t insn = readFromHalf16(loc); - writeFromHalf16(loc, 0x80000000 | (insn & 0x03ff0000)); - relocateOne(loc, R_PPC_GOT_TPREL16, val); + uint32_t Insn = readFromHalf16(Loc); + writeFromHalf16(Loc, 0x80000000 | (Insn & 0x03ff0000)); + relocateOne(Loc, R_PPC_GOT_TPREL16, Val); break; } case R_PPC_TLSGD: // bl __tls_get_addr(x@tldgd) --> add r3, r3, r2 - write32(loc, 0x7c631214); + write32(Loc, 0x7c631214); break; default: llvm_unreachable("unsupported relocation for TLS GD to IE relaxation"); } } -void PPC::relaxTlsGdToLe(uint8_t *loc, RelType type, uint64_t val) const { - switch (type) { +void PPC::relaxTlsGdToLe(uint8_t *Loc, RelType Type, uint64_t Val) const { + switch (Type) { case R_PPC_GOT_TLSGD16: // addi r3, r31, x@got@tlsgd --> addis r3, r2, x@tprel@ha - writeFromHalf16(loc, 0x3c620000 | ha(val)); + writeFromHalf16(Loc, 0x3c620000 | ha(Val)); break; case R_PPC_TLSGD: // bl __tls_get_addr(x@tldgd) --> add r3, r3, x@tprel@l - write32(loc, 0x38630000 | lo(val)); + write32(Loc, 0x38630000 | lo(Val)); break; default: llvm_unreachable("unsupported relocation for TLS GD to LE relaxation"); } } -void PPC::relaxTlsLdToLe(uint8_t *loc, RelType type, uint64_t val) const { - switch (type) { +void PPC::relaxTlsLdToLe(uint8_t *Loc, RelType Type, uint64_t Val) const { + switch (Type) { case R_PPC_GOT_TLSLD16: // addi r3, rA, x@got@tlsgd --> addis r3, r2, 0 - writeFromHalf16(loc, 0x3c620000); + writeFromHalf16(Loc, 0x3c620000); break; case R_PPC_TLSLD: // r3+x@dtprel computes r3+x-0x8000, while we want it to compute r3+x@tprel // = r3+x-0x7000, so add 4096 to r3. // bl __tls_get_addr(x@tlsld) --> addi r3, r3, 4096 - write32(loc, 0x38631000); + write32(Loc, 0x38631000); break; case R_PPC_DTPREL16: case R_PPC_DTPREL16_HA: case R_PPC_DTPREL16_HI: case R_PPC_DTPREL16_LO: - relocateOne(loc, type, val); + relocateOne(Loc, Type, Val); break; default: llvm_unreachable("unsupported relocation for TLS LD to LE relaxation"); } } -void PPC::relaxTlsIeToLe(uint8_t *loc, RelType type, uint64_t val) const { - switch (type) { +void PPC::relaxTlsIeToLe(uint8_t *Loc, RelType Type, uint64_t Val) const { + switch (Type) { case R_PPC_GOT_TPREL16: { // lwz rT, x@got@tprel(rA) --> addis rT, r2, x@tprel@ha - uint32_t rt = readFromHalf16(loc) & 0x03e00000; - writeFromHalf16(loc, 0x3c020000 | rt | ha(val)); + uint32_t RT = readFromHalf16(Loc) & 0x03e00000; + writeFromHalf16(Loc, 0x3c020000 | RT | ha(Val)); break; } case R_PPC_TLS: { - uint32_t insn = read32(loc); - if (insn >> 26 != 31) + uint32_t Insn = read32(Loc); + if (Insn >> 26 != 31) error("unrecognized instruction for IE to LE R_PPC_TLS"); // addi rT, rT, x@tls --> addi rT, rT, x@tprel@l - uint32_t dFormOp = getPPCDFormOp((read32(loc) & 0x000007fe) >> 1); - if (dFormOp == 0) + uint32_t DFormOp = getPPCDFormOp((read32(Loc) & 0x000007fe) >> 1); + if (DFormOp == 0) error("unrecognized instruction for IE to LE R_PPC_TLS"); - write32(loc, (dFormOp << 26) | (insn & 0x03ff0000) | lo(val)); + write32(Loc, (DFormOp << 26) | (Insn & 0x03ff0000) | lo(Val)); break; } default: @@ -436,6 +427,6 @@ void PPC::relaxTlsIeToLe(uint8_t *loc, RelType type, uint64_t val) const { } TargetInfo *elf::getPPCTargetInfo() { - static PPC target; - return ⌖ + static PPC Target; + return &Target; } diff --git a/lld/ELF/Arch/PPC64.cpp b/lld/ELF/Arch/PPC64.cpp index 15ad8db4649ca7..4af935e8a80ea3 100644 --- a/lld/ELF/Arch/PPC64.cpp +++ b/lld/ELF/Arch/PPC64.cpp @@ -19,8 +19,8 @@ using namespace llvm::ELF; using namespace lld; using namespace lld::elf; -static uint64_t ppc64TocOffset = 0x8000; -static uint64_t dynamicThreadPointerOffset = 0x8000; +static uint64_t PPC64TocOffset = 0x8000; +static uint64_t DynamicThreadPointerOffset = 0x8000; // The instruction encoding of bits 21-30 from the ISA for the Xform and Dform // instructions that can be used as part of the initial exec TLS sequence. @@ -64,16 +64,16 @@ uint64_t elf::getPPC64TocBase() { // TOC starts where the first of these sections starts. We always create a // .got when we see a relocation that uses it, so for us the start is always // the .got. - uint64_t tocVA = in.got->getVA(); + uint64_t TocVA = In.Got->getVA(); // Per the ppc64-elf-linux ABI, The TOC base is TOC value plus 0x8000 // thus permitting a full 64 Kbytes segment. Note that the glibc startup // code (crt1.o) assumes that you can get from the TOC base to the // start of the .toc section with only a single (signed) 16-bit relocation. - return tocVA + ppc64TocOffset; + return TocVA + PPC64TocOffset; } -unsigned elf::getPPC64GlobalEntryToLocalEntryOffset(uint8_t stOther) { +unsigned elf::getPPC64GlobalEntryToLocalEntryOffset(uint8_t StOther) { // The offset is encoded into the 3 most significant bits of the st_other // field, with some special values described in section 3.4.1 of the ABI: // 0 --> Zero offset between the GEP and LEP, and the function does NOT use @@ -85,29 +85,29 @@ unsigned elf::getPPC64GlobalEntryToLocalEntryOffset(uint8_t stOther) { // 2 --> 2^2 = 4 bytes --> 1 instruction. // 6 --> 2^6 = 64 bytes --> 16 instructions. // 7 --> Reserved. - uint8_t gepToLep = (stOther >> 5) & 7; - if (gepToLep < 2) + uint8_t GepToLep = (StOther >> 5) & 7; + if (GepToLep < 2) return 0; // The value encoded in the st_other bits is the // log-base-2(offset). - if (gepToLep < 7) - return 1 << gepToLep; + if (GepToLep < 7) + return 1 << GepToLep; error("reserved value of 7 in the 3 most-significant-bits of st_other"); return 0; } -bool elf::isPPC64SmallCodeModelTocReloc(RelType type) { +bool elf::isPPC64SmallCodeModelTocReloc(RelType Type) { // The only small code model relocations that access the .toc section. - return type == R_PPC64_TOC16 || type == R_PPC64_TOC16_DS; + return Type == R_PPC64_TOC16 || Type == R_PPC64_TOC16_DS; } // Find the R_PPC64_ADDR64 in .rela.toc with matching offset. template static std::pair -getRelaTocSymAndAddend(InputSectionBase *tocSec, uint64_t offset) { - if (tocSec->numRelocations == 0) +getRelaTocSymAndAddend(InputSectionBase *TocSec, uint64_t Offset) { + if (TocSec->NumRelocations == 0) return {}; // .rela.toc contains exclusively R_PPC64_ADDR64 relocations sorted by @@ -119,16 +119,16 @@ getRelaTocSymAndAddend(InputSectionBase *tocSec, uint64_t offset) { // points to a relocation with larger r_offset. Do a linear probe then. // Constants are extremely uncommon in .toc and the extra number of array // accesses can be seen as a small constant. - ArrayRef relas = tocSec->template relas(); - uint64_t index = std::min(offset / 8, relas.size() - 1); + ArrayRef Relas = TocSec->template relas(); + uint64_t Index = std::min(Offset / 8, Relas.size() - 1); for (;;) { - if (relas[index].r_offset == offset) { - Symbol &sym = tocSec->getFile()->getRelocTargetSym(relas[index]); - return {dyn_cast(&sym), getAddend(relas[index])}; + if (Relas[Index].r_offset == Offset) { + Symbol &Sym = TocSec->getFile()->getRelocTargetSym(Relas[Index]); + return {dyn_cast(&Sym), getAddend(Relas[Index])}; } - if (relas[index].r_offset < offset || index == 0) + if (Relas[Index].r_offset < Offset || Index == 0) break; - --index; + --Index; } return {}; } @@ -153,39 +153,35 @@ getRelaTocSymAndAddend(InputSectionBase *tocSec, uint64_t offset) { // ld/lwa 3, 0(3) # load the value from the address // // Returns true if the relaxation is performed. -bool elf::tryRelaxPPC64TocIndirection(RelType type, const Relocation &rel, - uint8_t *bufLoc) { - assert(config->tocOptimize); - if (rel.addend < 0) +bool elf::tryRelaxPPC64TocIndirection(RelType Type, const Relocation &Rel, + uint8_t *BufLoc) { + assert(Config->TocOptimize); + if (Rel.Addend < 0) return false; // If the symbol is not the .toc section, this isn't a toc-indirection. - Defined *defSym = dyn_cast(rel.sym); - if (!defSym || !defSym->isSection() || defSym->section->name != ".toc") + Defined *DefSym = dyn_cast(Rel.Sym); + if (!DefSym || !DefSym->isSection() || DefSym->Section->Name != ".toc") return false; - Defined *d; - int64_t addend; - auto *tocISB = cast(defSym->section); - std::tie(d, addend) = - config->isLE ? getRelaTocSymAndAddend(tocISB, rel.addend) - : getRelaTocSymAndAddend(tocISB, rel.addend); + Defined *D; + int64_t Addend; + auto *TocISB = cast(DefSym->Section); + std::tie(D, Addend) = + Config->IsLE ? getRelaTocSymAndAddend(TocISB, Rel.Addend) + : getRelaTocSymAndAddend(TocISB, Rel.Addend); // Only non-preemptable defined symbols can be relaxed. - if (!d || d->isPreemptible) + if (!D || D->IsPreemptible) return false; - // R_PPC64_ADDR64 should have created a canonical PLT for the non-preemptable - // ifunc and changed its type to STT_FUNC. - assert(!d->isGnuIFunc()); - // Two instructions can materialize a 32-bit signed offset from the toc base. - uint64_t tocRelative = d->getVA(addend) - getPPC64TocBase(); - if (!isInt<32>(tocRelative)) + uint64_t TocRelative = D->getVA(Addend) - getPPC64TocBase(); + if (!isInt<32>(TocRelative)) return false; // Add PPC64TocOffset that will be subtracted by relocateOne(). - target->relaxGot(bufLoc, type, tocRelative + ppc64TocOffset); + Target->relaxGot(BufLoc, Type, TocRelative + PPC64TocOffset); return true; } @@ -193,30 +189,30 @@ namespace { class PPC64 final : public TargetInfo { public: PPC64(); - int getTlsGdRelaxSkip(RelType type) const override; + int getTlsGdRelaxSkip(RelType Type) const override; uint32_t calcEFlags() const override; - RelExpr getRelExpr(RelType type, const Symbol &s, - const uint8_t *loc) const override; - RelType getDynRel(RelType type) const override; - void writePltHeader(uint8_t *buf) const override; - void writePlt(uint8_t *buf, uint64_t gotPltEntryAddr, uint64_t pltEntryAddr, - int32_t index, unsigned relOff) const override; - void relocateOne(uint8_t *loc, RelType type, uint64_t val) const override; - void writeGotHeader(uint8_t *buf) const override; - bool needsThunk(RelExpr expr, RelType type, const InputFile *file, - uint64_t branchAddr, const Symbol &s) const override; + RelExpr getRelExpr(RelType Type, const Symbol &S, + const uint8_t *Loc) const override; + RelType getDynRel(RelType Type) const override; + void writePltHeader(uint8_t *Buf) const override; + void writePlt(uint8_t *Buf, uint64_t GotPltEntryAddr, uint64_t PltEntryAddr, + int32_t Index, unsigned RelOff) const override; + void relocateOne(uint8_t *Loc, RelType Type, uint64_t Val) const override; + void writeGotHeader(uint8_t *Buf) const override; + bool needsThunk(RelExpr Expr, RelType Type, const InputFile *File, + uint64_t BranchAddr, const Symbol &S) const override; uint32_t getThunkSectionSpacing() const override; - bool inBranchRange(RelType type, uint64_t src, uint64_t dst) const override; - RelExpr adjustRelaxExpr(RelType type, const uint8_t *data, - RelExpr expr) const override; - void relaxGot(uint8_t *loc, RelType type, uint64_t val) const override; - void relaxTlsGdToIe(uint8_t *loc, RelType type, uint64_t val) const override; - void relaxTlsGdToLe(uint8_t *loc, RelType type, uint64_t val) const override; - void relaxTlsLdToLe(uint8_t *loc, RelType type, uint64_t val) const override; - void relaxTlsIeToLe(uint8_t *loc, RelType type, uint64_t val) const override; - - bool adjustPrologueForCrossSplitStack(uint8_t *loc, uint8_t *end, - uint8_t stOther) const override; + bool inBranchRange(RelType Type, uint64_t Src, uint64_t Dst) const override; + RelExpr adjustRelaxExpr(RelType Type, const uint8_t *Data, + RelExpr Expr) const override; + void relaxGot(uint8_t *Loc, RelType Type, uint64_t Val) const override; + void relaxTlsGdToIe(uint8_t *Loc, RelType Type, uint64_t Val) const override; + void relaxTlsGdToLe(uint8_t *Loc, RelType Type, uint64_t Val) const override; + void relaxTlsLdToLe(uint8_t *Loc, RelType Type, uint64_t Val) const override; + void relaxTlsIeToLe(uint8_t *Loc, RelType Type, uint64_t Val) const override; + + bool adjustPrologueForCrossSplitStack(uint8_t *Loc, uint8_t *End, + uint8_t StOther) const override; }; } // namespace @@ -224,19 +220,19 @@ class PPC64 final : public TargetInfo { // #higher(value), #highera(value), #highest(value), and #highesta(value) // macros defined in section 4.5.1. Relocation Types of the PPC-elf64abi // document. -static uint16_t lo(uint64_t v) { return v; } -static uint16_t hi(uint64_t v) { return v >> 16; } -static uint16_t ha(uint64_t v) { return (v + 0x8000) >> 16; } -static uint16_t higher(uint64_t v) { return v >> 32; } -static uint16_t highera(uint64_t v) { return (v + 0x8000) >> 32; } -static uint16_t highest(uint64_t v) { return v >> 48; } -static uint16_t highesta(uint64_t v) { return (v + 0x8000) >> 48; } +static uint16_t lo(uint64_t V) { return V; } +static uint16_t hi(uint64_t V) { return V >> 16; } +static uint16_t ha(uint64_t V) { return (V + 0x8000) >> 16; } +static uint16_t higher(uint64_t V) { return V >> 32; } +static uint16_t highera(uint64_t V) { return (V + 0x8000) >> 32; } +static uint16_t highest(uint64_t V) { return V >> 48; } +static uint16_t highesta(uint64_t V) { return (V + 0x8000) >> 48; } // Extracts the 'PO' field of an instruction encoding. -static uint8_t getPrimaryOpCode(uint32_t encoding) { return (encoding >> 26); } +static uint8_t getPrimaryOpCode(uint32_t Encoding) { return (Encoding >> 26); } -static bool isDQFormInstruction(uint32_t encoding) { - switch (getPrimaryOpCode(encoding)) { +static bool isDQFormInstruction(uint32_t Encoding) { + switch (getPrimaryOpCode(Encoding)) { default: return false; case 56: @@ -246,12 +242,12 @@ static bool isDQFormInstruction(uint32_t encoding) { // There are both DS and DQ instruction forms with this primary opcode. // Namely `lxv` and `stxv` are the DQ-forms that use it. // The DS 'XO' bits being set to 01 is restricted to DQ form. - return (encoding & 3) == 0x1; + return (Encoding & 3) == 0x1; } } -static bool isInstructionUpdateForm(uint32_t encoding) { - switch (getPrimaryOpCode(encoding)) { +static bool isInstructionUpdateForm(uint32_t Encoding) { + switch (getPrimaryOpCode(Encoding)) { default: return false; case LBZU: @@ -270,7 +266,7 @@ static bool isInstructionUpdateForm(uint32_t encoding) { // between LD/LDU/LWA case LD: case STD: - return (encoding & 3) == 1; + return (Encoding & 3) == 1; } } @@ -279,38 +275,38 @@ static bool isInstructionUpdateForm(uint32_t encoding) { // pointer is pointing into the middle of the word we want to extract, and on // little-endian it is pointing to the start of the word. These 2 helpers are to // simplify reading and writing in that context. -static void writeFromHalf16(uint8_t *loc, uint32_t insn) { - write32(config->isLE ? loc : loc - 2, insn); +static void writeFromHalf16(uint8_t *Loc, uint32_t Insn) { + write32(Config->IsLE ? Loc : Loc - 2, Insn); } -static uint32_t readFromHalf16(const uint8_t *loc) { - return read32(config->isLE ? loc : loc - 2); +static uint32_t readFromHalf16(const uint8_t *Loc) { + return read32(Config->IsLE ? Loc : Loc - 2); } PPC64::PPC64() { - gotRel = R_PPC64_GLOB_DAT; - noneRel = R_PPC64_NONE; - pltRel = R_PPC64_JMP_SLOT; - relativeRel = R_PPC64_RELATIVE; - iRelativeRel = R_PPC64_IRELATIVE; - symbolicRel = R_PPC64_ADDR64; - pltEntrySize = 4; - gotBaseSymInGotPlt = false; - gotHeaderEntriesNum = 1; - gotPltHeaderEntriesNum = 2; - pltHeaderSize = 60; - needsThunks = true; - - tlsModuleIndexRel = R_PPC64_DTPMOD64; - tlsOffsetRel = R_PPC64_DTPREL64; - - tlsGotRel = R_PPC64_TPREL64; - - needsMoreStackNonSplit = false; + GotRel = R_PPC64_GLOB_DAT; + NoneRel = R_PPC64_NONE; + PltRel = R_PPC64_JMP_SLOT; + RelativeRel = R_PPC64_RELATIVE; + IRelativeRel = R_PPC64_IRELATIVE; + SymbolicRel = R_PPC64_ADDR64; + PltEntrySize = 4; + GotBaseSymInGotPlt = false; + GotHeaderEntriesNum = 1; + GotPltHeaderEntriesNum = 2; + PltHeaderSize = 60; + NeedsThunks = true; + + TlsModuleIndexRel = R_PPC64_DTPMOD64; + TlsOffsetRel = R_PPC64_DTPREL64; + + TlsGotRel = R_PPC64_TPREL64; + + NeedsMoreStackNonSplit = false; // We need 64K pages (at least under glibc/Linux, the loader won't // set different permissions on a finer granularity than that). - defaultMaxPageSize = 65536; + DefaultMaxPageSize = 65536; // The PPC64 ELF ABI v1 spec, says: // @@ -320,12 +316,12 @@ PPC64::PPC64() { // // And because the lowest non-zero 256M boundary is 0x10000000, PPC64 linkers // use 0x10000000 as the starting address. - defaultImageBase = 0x10000000; + DefaultImageBase = 0x10000000; - write32(trapInstr.data(), 0x7fe00008); + write32(TrapInstr.data(), 0x7fe00008); } -int PPC64::getTlsGdRelaxSkip(RelType type) const { +int PPC64::getTlsGdRelaxSkip(RelType Type) const { // A __tls_get_addr call instruction is marked with 2 relocations: // // R_PPC64_TLSGD / R_PPC64_TLSLD: marker relocation @@ -334,44 +330,44 @@ int PPC64::getTlsGdRelaxSkip(RelType type) const { // After the relaxation we no longer call __tls_get_addr and should skip both // relocations to not create a false dependence on __tls_get_addr being // defined. - if (type == R_PPC64_TLSGD || type == R_PPC64_TLSLD) + if (Type == R_PPC64_TLSGD || Type == R_PPC64_TLSLD) return 2; return 1; } -static uint32_t getEFlags(InputFile *file) { - if (config->ekind == ELF64BEKind) - return cast>(file)->getObj().getHeader()->e_flags; - return cast>(file)->getObj().getHeader()->e_flags; +static uint32_t getEFlags(InputFile *File) { + if (Config->EKind == ELF64BEKind) + return cast>(File)->getObj().getHeader()->e_flags; + return cast>(File)->getObj().getHeader()->e_flags; } // This file implements v2 ABI. This function makes sure that all // object files have v2 or an unspecified version as an ABI version. uint32_t PPC64::calcEFlags() const { - for (InputFile *f : objectFiles) { - uint32_t flag = getEFlags(f); - if (flag == 1) - error(toString(f) + ": ABI version 1 is not supported"); - else if (flag > 2) - error(toString(f) + ": unrecognized e_flags: " + Twine(flag)); + for (InputFile *F : ObjectFiles) { + uint32_t Flag = getEFlags(F); + if (Flag == 1) + error(toString(F) + ": ABI version 1 is not supported"); + else if (Flag > 2) + error(toString(F) + ": unrecognized e_flags: " + Twine(Flag)); } return 2; } -void PPC64::relaxGot(uint8_t *loc, RelType type, uint64_t val) const { - switch (type) { +void PPC64::relaxGot(uint8_t *Loc, RelType Type, uint64_t Val) const { + switch (Type) { case R_PPC64_TOC16_HA: // Convert "addis reg, 2, .LC0@toc@h" to "addis reg, 2, var@toc@h" or "nop". - relocateOne(loc, type, val); + relocateOne(Loc, Type, Val); break; case R_PPC64_TOC16_LO_DS: { // Convert "ld reg, .LC0@toc@l(reg)" to "addi reg, reg, var@toc@l" or // "addi reg, 2, var@toc". - uint32_t insn = readFromHalf16(loc); - if (getPrimaryOpCode(insn) != LD) + uint32_t Insn = readFromHalf16(Loc); + if (getPrimaryOpCode(Insn) != LD) error("expected a 'ld' for got-indirect to toc-relative relaxing"); - writeFromHalf16(loc, (insn & 0x03ffffff) | 0x38000000); - relocateOne(loc, R_PPC64_TOC16_LO, val); + writeFromHalf16(Loc, (Insn & 0x03ffffff) | 0x38000000); + relocateOne(Loc, R_PPC64_TOC16_LO, Val); break; } default: @@ -379,7 +375,7 @@ void PPC64::relaxGot(uint8_t *loc, RelType type, uint64_t val) const { } } -void PPC64::relaxTlsGdToLe(uint8_t *loc, RelType type, uint64_t val) const { +void PPC64::relaxTlsGdToLe(uint8_t *Loc, RelType Type, uint64_t Val) const { // Reference: 3.7.4.2 of the 64-bit ELF V2 abi supplement. // The general dynamic code sequence for a global `x` will look like: // Instruction Relocation Symbol @@ -395,30 +391,30 @@ void PPC64::relaxTlsGdToLe(uint8_t *loc, RelType type, uint64_t val) const { // bl __tls_get_addr(x@tlsgd) into nop // nop into addi r3, r3, x@tprel@l - switch (type) { + switch (Type) { case R_PPC64_GOT_TLSGD16_HA: - writeFromHalf16(loc, 0x60000000); // nop + writeFromHalf16(Loc, 0x60000000); // nop break; case R_PPC64_GOT_TLSGD16: case R_PPC64_GOT_TLSGD16_LO: - writeFromHalf16(loc, 0x3c6d0000); // addis r3, r13 - relocateOne(loc, R_PPC64_TPREL16_HA, val); + writeFromHalf16(Loc, 0x3c6d0000); // addis r3, r13 + relocateOne(Loc, R_PPC64_TPREL16_HA, Val); break; case R_PPC64_TLSGD: - write32(loc, 0x60000000); // nop - write32(loc + 4, 0x38630000); // addi r3, r3 + write32(Loc, 0x60000000); // nop + write32(Loc + 4, 0x38630000); // addi r3, r3 // Since we are relocating a half16 type relocation and Loc + 4 points to // the start of an instruction we need to advance the buffer by an extra // 2 bytes on BE. - relocateOne(loc + 4 + (config->ekind == ELF64BEKind ? 2 : 0), - R_PPC64_TPREL16_LO, val); + relocateOne(Loc + 4 + (Config->EKind == ELF64BEKind ? 2 : 0), + R_PPC64_TPREL16_LO, Val); break; default: llvm_unreachable("unsupported relocation for TLS GD to LE relaxation"); } } -void PPC64::relaxTlsLdToLe(uint8_t *loc, RelType type, uint64_t val) const { +void PPC64::relaxTlsLdToLe(uint8_t *Loc, RelType Type, uint64_t Val) const { // Reference: 3.7.4.3 of the 64-bit ELF V2 abi supplement. // The local dynamic code sequence for a global `x` will look like: // Instruction Relocation Symbol @@ -434,16 +430,16 @@ void PPC64::relaxTlsLdToLe(uint8_t *loc, RelType type, uint64_t val) const { // bl __tls_get_addr(x@tlsgd) into nop // nop into addi r3, r3, 4096 - switch (type) { + switch (Type) { case R_PPC64_GOT_TLSLD16_HA: - writeFromHalf16(loc, 0x60000000); // nop + writeFromHalf16(Loc, 0x60000000); // nop break; case R_PPC64_GOT_TLSLD16_LO: - writeFromHalf16(loc, 0x3c6d0000); // addis r3, r13, 0 + writeFromHalf16(Loc, 0x3c6d0000); // addis r3, r13, 0 break; case R_PPC64_TLSLD: - write32(loc, 0x60000000); // nop - write32(loc + 4, 0x38631000); // addi r3, r3, 4096 + write32(Loc, 0x60000000); // nop + write32(Loc + 4, 0x38631000); // addi r3, r3, 4096 break; case R_PPC64_DTPREL16: case R_PPC64_DTPREL16_HA: @@ -451,15 +447,15 @@ void PPC64::relaxTlsLdToLe(uint8_t *loc, RelType type, uint64_t val) const { case R_PPC64_DTPREL16_DS: case R_PPC64_DTPREL16_LO: case R_PPC64_DTPREL16_LO_DS: - relocateOne(loc, type, val); + relocateOne(Loc, Type, Val); break; default: llvm_unreachable("unsupported relocation for TLS LD to LE relaxation"); } } -unsigned elf::getPPCDFormOp(unsigned secondaryOp) { - switch (secondaryOp) { +unsigned elf::getPPCDFormOp(unsigned SecondaryOp) { + switch (SecondaryOp) { case LBZX: return LBZ; case LHZX: @@ -483,7 +479,7 @@ unsigned elf::getPPCDFormOp(unsigned secondaryOp) { } } -void PPC64::relaxTlsIeToLe(uint8_t *loc, RelType type, uint64_t val) const { +void PPC64::relaxTlsIeToLe(uint8_t *Loc, RelType Type, uint64_t Val) const { // The initial exec code sequence for a global `x` will look like: // Instruction Relocation Symbol // addis r9, r2, x@got@tprel@ha R_PPC64_GOT_TPREL16_HA x @@ -503,28 +499,28 @@ void PPC64::relaxTlsIeToLe(uint8_t *loc, RelType type, uint64_t val) const { // instruction, if we are accessing memory it will use any of the X-form // indexed load or store instructions. - unsigned offset = (config->ekind == ELF64BEKind) ? 2 : 0; - switch (type) { + unsigned Offset = (Config->EKind == ELF64BEKind) ? 2 : 0; + switch (Type) { case R_PPC64_GOT_TPREL16_HA: - write32(loc - offset, 0x60000000); // nop + write32(Loc - Offset, 0x60000000); // nop break; case R_PPC64_GOT_TPREL16_LO_DS: case R_PPC64_GOT_TPREL16_DS: { - uint32_t regNo = read32(loc - offset) & 0x03E00000; // bits 6-10 - write32(loc - offset, 0x3C0D0000 | regNo); // addis RegNo, r13 - relocateOne(loc, R_PPC64_TPREL16_HA, val); + uint32_t RegNo = read32(Loc - Offset) & 0x03E00000; // bits 6-10 + write32(Loc - Offset, 0x3C0D0000 | RegNo); // addis RegNo, r13 + relocateOne(Loc, R_PPC64_TPREL16_HA, Val); break; } case R_PPC64_TLS: { - uint32_t primaryOp = getPrimaryOpCode(read32(loc)); - if (primaryOp != 31) + uint32_t PrimaryOp = getPrimaryOpCode(read32(Loc)); + if (PrimaryOp != 31) error("unrecognized instruction for IE to LE R_PPC64_TLS"); - uint32_t secondaryOp = (read32(loc) & 0x000007FE) >> 1; // bits 21-30 - uint32_t dFormOp = getPPCDFormOp(secondaryOp); - if (dFormOp == 0) + uint32_t SecondaryOp = (read32(Loc) & 0x000007FE) >> 1; // bits 21-30 + uint32_t DFormOp = getPPCDFormOp(SecondaryOp); + if (DFormOp == 0) error("unrecognized instruction for IE to LE R_PPC64_TLS"); - write32(loc, ((dFormOp << 26) | (read32(loc) & 0x03FFFFFF))); - relocateOne(loc + offset, R_PPC64_TPREL16_LO, val); + write32(Loc, ((DFormOp << 26) | (read32(Loc) & 0x03FFFFFF))); + relocateOne(Loc + Offset, R_PPC64_TPREL16_LO, Val); break; } default: @@ -533,24 +529,9 @@ void PPC64::relaxTlsIeToLe(uint8_t *loc, RelType type, uint64_t val) const { } } -RelExpr PPC64::getRelExpr(RelType type, const Symbol &s, - const uint8_t *loc) const { - switch (type) { - case R_PPC64_NONE: - return R_NONE; - case R_PPC64_ADDR16: - case R_PPC64_ADDR16_DS: - case R_PPC64_ADDR16_HA: - case R_PPC64_ADDR16_HI: - case R_PPC64_ADDR16_HIGHER: - case R_PPC64_ADDR16_HIGHERA: - case R_PPC64_ADDR16_HIGHEST: - case R_PPC64_ADDR16_HIGHESTA: - case R_PPC64_ADDR16_LO: - case R_PPC64_ADDR16_LO_DS: - case R_PPC64_ADDR32: - case R_PPC64_ADDR64: - return R_ABS; +RelExpr PPC64::getRelExpr(RelType Type, const Symbol &S, + const uint8_t *Loc) const { + switch (Type) { case R_PPC64_GOT16: case R_PPC64_GOT16_DS: case R_PPC64_GOT16_HA: @@ -565,7 +546,7 @@ RelExpr PPC64::getRelExpr(RelType type, const Symbol &s, return R_GOTREL; case R_PPC64_TOC16_HA: case R_PPC64_TOC16_LO_DS: - return config->tocOptimize ? R_PPC64_RELAX_TOC : R_GOTREL; + return Config->TocOptimize ? R_PPC64_RELAX_TOC : R_GOTREL; case R_PPC64_TOC: return R_PPC64_TOCBASE; case R_PPC64_REL14: @@ -573,7 +554,6 @@ RelExpr PPC64::getRelExpr(RelType type, const Symbol &s, return R_PPC64_CALL_PLT; case R_PPC64_REL16_LO: case R_PPC64_REL16_HA: - case R_PPC64_REL16_HI: case R_PPC64_REL32: case R_PPC64_REL64: return R_PC; @@ -627,127 +607,125 @@ RelExpr PPC64::getRelExpr(RelType type, const Symbol &s, case R_PPC64_TLS: return R_TLSIE_HINT; default: - error(getErrorLocation(loc) + "unknown relocation (" + Twine(type) + - ") against symbol " + toString(s)); - return R_NONE; + return R_ABS; } } -RelType PPC64::getDynRel(RelType type) const { - if (type == R_PPC64_ADDR64 || type == R_PPC64_TOC) +RelType PPC64::getDynRel(RelType Type) const { + if (Type == R_PPC64_ADDR64 || Type == R_PPC64_TOC) return R_PPC64_ADDR64; return R_PPC64_NONE; } -void PPC64::writeGotHeader(uint8_t *buf) const { - write64(buf, getPPC64TocBase()); +void PPC64::writeGotHeader(uint8_t *Buf) const { + write64(Buf, getPPC64TocBase()); } -void PPC64::writePltHeader(uint8_t *buf) const { +void PPC64::writePltHeader(uint8_t *Buf) const { // The generic resolver stub goes first. - write32(buf + 0, 0x7c0802a6); // mflr r0 - write32(buf + 4, 0x429f0005); // bcl 20,4*cr7+so,8 <_glink+0x8> - write32(buf + 8, 0x7d6802a6); // mflr r11 - write32(buf + 12, 0x7c0803a6); // mtlr r0 - write32(buf + 16, 0x7d8b6050); // subf r12, r11, r12 - write32(buf + 20, 0x380cffcc); // subi r0,r12,52 - write32(buf + 24, 0x7800f082); // srdi r0,r0,62,2 - write32(buf + 28, 0xe98b002c); // ld r12,44(r11) - write32(buf + 32, 0x7d6c5a14); // add r11,r12,r11 - write32(buf + 36, 0xe98b0000); // ld r12,0(r11) - write32(buf + 40, 0xe96b0008); // ld r11,8(r11) - write32(buf + 44, 0x7d8903a6); // mtctr r12 - write32(buf + 48, 0x4e800420); // bctr + write32(Buf + 0, 0x7c0802a6); // mflr r0 + write32(Buf + 4, 0x429f0005); // bcl 20,4*cr7+so,8 <_glink+0x8> + write32(Buf + 8, 0x7d6802a6); // mflr r11 + write32(Buf + 12, 0x7c0803a6); // mtlr r0 + write32(Buf + 16, 0x7d8b6050); // subf r12, r11, r12 + write32(Buf + 20, 0x380cffcc); // subi r0,r12,52 + write32(Buf + 24, 0x7800f082); // srdi r0,r0,62,2 + write32(Buf + 28, 0xe98b002c); // ld r12,44(r11) + write32(Buf + 32, 0x7d6c5a14); // add r11,r12,r11 + write32(Buf + 36, 0xe98b0000); // ld r12,0(r11) + write32(Buf + 40, 0xe96b0008); // ld r11,8(r11) + write32(Buf + 44, 0x7d8903a6); // mtctr r12 + write32(Buf + 48, 0x4e800420); // bctr // The 'bcl' instruction will set the link register to the address of the // following instruction ('mflr r11'). Here we store the offset from that // instruction to the first entry in the GotPlt section. - int64_t gotPltOffset = in.gotPlt->getVA() - (in.plt->getVA() + 8); - write64(buf + 52, gotPltOffset); + int64_t GotPltOffset = In.GotPlt->getVA() - (In.Plt->getVA() + 8); + write64(Buf + 52, GotPltOffset); } -void PPC64::writePlt(uint8_t *buf, uint64_t gotPltEntryAddr, - uint64_t pltEntryAddr, int32_t index, - unsigned relOff) const { - int32_t offset = pltHeaderSize + index * pltEntrySize; +void PPC64::writePlt(uint8_t *Buf, uint64_t GotPltEntryAddr, + uint64_t PltEntryAddr, int32_t Index, + unsigned RelOff) const { + int32_t Offset = PltHeaderSize + Index * PltEntrySize; // bl __glink_PLTresolve - write32(buf, 0x48000000 | ((-offset) & 0x03FFFFFc)); + write32(Buf, 0x48000000 | ((-Offset) & 0x03FFFFFc)); } -static std::pair toAddr16Rel(RelType type, uint64_t val) { +static std::pair toAddr16Rel(RelType Type, uint64_t Val) { // Relocations relative to the toc-base need to be adjusted by the Toc offset. - uint64_t tocBiasedVal = val - ppc64TocOffset; + uint64_t TocBiasedVal = Val - PPC64TocOffset; // Relocations relative to dtv[dtpmod] need to be adjusted by the DTP offset. - uint64_t dtpBiasedVal = val - dynamicThreadPointerOffset; + uint64_t DTPBiasedVal = Val - DynamicThreadPointerOffset; - switch (type) { + switch (Type) { // TOC biased relocation. case R_PPC64_GOT16: case R_PPC64_GOT_TLSGD16: case R_PPC64_GOT_TLSLD16: case R_PPC64_TOC16: - return {R_PPC64_ADDR16, tocBiasedVal}; + return {R_PPC64_ADDR16, TocBiasedVal}; case R_PPC64_GOT16_DS: case R_PPC64_TOC16_DS: case R_PPC64_GOT_TPREL16_DS: case R_PPC64_GOT_DTPREL16_DS: - return {R_PPC64_ADDR16_DS, tocBiasedVal}; + return {R_PPC64_ADDR16_DS, TocBiasedVal}; case R_PPC64_GOT16_HA: case R_PPC64_GOT_TLSGD16_HA: case R_PPC64_GOT_TLSLD16_HA: case R_PPC64_GOT_TPREL16_HA: case R_PPC64_GOT_DTPREL16_HA: case R_PPC64_TOC16_HA: - return {R_PPC64_ADDR16_HA, tocBiasedVal}; + return {R_PPC64_ADDR16_HA, TocBiasedVal}; case R_PPC64_GOT16_HI: case R_PPC64_GOT_TLSGD16_HI: case R_PPC64_GOT_TLSLD16_HI: case R_PPC64_GOT_TPREL16_HI: case R_PPC64_GOT_DTPREL16_HI: case R_PPC64_TOC16_HI: - return {R_PPC64_ADDR16_HI, tocBiasedVal}; + return {R_PPC64_ADDR16_HI, TocBiasedVal}; case R_PPC64_GOT16_LO: case R_PPC64_GOT_TLSGD16_LO: case R_PPC64_GOT_TLSLD16_LO: case R_PPC64_TOC16_LO: - return {R_PPC64_ADDR16_LO, tocBiasedVal}; + return {R_PPC64_ADDR16_LO, TocBiasedVal}; case R_PPC64_GOT16_LO_DS: case R_PPC64_TOC16_LO_DS: case R_PPC64_GOT_TPREL16_LO_DS: case R_PPC64_GOT_DTPREL16_LO_DS: - return {R_PPC64_ADDR16_LO_DS, tocBiasedVal}; + return {R_PPC64_ADDR16_LO_DS, TocBiasedVal}; // Dynamic Thread pointer biased relocation types. case R_PPC64_DTPREL16: - return {R_PPC64_ADDR16, dtpBiasedVal}; + return {R_PPC64_ADDR16, DTPBiasedVal}; case R_PPC64_DTPREL16_DS: - return {R_PPC64_ADDR16_DS, dtpBiasedVal}; + return {R_PPC64_ADDR16_DS, DTPBiasedVal}; case R_PPC64_DTPREL16_HA: - return {R_PPC64_ADDR16_HA, dtpBiasedVal}; + return {R_PPC64_ADDR16_HA, DTPBiasedVal}; case R_PPC64_DTPREL16_HI: - return {R_PPC64_ADDR16_HI, dtpBiasedVal}; + return {R_PPC64_ADDR16_HI, DTPBiasedVal}; case R_PPC64_DTPREL16_HIGHER: - return {R_PPC64_ADDR16_HIGHER, dtpBiasedVal}; + return {R_PPC64_ADDR16_HIGHER, DTPBiasedVal}; case R_PPC64_DTPREL16_HIGHERA: - return {R_PPC64_ADDR16_HIGHERA, dtpBiasedVal}; + return {R_PPC64_ADDR16_HIGHERA, DTPBiasedVal}; case R_PPC64_DTPREL16_HIGHEST: - return {R_PPC64_ADDR16_HIGHEST, dtpBiasedVal}; + return {R_PPC64_ADDR16_HIGHEST, DTPBiasedVal}; case R_PPC64_DTPREL16_HIGHESTA: - return {R_PPC64_ADDR16_HIGHESTA, dtpBiasedVal}; + return {R_PPC64_ADDR16_HIGHESTA, DTPBiasedVal}; case R_PPC64_DTPREL16_LO: - return {R_PPC64_ADDR16_LO, dtpBiasedVal}; + return {R_PPC64_ADDR16_LO, DTPBiasedVal}; case R_PPC64_DTPREL16_LO_DS: - return {R_PPC64_ADDR16_LO_DS, dtpBiasedVal}; + return {R_PPC64_ADDR16_LO_DS, DTPBiasedVal}; case R_PPC64_DTPREL64: - return {R_PPC64_ADDR64, dtpBiasedVal}; + return {R_PPC64_ADDR64, DTPBiasedVal}; default: - return {type, val}; + return {Type, Val}; } } -static bool isTocOptType(RelType type) { - switch (type) { +static bool isTocOptType(RelType Type) { + switch (Type) { case R_PPC64_GOT16_HA: case R_PPC64_GOT16_LO_DS: case R_PPC64_TOC16_HA: @@ -759,69 +737,69 @@ static bool isTocOptType(RelType type) { } } -void PPC64::relocateOne(uint8_t *loc, RelType type, uint64_t val) const { +void PPC64::relocateOne(uint8_t *Loc, RelType Type, uint64_t Val) const { // We need to save the original relocation type to use in diagnostics, and // use the original type to determine if we should toc-optimize the // instructions being relocated. - RelType originalType = type; - bool shouldTocOptimize = isTocOptType(type); + RelType OriginalType = Type; + bool ShouldTocOptimize = isTocOptType(Type); // For dynamic thread pointer relative, toc-relative, and got-indirect // relocations, proceed in terms of the corresponding ADDR16 relocation type. - std::tie(type, val) = toAddr16Rel(type, val); + std::tie(Type, Val) = toAddr16Rel(Type, Val); - switch (type) { + switch (Type) { case R_PPC64_ADDR14: { - checkAlignment(loc, val, 4, type); + checkAlignment(Loc, Val, 4, Type); // Preserve the AA/LK bits in the branch instruction - uint8_t aalk = loc[3]; - write16(loc + 2, (aalk & 3) | (val & 0xfffc)); + uint8_t AALK = Loc[3]; + write16(Loc + 2, (AALK & 3) | (Val & 0xfffc)); break; } case R_PPC64_ADDR16: - checkIntUInt(loc, val, 16, originalType); - write16(loc, val); + checkIntUInt(Loc, Val, 16, OriginalType); + write16(Loc, Val); break; case R_PPC64_ADDR32: - checkIntUInt(loc, val, 32, originalType); - write32(loc, val); + checkIntUInt(Loc, Val, 32, OriginalType); + write32(Loc, Val); break; case R_PPC64_ADDR16_DS: case R_PPC64_TPREL16_DS: { - checkInt(loc, val, 16, originalType); + checkInt(Loc, Val, 16, OriginalType); // DQ-form instructions use bits 28-31 as part of the instruction encoding // DS-form instructions only use bits 30-31. - uint16_t mask = isDQFormInstruction(readFromHalf16(loc)) ? 0xf : 0x3; - checkAlignment(loc, lo(val), mask + 1, originalType); - write16(loc, (read16(loc) & mask) | lo(val)); + uint16_t Mask = isDQFormInstruction(readFromHalf16(Loc)) ? 0xf : 0x3; + checkAlignment(Loc, lo(Val), Mask + 1, OriginalType); + write16(Loc, (read16(Loc) & Mask) | lo(Val)); } break; case R_PPC64_ADDR16_HA: case R_PPC64_REL16_HA: case R_PPC64_TPREL16_HA: - if (config->tocOptimize && shouldTocOptimize && ha(val) == 0) - writeFromHalf16(loc, 0x60000000); + if (Config->TocOptimize && ShouldTocOptimize && ha(Val) == 0) + writeFromHalf16(Loc, 0x60000000); else - write16(loc, ha(val)); + write16(Loc, ha(Val)); break; case R_PPC64_ADDR16_HI: case R_PPC64_REL16_HI: case R_PPC64_TPREL16_HI: - write16(loc, hi(val)); + write16(Loc, hi(Val)); break; case R_PPC64_ADDR16_HIGHER: case R_PPC64_TPREL16_HIGHER: - write16(loc, higher(val)); + write16(Loc, higher(Val)); break; case R_PPC64_ADDR16_HIGHERA: case R_PPC64_TPREL16_HIGHERA: - write16(loc, highera(val)); + write16(Loc, highera(Val)); break; case R_PPC64_ADDR16_HIGHEST: case R_PPC64_TPREL16_HIGHEST: - write16(loc, highest(val)); + write16(Loc, highest(Val)); break; case R_PPC64_ADDR16_HIGHESTA: case R_PPC64_TPREL16_HIGHESTA: - write16(loc, highesta(val)); + write16(Loc, highesta(Val)); break; case R_PPC64_ADDR16_LO: case R_PPC64_REL16_LO: @@ -829,93 +807,93 @@ void PPC64::relocateOne(uint8_t *loc, RelType type, uint64_t val) const { // When the high-adjusted part of a toc relocation evalutes to 0, it is // changed into a nop. The lo part then needs to be updated to use the // toc-pointer register r2, as the base register. - if (config->tocOptimize && shouldTocOptimize && ha(val) == 0) { - uint32_t insn = readFromHalf16(loc); - if (isInstructionUpdateForm(insn)) - error(getErrorLocation(loc) + + if (Config->TocOptimize && ShouldTocOptimize && ha(Val) == 0) { + uint32_t Insn = readFromHalf16(Loc); + if (isInstructionUpdateForm(Insn)) + error(getErrorLocation(Loc) + "can't toc-optimize an update instruction: 0x" + - utohexstr(insn)); - writeFromHalf16(loc, (insn & 0xffe00000) | 0x00020000 | lo(val)); + utohexstr(Insn)); + writeFromHalf16(Loc, (Insn & 0xffe00000) | 0x00020000 | lo(Val)); } else { - write16(loc, lo(val)); + write16(Loc, lo(Val)); } break; case R_PPC64_ADDR16_LO_DS: case R_PPC64_TPREL16_LO_DS: { // DQ-form instructions use bits 28-31 as part of the instruction encoding // DS-form instructions only use bits 30-31. - uint32_t insn = readFromHalf16(loc); - uint16_t mask = isDQFormInstruction(insn) ? 0xf : 0x3; - checkAlignment(loc, lo(val), mask + 1, originalType); - if (config->tocOptimize && shouldTocOptimize && ha(val) == 0) { + uint32_t Insn = readFromHalf16(Loc); + uint16_t Mask = isDQFormInstruction(Insn) ? 0xf : 0x3; + checkAlignment(Loc, lo(Val), Mask + 1, OriginalType); + if (Config->TocOptimize && ShouldTocOptimize && ha(Val) == 0) { // When the high-adjusted part of a toc relocation evalutes to 0, it is // changed into a nop. The lo part then needs to be updated to use the toc // pointer register r2, as the base register. - if (isInstructionUpdateForm(insn)) - error(getErrorLocation(loc) + + if (isInstructionUpdateForm(Insn)) + error(getErrorLocation(Loc) + "Can't toc-optimize an update instruction: 0x" + - Twine::utohexstr(insn)); - insn &= 0xffe00000 | mask; - writeFromHalf16(loc, insn | 0x00020000 | lo(val)); + Twine::utohexstr(Insn)); + Insn &= 0xffe00000 | Mask; + writeFromHalf16(Loc, Insn | 0x00020000 | lo(Val)); } else { - write16(loc, (read16(loc) & mask) | lo(val)); + write16(Loc, (read16(Loc) & Mask) | lo(Val)); } } break; case R_PPC64_TPREL16: - checkInt(loc, val, 16, originalType); - write16(loc, val); + checkInt(Loc, Val, 16, OriginalType); + write16(Loc, Val); break; case R_PPC64_REL32: - checkInt(loc, val, 32, type); - write32(loc, val); + checkInt(Loc, Val, 32, Type); + write32(Loc, Val); break; case R_PPC64_ADDR64: case R_PPC64_REL64: case R_PPC64_TOC: - write64(loc, val); + write64(Loc, Val); break; case R_PPC64_REL14: { - uint32_t mask = 0x0000FFFC; - checkInt(loc, val, 16, type); - checkAlignment(loc, val, 4, type); - write32(loc, (read32(loc) & ~mask) | (val & mask)); + uint32_t Mask = 0x0000FFFC; + checkInt(Loc, Val, 16, Type); + checkAlignment(Loc, Val, 4, Type); + write32(Loc, (read32(Loc) & ~Mask) | (Val & Mask)); break; } case R_PPC64_REL24: { - uint32_t mask = 0x03FFFFFC; - checkInt(loc, val, 26, type); - checkAlignment(loc, val, 4, type); - write32(loc, (read32(loc) & ~mask) | (val & mask)); + uint32_t Mask = 0x03FFFFFC; + checkInt(Loc, Val, 26, Type); + checkAlignment(Loc, Val, 4, Type); + write32(Loc, (read32(Loc) & ~Mask) | (Val & Mask)); break; } case R_PPC64_DTPREL64: - write64(loc, val - dynamicThreadPointerOffset); + write64(Loc, Val - DynamicThreadPointerOffset); break; default: - llvm_unreachable("unknown relocation"); + error(getErrorLocation(Loc) + "unrecognized relocation " + toString(Type)); } } -bool PPC64::needsThunk(RelExpr expr, RelType type, const InputFile *file, - uint64_t branchAddr, const Symbol &s) const { - if (type != R_PPC64_REL14 && type != R_PPC64_REL24) +bool PPC64::needsThunk(RelExpr Expr, RelType Type, const InputFile *File, + uint64_t BranchAddr, const Symbol &S) const { + if (Type != R_PPC64_REL14 && Type != R_PPC64_REL24) return false; // If a function is in the Plt it needs to be called with a call-stub. - if (s.isInPlt()) + if (S.isInPlt()) return true; // If a symbol is a weak undefined and we are compiling an executable // it doesn't need a range-extending thunk since it can't be called. - if (s.isUndefWeak() && !config->shared) + if (S.isUndefWeak() && !Config->Shared) return false; // If the offset exceeds the range of the branch type then it will need // a range-extending thunk. // See the comment in getRelocTargetVA() about R_PPC64_CALL. - return !inBranchRange(type, branchAddr, - s.getVA() + - getPPC64GlobalEntryToLocalEntryOffset(s.stOther)); + return !inBranchRange(Type, BranchAddr, + S.getVA() + + getPPC64GlobalEntryToLocalEntryOffset(S.StOther)); } uint32_t PPC64::getThunkSectionSpacing() const { @@ -926,22 +904,22 @@ uint32_t PPC64::getThunkSectionSpacing() const { return 0x2000000; } -bool PPC64::inBranchRange(RelType type, uint64_t src, uint64_t dst) const { - int64_t offset = dst - src; - if (type == R_PPC64_REL14) - return isInt<16>(offset); - if (type == R_PPC64_REL24) - return isInt<26>(offset); +bool PPC64::inBranchRange(RelType Type, uint64_t Src, uint64_t Dst) const { + int64_t Offset = Dst - Src; + if (Type == R_PPC64_REL14) + return isInt<16>(Offset); + if (Type == R_PPC64_REL24) + return isInt<26>(Offset); llvm_unreachable("unsupported relocation type used in branch"); } -RelExpr PPC64::adjustRelaxExpr(RelType type, const uint8_t *data, - RelExpr expr) const { - if (expr == R_RELAX_TLS_GD_TO_IE) +RelExpr PPC64::adjustRelaxExpr(RelType Type, const uint8_t *Data, + RelExpr Expr) const { + if (Expr == R_RELAX_TLS_GD_TO_IE) return R_RELAX_TLS_GD_TO_IE_GOT_OFF; - if (expr == R_RELAX_TLS_LD_TO_LE) + if (Expr == R_RELAX_TLS_LD_TO_LE) return R_RELAX_TLS_LD_TO_LE_ABS; - return expr; + return Expr; } // Reference: 3.7.4.1 of the 64-bit ELF V2 abi supplement. @@ -961,25 +939,24 @@ RelExpr PPC64::adjustRelaxExpr(RelType type, const uint8_t *data, // thread pointer. // Since the nop must directly follow the call, the R_PPC64_TLSGD relocation is // used as the relaxation hint for both steps 2 and 3. -void PPC64::relaxTlsGdToIe(uint8_t *loc, RelType type, uint64_t val) const { - switch (type) { +void PPC64::relaxTlsGdToIe(uint8_t *Loc, RelType Type, uint64_t Val) const { + switch (Type) { case R_PPC64_GOT_TLSGD16_HA: // This is relaxed from addis rT, r2, sym@got@tlsgd@ha to // addis rT, r2, sym@got@tprel@ha. - relocateOne(loc, R_PPC64_GOT_TPREL16_HA, val); + relocateOne(Loc, R_PPC64_GOT_TPREL16_HA, Val); return; - case R_PPC64_GOT_TLSGD16: case R_PPC64_GOT_TLSGD16_LO: { // Relax from addi r3, rA, sym@got@tlsgd@l to // ld r3, sym@got@tprel@l(rA) - uint32_t ra = (readFromHalf16(loc) & (0x1f << 16)); - writeFromHalf16(loc, 0xe8600000 | ra); - relocateOne(loc, R_PPC64_GOT_TPREL16_LO_DS, val); + uint32_t RA = (readFromHalf16(Loc) & (0x1f << 16)); + writeFromHalf16(Loc, 0xe8600000 | RA); + relocateOne(Loc, R_PPC64_GOT_TPREL16_LO_DS, Val); return; } case R_PPC64_TLSGD: - write32(loc, 0x60000000); // bl __tls_get_addr(sym@tlsgd) --> nop - write32(loc + 4, 0x7c636A14); // nop --> add r3, r3, r13 + write32(Loc, 0x60000000); // bl __tls_get_addr(sym@tlsgd) --> nop + write32(Loc + 4, 0x7c636A14); // nop --> add r3, r3, r13 return; default: llvm_unreachable("unsupported relocation for TLS GD to IE relaxation"); @@ -1014,86 +991,86 @@ void PPC64::relaxTlsGdToIe(uint8_t *loc, RelType type, uint64_t val) const { // pair by split-stack-size-adjust. // addis r12, r1, ha(-stack-frame size - split-stack-adjust-size) // addi r12, r12, l(-stack-frame size - split-stack-adjust-size) -bool PPC64::adjustPrologueForCrossSplitStack(uint8_t *loc, uint8_t *end, - uint8_t stOther) const { +bool PPC64::adjustPrologueForCrossSplitStack(uint8_t *Loc, uint8_t *End, + uint8_t StOther) const { // If the caller has a global entry point adjust the buffer past it. The start // of the split-stack prologue will be at the local entry point. - loc += getPPC64GlobalEntryToLocalEntryOffset(stOther); + Loc += getPPC64GlobalEntryToLocalEntryOffset(StOther); // At the very least we expect to see a load of some split-stack data from the // tcb, and 2 instructions that calculate the ending stack address this // function will require. If there is not enough room for at least 3 // instructions it can't be a split-stack prologue. - if (loc + 12 >= end) + if (Loc + 12 >= End) return false; // First instruction must be `ld r0, -0x7000-64(r13)` - if (read32(loc) != 0xe80d8fc0) + if (read32(Loc) != 0xe80d8fc0) return false; - int16_t hiImm = 0; - int16_t loImm = 0; + int16_t HiImm = 0; + int16_t LoImm = 0; // First instruction can be either an addis if the frame size is larger then // 32K, or an addi if the size is less then 32K. - int32_t firstInstr = read32(loc + 4); - if (getPrimaryOpCode(firstInstr) == 15) { - hiImm = firstInstr & 0xFFFF; - } else if (getPrimaryOpCode(firstInstr) == 14) { - loImm = firstInstr & 0xFFFF; + int32_t FirstInstr = read32(Loc + 4); + if (getPrimaryOpCode(FirstInstr) == 15) { + HiImm = FirstInstr & 0xFFFF; + } else if (getPrimaryOpCode(FirstInstr) == 14) { + LoImm = FirstInstr & 0xFFFF; } else { return false; } // Second instruction is either an addi or a nop. If the first instruction was // an addi then LoImm is set and the second instruction must be a nop. - uint32_t secondInstr = read32(loc + 8); - if (!loImm && getPrimaryOpCode(secondInstr) == 14) { - loImm = secondInstr & 0xFFFF; - } else if (secondInstr != 0x60000000) { + uint32_t SecondInstr = read32(Loc + 8); + if (!LoImm && getPrimaryOpCode(SecondInstr) == 14) { + LoImm = SecondInstr & 0xFFFF; + } else if (SecondInstr != 0x60000000) { return false; } // The register operands of the first instruction should be the stack-pointer // (r1) as the input (RA) and r12 as the output (RT). If the second // instruction is not a nop, then it should use r12 as both input and output. - auto checkRegOperands = [](uint32_t instr, uint8_t expectedRT, - uint8_t expectedRA) { - return ((instr & 0x3E00000) >> 21 == expectedRT) && - ((instr & 0x1F0000) >> 16 == expectedRA); + auto CheckRegOperands = [](uint32_t Instr, uint8_t ExpectedRT, + uint8_t ExpectedRA) { + return ((Instr & 0x3E00000) >> 21 == ExpectedRT) && + ((Instr & 0x1F0000) >> 16 == ExpectedRA); }; - if (!checkRegOperands(firstInstr, 12, 1)) + if (!CheckRegOperands(FirstInstr, 12, 1)) return false; - if (secondInstr != 0x60000000 && !checkRegOperands(secondInstr, 12, 12)) + if (SecondInstr != 0x60000000 && !CheckRegOperands(SecondInstr, 12, 12)) return false; - int32_t stackFrameSize = (hiImm * 65536) + loImm; + int32_t StackFrameSize = (HiImm * 65536) + LoImm; // Check that the adjusted size doesn't overflow what we can represent with 2 // instructions. - if (stackFrameSize < config->splitStackAdjustSize + INT32_MIN) { - error(getErrorLocation(loc) + "split-stack prologue adjustment overflows"); + if (StackFrameSize < Config->SplitStackAdjustSize + INT32_MIN) { + error(getErrorLocation(Loc) + "split-stack prologue adjustment overflows"); return false; } - int32_t adjustedStackFrameSize = - stackFrameSize - config->splitStackAdjustSize; + int32_t AdjustedStackFrameSize = + StackFrameSize - Config->SplitStackAdjustSize; - loImm = adjustedStackFrameSize & 0xFFFF; - hiImm = (adjustedStackFrameSize + 0x8000) >> 16; - if (hiImm) { - write32(loc + 4, 0x3D810000 | (uint16_t)hiImm); + LoImm = AdjustedStackFrameSize & 0xFFFF; + HiImm = (AdjustedStackFrameSize + 0x8000) >> 16; + if (HiImm) { + write32(Loc + 4, 0x3D810000 | (uint16_t)HiImm); // If the low immediate is zero the second instruction will be a nop. - secondInstr = loImm ? 0x398C0000 | (uint16_t)loImm : 0x60000000; - write32(loc + 8, secondInstr); + SecondInstr = LoImm ? 0x398C0000 | (uint16_t)LoImm : 0x60000000; + write32(Loc + 8, SecondInstr); } else { // addi r12, r1, imm - write32(loc + 4, (0x39810000) | (uint16_t)loImm); - write32(loc + 8, 0x60000000); + write32(Loc + 4, (0x39810000) | (uint16_t)LoImm); + write32(Loc + 8, 0x60000000); } return true; } TargetInfo *elf::getPPC64TargetInfo() { - static PPC64 target; - return ⌖ + static PPC64 Target; + return &Target; } diff --git a/lld/ELF/Arch/RISCV.cpp b/lld/ELF/Arch/RISCV.cpp index 6f16ade5717731..9355a746156c77 100644 --- a/lld/ELF/Arch/RISCV.cpp +++ b/lld/ELF/Arch/RISCV.cpp @@ -7,7 +7,6 @@ //===----------------------------------------------------------------------===// #include "InputFiles.h" -#include "SyntheticSections.h" #include "Target.h" using namespace llvm; @@ -23,166 +22,46 @@ class RISCV final : public TargetInfo { public: RISCV(); uint32_t calcEFlags() const override; - void writeGotHeader(uint8_t *buf) const override; - void writeGotPlt(uint8_t *buf, const Symbol &s) const override; - void writePltHeader(uint8_t *buf) const override; - void writePlt(uint8_t *buf, uint64_t gotPltEntryAddr, uint64_t pltEntryAddr, - int32_t index, unsigned relOff) const override; - RelType getDynRel(RelType type) const override; - RelExpr getRelExpr(RelType type, const Symbol &s, - const uint8_t *loc) const override; - void relocateOne(uint8_t *loc, RelType type, uint64_t val) const override; + RelExpr getRelExpr(RelType Type, const Symbol &S, + const uint8_t *Loc) const override; + void relocateOne(uint8_t *Loc, RelType Type, uint64_t Val) const override; }; } // end anonymous namespace -const uint64_t dtpOffset = 0x800; +RISCV::RISCV() { NoneRel = R_RISCV_NONE; } -enum Op { - ADDI = 0x13, - AUIPC = 0x17, - JALR = 0x67, - LD = 0x3003, - LW = 0x2003, - SRLI = 0x5013, - SUB = 0x40000033, -}; - -enum Reg { - X_RA = 1, - X_T0 = 5, - X_T1 = 6, - X_T2 = 7, - X_T3 = 28, -}; - -static uint32_t hi20(uint32_t val) { return (val + 0x800) >> 12; } -static uint32_t lo12(uint32_t val) { return val & 4095; } - -static uint32_t itype(uint32_t op, uint32_t rd, uint32_t rs1, uint32_t imm) { - return op | (rd << 7) | (rs1 << 15) | (imm << 20); -} -static uint32_t rtype(uint32_t op, uint32_t rd, uint32_t rs1, uint32_t rs2) { - return op | (rd << 7) | (rs1 << 15) | (rs2 << 20); -} -static uint32_t utype(uint32_t op, uint32_t rd, uint32_t imm) { - return op | (rd << 7) | (imm << 12); -} - -RISCV::RISCV() { - copyRel = R_RISCV_COPY; - noneRel = R_RISCV_NONE; - pltRel = R_RISCV_JUMP_SLOT; - relativeRel = R_RISCV_RELATIVE; - if (config->is64) { - symbolicRel = R_RISCV_64; - tlsModuleIndexRel = R_RISCV_TLS_DTPMOD64; - tlsOffsetRel = R_RISCV_TLS_DTPREL64; - tlsGotRel = R_RISCV_TLS_TPREL64; - } else { - symbolicRel = R_RISCV_32; - tlsModuleIndexRel = R_RISCV_TLS_DTPMOD32; - tlsOffsetRel = R_RISCV_TLS_DTPREL32; - tlsGotRel = R_RISCV_TLS_TPREL32; - } - gotRel = symbolicRel; - - // .got[0] = _DYNAMIC - gotBaseSymInGotPlt = false; - gotHeaderEntriesNum = 1; - - // .got.plt[0] = _dl_runtime_resolve, .got.plt[1] = link_map - gotPltHeaderEntriesNum = 2; - - pltEntrySize = 16; - pltHeaderSize = 32; -} - -static uint32_t getEFlags(InputFile *f) { - if (config->is64) - return cast>(f)->getObj().getHeader()->e_flags; - return cast>(f)->getObj().getHeader()->e_flags; +static uint32_t getEFlags(InputFile *F) { + if (Config->Is64) + return cast>(F)->getObj().getHeader()->e_flags; + return cast>(F)->getObj().getHeader()->e_flags; } uint32_t RISCV::calcEFlags() const { - assert(!objectFiles.empty()); + assert(!ObjectFiles.empty()); - uint32_t target = getEFlags(objectFiles.front()); + uint32_t Target = getEFlags(ObjectFiles.front()); - for (InputFile *f : objectFiles) { - uint32_t eflags = getEFlags(f); - if (eflags & EF_RISCV_RVC) - target |= EF_RISCV_RVC; + for (InputFile *F : ObjectFiles) { + uint32_t EFlags = getEFlags(F); + if (EFlags & EF_RISCV_RVC) + Target |= EF_RISCV_RVC; - if ((eflags & EF_RISCV_FLOAT_ABI) != (target & EF_RISCV_FLOAT_ABI)) - error(toString(f) + + if ((EFlags & EF_RISCV_FLOAT_ABI) != (Target & EF_RISCV_FLOAT_ABI)) + error(toString(F) + ": cannot link object files with different floating-point ABI"); - if ((eflags & EF_RISCV_RVE) != (target & EF_RISCV_RVE)) - error(toString(f) + + if ((EFlags & EF_RISCV_RVE) != (Target & EF_RISCV_RVE)) + error(toString(F) + ": cannot link object files with different EF_RISCV_RVE"); } - return target; + return Target; } -void RISCV::writeGotHeader(uint8_t *buf) const { - if (config->is64) - write64le(buf, mainPart->dynamic->getVA()); - else - write32le(buf, mainPart->dynamic->getVA()); -} - -void RISCV::writeGotPlt(uint8_t *buf, const Symbol &s) const { - if (config->is64) - write64le(buf, in.plt->getVA()); - else - write32le(buf, in.plt->getVA()); -} - -void RISCV::writePltHeader(uint8_t *buf) const { - // 1: auipc t2, %pcrel_hi(.got.plt) - // sub t1, t1, t3 - // l[wd] t3, %pcrel_lo(1b)(t2); t3 = _dl_runtime_resolve - // addi t1, t1, -pltHeaderSize-12; t1 = &.plt[i] - &.plt[0] - // addi t0, t2, %pcrel_lo(1b) - // srli t1, t1, (rv64?1:2); t1 = &.got.plt[i] - &.got.plt[0] - // l[wd] t0, Wordsize(t0); t0 = link_map - // jr t3 - uint32_t offset = in.gotPlt->getVA() - in.plt->getVA(); - uint32_t load = config->is64 ? LD : LW; - write32le(buf + 0, utype(AUIPC, X_T2, hi20(offset))); - write32le(buf + 4, rtype(SUB, X_T1, X_T1, X_T3)); - write32le(buf + 8, itype(load, X_T3, X_T2, lo12(offset))); - write32le(buf + 12, itype(ADDI, X_T1, X_T1, -target->pltHeaderSize - 12)); - write32le(buf + 16, itype(ADDI, X_T0, X_T2, lo12(offset))); - write32le(buf + 20, itype(SRLI, X_T1, X_T1, config->is64 ? 1 : 2)); - write32le(buf + 24, itype(load, X_T0, X_T0, config->wordsize)); - write32le(buf + 28, itype(JALR, 0, X_T3, 0)); -} - -void RISCV::writePlt(uint8_t *buf, uint64_t gotPltEntryAddr, - uint64_t pltEntryAddr, int32_t index, - unsigned relOff) const { - // 1: auipc t3, %pcrel_hi(f@.got.plt) - // l[wd] t3, %pcrel_lo(1b)(t3) - // jalr t1, t3 - // nop - uint32_t offset = gotPltEntryAddr - pltEntryAddr; - write32le(buf + 0, utype(AUIPC, X_T3, hi20(offset))); - write32le(buf + 4, itype(config->is64 ? LD : LW, X_T3, X_T3, lo12(offset))); - write32le(buf + 8, itype(JALR, X_T1, X_T3, 0)); - write32le(buf + 12, itype(ADDI, 0, 0, 0)); -} - -RelType RISCV::getDynRel(RelType type) const { - return type == target->symbolicRel ? type - : static_cast(R_RISCV_NONE); -} - -RelExpr RISCV::getRelExpr(const RelType type, const Symbol &s, - const uint8_t *loc) const { - switch (type) { +RelExpr RISCV::getRelExpr(const RelType Type, const Symbol &S, + const uint8_t *Loc) const { + switch (Type) { case R_RISCV_ADD8: case R_RISCV_ADD16: case R_RISCV_ADD32: @@ -199,31 +78,17 @@ RelExpr RISCV::getRelExpr(const RelType type, const Symbol &s, return R_RISCV_ADD; case R_RISCV_JAL: case R_RISCV_BRANCH: + case R_RISCV_CALL: case R_RISCV_PCREL_HI20: case R_RISCV_RVC_BRANCH: case R_RISCV_RVC_JUMP: case R_RISCV_32_PCREL: return R_PC; - case R_RISCV_CALL: - case R_RISCV_CALL_PLT: - return R_PLT_PC; - case R_RISCV_GOT_HI20: - return R_GOT_PC; case R_RISCV_PCREL_LO12_I: case R_RISCV_PCREL_LO12_S: return R_RISCV_PC_INDIRECT; - case R_RISCV_TLS_GD_HI20: - return R_TLSGD_PC; - case R_RISCV_TLS_GOT_HI20: - config->hasStaticTlsModel = true; - return R_GOT_PC; - case R_RISCV_TPREL_HI20: - case R_RISCV_TPREL_LO12_I: - case R_RISCV_TPREL_LO12_S: - return R_TLS; case R_RISCV_RELAX: case R_RISCV_ALIGN: - case R_RISCV_TPREL_ADD: return R_HINT; default: return R_ABS; @@ -231,190 +96,176 @@ RelExpr RISCV::getRelExpr(const RelType type, const Symbol &s, } // Extract bits V[Begin:End], where range is inclusive, and Begin must be < 63. -static uint32_t extractBits(uint64_t v, uint32_t begin, uint32_t end) { - return (v & ((1ULL << (begin + 1)) - 1)) >> end; +static uint32_t extractBits(uint64_t V, uint32_t Begin, uint32_t End) { + return (V & ((1ULL << (Begin + 1)) - 1)) >> End; } -void RISCV::relocateOne(uint8_t *loc, const RelType type, - const uint64_t val) const { - const unsigned bits = config->wordsize * 8; +void RISCV::relocateOne(uint8_t *Loc, const RelType Type, + const uint64_t Val) const { + const unsigned Bits = Config->Wordsize * 8; - switch (type) { + switch (Type) { case R_RISCV_32: - write32le(loc, val); + write32le(Loc, Val); return; case R_RISCV_64: - write64le(loc, val); + write64le(Loc, Val); return; case R_RISCV_RVC_BRANCH: { - checkInt(loc, static_cast(val) >> 1, 8, type); - checkAlignment(loc, val, 2, type); - uint16_t insn = read16le(loc) & 0xE383; - uint16_t imm8 = extractBits(val, 8, 8) << 12; - uint16_t imm4_3 = extractBits(val, 4, 3) << 10; - uint16_t imm7_6 = extractBits(val, 7, 6) << 5; - uint16_t imm2_1 = extractBits(val, 2, 1) << 3; - uint16_t imm5 = extractBits(val, 5, 5) << 2; - insn |= imm8 | imm4_3 | imm7_6 | imm2_1 | imm5; - - write16le(loc, insn); + checkInt(Loc, static_cast(Val) >> 1, 8, Type); + checkAlignment(Loc, Val, 2, Type); + uint16_t Insn = read16le(Loc) & 0xE383; + uint16_t Imm8 = extractBits(Val, 8, 8) << 12; + uint16_t Imm4_3 = extractBits(Val, 4, 3) << 10; + uint16_t Imm7_6 = extractBits(Val, 7, 6) << 5; + uint16_t Imm2_1 = extractBits(Val, 2, 1) << 3; + uint16_t Imm5 = extractBits(Val, 5, 5) << 2; + Insn |= Imm8 | Imm4_3 | Imm7_6 | Imm2_1 | Imm5; + + write16le(Loc, Insn); return; } case R_RISCV_RVC_JUMP: { - checkInt(loc, static_cast(val) >> 1, 11, type); - checkAlignment(loc, val, 2, type); - uint16_t insn = read16le(loc) & 0xE003; - uint16_t imm11 = extractBits(val, 11, 11) << 12; - uint16_t imm4 = extractBits(val, 4, 4) << 11; - uint16_t imm9_8 = extractBits(val, 9, 8) << 9; - uint16_t imm10 = extractBits(val, 10, 10) << 8; - uint16_t imm6 = extractBits(val, 6, 6) << 7; - uint16_t imm7 = extractBits(val, 7, 7) << 6; - uint16_t imm3_1 = extractBits(val, 3, 1) << 3; - uint16_t imm5 = extractBits(val, 5, 5) << 2; - insn |= imm11 | imm4 | imm9_8 | imm10 | imm6 | imm7 | imm3_1 | imm5; - - write16le(loc, insn); + checkInt(Loc, static_cast(Val) >> 1, 11, Type); + checkAlignment(Loc, Val, 2, Type); + uint16_t Insn = read16le(Loc) & 0xE003; + uint16_t Imm11 = extractBits(Val, 11, 11) << 12; + uint16_t Imm4 = extractBits(Val, 4, 4) << 11; + uint16_t Imm9_8 = extractBits(Val, 9, 8) << 9; + uint16_t Imm10 = extractBits(Val, 10, 10) << 8; + uint16_t Imm6 = extractBits(Val, 6, 6) << 7; + uint16_t Imm7 = extractBits(Val, 7, 7) << 6; + uint16_t Imm3_1 = extractBits(Val, 3, 1) << 3; + uint16_t Imm5 = extractBits(Val, 5, 5) << 2; + Insn |= Imm11 | Imm4 | Imm9_8 | Imm10 | Imm6 | Imm7 | Imm3_1 | Imm5; + + write16le(Loc, Insn); return; } case R_RISCV_RVC_LUI: { - int64_t imm = SignExtend64(val + 0x800, bits) >> 12; - checkInt(loc, imm, 6, type); - if (imm == 0) { // `c.lui rd, 0` is illegal, convert to `c.li rd, 0` - write16le(loc, (read16le(loc) & 0x0F83) | 0x4000); + int64_t Imm = SignExtend64(Val + 0x800, Bits) >> 12; + checkInt(Loc, Imm, 6, Type); + if (Imm == 0) { // `c.lui rd, 0` is illegal, convert to `c.li rd, 0` + write16le(Loc, (read16le(Loc) & 0x0F83) | 0x4000); } else { - uint16_t imm17 = extractBits(val + 0x800, 17, 17) << 12; - uint16_t imm16_12 = extractBits(val + 0x800, 16, 12) << 2; - write16le(loc, (read16le(loc) & 0xEF83) | imm17 | imm16_12); + uint16_t Imm17 = extractBits(Val + 0x800, 17, 17) << 12; + uint16_t Imm16_12 = extractBits(Val + 0x800, 16, 12) << 2; + write16le(Loc, (read16le(Loc) & 0xEF83) | Imm17 | Imm16_12); } return; } case R_RISCV_JAL: { - checkInt(loc, static_cast(val) >> 1, 20, type); - checkAlignment(loc, val, 2, type); + checkInt(Loc, static_cast(Val) >> 1, 20, Type); + checkAlignment(Loc, Val, 2, Type); - uint32_t insn = read32le(loc) & 0xFFF; - uint32_t imm20 = extractBits(val, 20, 20) << 31; - uint32_t imm10_1 = extractBits(val, 10, 1) << 21; - uint32_t imm11 = extractBits(val, 11, 11) << 20; - uint32_t imm19_12 = extractBits(val, 19, 12) << 12; - insn |= imm20 | imm10_1 | imm11 | imm19_12; + uint32_t Insn = read32le(Loc) & 0xFFF; + uint32_t Imm20 = extractBits(Val, 20, 20) << 31; + uint32_t Imm10_1 = extractBits(Val, 10, 1) << 21; + uint32_t Imm11 = extractBits(Val, 11, 11) << 20; + uint32_t Imm19_12 = extractBits(Val, 19, 12) << 12; + Insn |= Imm20 | Imm10_1 | Imm11 | Imm19_12; - write32le(loc, insn); + write32le(Loc, Insn); return; } case R_RISCV_BRANCH: { - checkInt(loc, static_cast(val) >> 1, 12, type); - checkAlignment(loc, val, 2, type); + checkInt(Loc, static_cast(Val) >> 1, 12, Type); + checkAlignment(Loc, Val, 2, Type); - uint32_t insn = read32le(loc) & 0x1FFF07F; - uint32_t imm12 = extractBits(val, 12, 12) << 31; - uint32_t imm10_5 = extractBits(val, 10, 5) << 25; - uint32_t imm4_1 = extractBits(val, 4, 1) << 8; - uint32_t imm11 = extractBits(val, 11, 11) << 7; - insn |= imm12 | imm10_5 | imm4_1 | imm11; + uint32_t Insn = read32le(Loc) & 0x1FFF07F; + uint32_t Imm12 = extractBits(Val, 12, 12) << 31; + uint32_t Imm10_5 = extractBits(Val, 10, 5) << 25; + uint32_t Imm4_1 = extractBits(Val, 4, 1) << 8; + uint32_t Imm11 = extractBits(Val, 11, 11) << 7; + Insn |= Imm12 | Imm10_5 | Imm4_1 | Imm11; - write32le(loc, insn); + write32le(Loc, Insn); return; } // auipc + jalr pair - case R_RISCV_CALL: - case R_RISCV_CALL_PLT: { - int64_t hi = SignExtend64(val + 0x800, bits) >> 12; - checkInt(loc, hi, 20, type); - if (isInt<20>(hi)) { - relocateOne(loc, R_RISCV_PCREL_HI20, val); - relocateOne(loc + 4, R_RISCV_PCREL_LO12_I, val); + case R_RISCV_CALL: { + int64_t Hi = SignExtend64(Val + 0x800, Bits) >> 12; + checkInt(Loc, Hi, 20, Type); + if (isInt<20>(Hi)) { + relocateOne(Loc, R_RISCV_PCREL_HI20, Val); + relocateOne(Loc + 4, R_RISCV_PCREL_LO12_I, Val); } return; } - case R_RISCV_GOT_HI20: case R_RISCV_PCREL_HI20: - case R_RISCV_TLS_GD_HI20: - case R_RISCV_TLS_GOT_HI20: - case R_RISCV_TPREL_HI20: case R_RISCV_HI20: { - uint64_t hi = val + 0x800; - checkInt(loc, SignExtend64(hi, bits) >> 12, 20, type); - write32le(loc, (read32le(loc) & 0xFFF) | (hi & 0xFFFFF000)); + uint64_t Hi = Val + 0x800; + checkInt(Loc, SignExtend64(Hi, Bits) >> 12, 20, Type); + write32le(Loc, (read32le(Loc) & 0xFFF) | (Hi & 0xFFFFF000)); return; } case R_RISCV_PCREL_LO12_I: - case R_RISCV_TPREL_LO12_I: case R_RISCV_LO12_I: { - uint64_t hi = (val + 0x800) >> 12; - uint64_t lo = val - (hi << 12); - write32le(loc, (read32le(loc) & 0xFFFFF) | ((lo & 0xFFF) << 20)); + uint64_t Hi = (Val + 0x800) >> 12; + uint64_t Lo = Val - (Hi << 12); + write32le(Loc, (read32le(Loc) & 0xFFFFF) | ((Lo & 0xFFF) << 20)); return; } case R_RISCV_PCREL_LO12_S: - case R_RISCV_TPREL_LO12_S: case R_RISCV_LO12_S: { - uint64_t hi = (val + 0x800) >> 12; - uint64_t lo = val - (hi << 12); - uint32_t imm11_5 = extractBits(lo, 11, 5) << 25; - uint32_t imm4_0 = extractBits(lo, 4, 0) << 7; - write32le(loc, (read32le(loc) & 0x1FFF07F) | imm11_5 | imm4_0); + uint64_t Hi = (Val + 0x800) >> 12; + uint64_t Lo = Val - (Hi << 12); + uint32_t Imm11_5 = extractBits(Lo, 11, 5) << 25; + uint32_t Imm4_0 = extractBits(Lo, 4, 0) << 7; + write32le(Loc, (read32le(Loc) & 0x1FFF07F) | Imm11_5 | Imm4_0); return; } case R_RISCV_ADD8: - *loc += val; + *Loc += Val; return; case R_RISCV_ADD16: - write16le(loc, read16le(loc) + val); + write16le(Loc, read16le(Loc) + Val); return; case R_RISCV_ADD32: - write32le(loc, read32le(loc) + val); + write32le(Loc, read32le(Loc) + Val); return; case R_RISCV_ADD64: - write64le(loc, read64le(loc) + val); + write64le(Loc, read64le(Loc) + Val); return; case R_RISCV_SUB6: - *loc = (*loc & 0xc0) | (((*loc & 0x3f) - val) & 0x3f); + *Loc = (*Loc & 0xc0) | (((*Loc & 0x3f) - Val) & 0x3f); return; case R_RISCV_SUB8: - *loc -= val; + *Loc -= Val; return; case R_RISCV_SUB16: - write16le(loc, read16le(loc) - val); + write16le(Loc, read16le(Loc) - Val); return; case R_RISCV_SUB32: - write32le(loc, read32le(loc) - val); + write32le(Loc, read32le(Loc) - Val); return; case R_RISCV_SUB64: - write64le(loc, read64le(loc) - val); + write64le(Loc, read64le(Loc) - Val); return; case R_RISCV_SET6: - *loc = (*loc & 0xc0) | (val & 0x3f); + *Loc = (*Loc & 0xc0) | (Val & 0x3f); return; case R_RISCV_SET8: - *loc = val; + *Loc = Val; return; case R_RISCV_SET16: - write16le(loc, val); + write16le(Loc, Val); return; case R_RISCV_SET32: case R_RISCV_32_PCREL: - write32le(loc, val); + write32le(Loc, Val); return; - case R_RISCV_TLS_DTPREL32: - write32le(loc, val - dtpOffset); - break; - case R_RISCV_TLS_DTPREL64: - write64le(loc, val - dtpOffset); - break; - case R_RISCV_ALIGN: case R_RISCV_RELAX: return; // Ignored (for now) @@ -430,13 +281,13 @@ void RISCV::relocateOne(uint8_t *loc, const RelType type, case R_RISCV_GPREL_I: case R_RISCV_GPREL_S: default: - error(getErrorLocation(loc) + - "unimplemented relocation: " + toString(type)); + error(getErrorLocation(Loc) + + "unimplemented relocation: " + toString(Type)); return; } } TargetInfo *elf::getRISCVTargetInfo() { - static RISCV target; - return ⌖ + static RISCV Target; + return &Target; } diff --git a/lld/ELF/Arch/SPARCV9.cpp b/lld/ELF/Arch/SPARCV9.cpp index 5299206dd919f3..7d85f8697ec4da 100644 --- a/lld/ELF/Arch/SPARCV9.cpp +++ b/lld/ELF/Arch/SPARCV9.cpp @@ -23,32 +23,32 @@ namespace { class SPARCV9 final : public TargetInfo { public: SPARCV9(); - RelExpr getRelExpr(RelType type, const Symbol &s, - const uint8_t *loc) const override; - void writePlt(uint8_t *buf, uint64_t gotEntryAddr, uint64_t pltEntryAddr, - int32_t index, unsigned relOff) const override; - void relocateOne(uint8_t *loc, RelType type, uint64_t val) const override; + RelExpr getRelExpr(RelType Type, const Symbol &S, + const uint8_t *Loc) const override; + void writePlt(uint8_t *Buf, uint64_t GotEntryAddr, uint64_t PltEntryAddr, + int32_t Index, unsigned RelOff) const override; + void relocateOne(uint8_t *Loc, RelType Type, uint64_t Val) const override; }; } // namespace SPARCV9::SPARCV9() { - copyRel = R_SPARC_COPY; - gotRel = R_SPARC_GLOB_DAT; - noneRel = R_SPARC_NONE; - pltRel = R_SPARC_JMP_SLOT; - relativeRel = R_SPARC_RELATIVE; - symbolicRel = R_SPARC_64; - pltEntrySize = 32; - pltHeaderSize = 4 * pltEntrySize; + CopyRel = R_SPARC_COPY; + GotRel = R_SPARC_GLOB_DAT; + NoneRel = R_SPARC_NONE; + PltRel = R_SPARC_JMP_SLOT; + RelativeRel = R_SPARC_RELATIVE; + SymbolicRel = R_SPARC_64; + PltEntrySize = 32; + PltHeaderSize = 4 * PltEntrySize; - defaultCommonPageSize = 8192; - defaultMaxPageSize = 0x100000; - defaultImageBase = 0x100000; + DefaultCommonPageSize = 8192; + DefaultMaxPageSize = 0x100000; + DefaultImageBase = 0x100000; } -RelExpr SPARCV9::getRelExpr(RelType type, const Symbol &s, - const uint8_t *loc) const { - switch (type) { +RelExpr SPARCV9::getRelExpr(RelType Type, const Symbol &S, + const uint8_t *Loc) const { + switch (Type) { case R_SPARC_32: case R_SPARC_UA32: case R_SPARC_64: @@ -68,65 +68,65 @@ RelExpr SPARCV9::getRelExpr(RelType type, const Symbol &s, case R_SPARC_NONE: return R_NONE; default: - error(getErrorLocation(loc) + "unknown relocation (" + Twine(type) + - ") against symbol " + toString(s)); + error(getErrorLocation(Loc) + "unknown relocation (" + Twine(Type) + + ") against symbol " + toString(S)); return R_NONE; } } -void SPARCV9::relocateOne(uint8_t *loc, RelType type, uint64_t val) const { - switch (type) { +void SPARCV9::relocateOne(uint8_t *Loc, RelType Type, uint64_t Val) const { + switch (Type) { case R_SPARC_32: case R_SPARC_UA32: // V-word32 - checkUInt(loc, val, 32, type); - write32be(loc, val); + checkUInt(Loc, Val, 32, Type); + write32be(Loc, Val); break; case R_SPARC_DISP32: // V-disp32 - checkInt(loc, val, 32, type); - write32be(loc, val); + checkInt(Loc, Val, 32, Type); + write32be(Loc, Val); break; case R_SPARC_WDISP30: case R_SPARC_WPLT30: // V-disp30 - checkInt(loc, val, 32, type); - write32be(loc, (read32be(loc) & ~0x3fffffff) | ((val >> 2) & 0x3fffffff)); + checkInt(Loc, Val, 32, Type); + write32be(Loc, (read32be(Loc) & ~0x3fffffff) | ((Val >> 2) & 0x3fffffff)); break; case R_SPARC_22: // V-imm22 - checkUInt(loc, val, 22, type); - write32be(loc, (read32be(loc) & ~0x003fffff) | (val & 0x003fffff)); + checkUInt(Loc, Val, 22, Type); + write32be(Loc, (read32be(Loc) & ~0x003fffff) | (Val & 0x003fffff)); break; case R_SPARC_GOT22: case R_SPARC_PC22: // T-imm22 - write32be(loc, (read32be(loc) & ~0x003fffff) | ((val >> 10) & 0x003fffff)); + write32be(Loc, (read32be(Loc) & ~0x003fffff) | ((Val >> 10) & 0x003fffff)); break; case R_SPARC_WDISP19: // V-disp19 - checkInt(loc, val, 21, type); - write32be(loc, (read32be(loc) & ~0x0007ffff) | ((val >> 2) & 0x0007ffff)); + checkInt(Loc, Val, 21, Type); + write32be(Loc, (read32be(Loc) & ~0x0007ffff) | ((Val >> 2) & 0x0007ffff)); break; case R_SPARC_GOT10: case R_SPARC_PC10: // T-simm10 - write32be(loc, (read32be(loc) & ~0x000003ff) | (val & 0x000003ff)); + write32be(Loc, (read32be(Loc) & ~0x000003ff) | (Val & 0x000003ff)); break; case R_SPARC_64: case R_SPARC_UA64: // V-xword64 - write64be(loc, val); + write64be(Loc, Val); break; default: llvm_unreachable("unknown relocation"); } } -void SPARCV9::writePlt(uint8_t *buf, uint64_t gotEntryAddr, - uint64_t pltEntryAddr, int32_t index, - unsigned relOff) const { - const uint8_t pltData[] = { +void SPARCV9::writePlt(uint8_t *Buf, uint64_t GotEntryAddr, + uint64_t PltEntryAddr, int32_t Index, + unsigned RelOff) const { + const uint8_t PltData[] = { 0x03, 0x00, 0x00, 0x00, // sethi (. - .PLT0), %g1 0x30, 0x68, 0x00, 0x00, // ba,a %xcc, .PLT1 0x01, 0x00, 0x00, 0x00, // nop @@ -136,14 +136,14 @@ void SPARCV9::writePlt(uint8_t *buf, uint64_t gotEntryAddr, 0x01, 0x00, 0x00, 0x00, // nop 0x01, 0x00, 0x00, 0x00 // nop }; - memcpy(buf, pltData, sizeof(pltData)); + memcpy(Buf, PltData, sizeof(PltData)); - uint64_t off = pltHeaderSize + pltEntrySize * index; - relocateOne(buf, R_SPARC_22, off); - relocateOne(buf + 4, R_SPARC_WDISP19, -(off + 4 - pltEntrySize)); + uint64_t Off = PltHeaderSize + PltEntrySize * Index; + relocateOne(Buf, R_SPARC_22, Off); + relocateOne(Buf + 4, R_SPARC_WDISP19, -(Off + 4 - PltEntrySize)); } TargetInfo *elf::getSPARCV9TargetInfo() { - static SPARCV9 target; - return ⌖ + static SPARCV9 Target; + return &Target; } diff --git a/lld/ELF/Arch/X86.cpp b/lld/ELF/Arch/X86.cpp index e1dd231e8e8d46..ebc59ab2895d53 100644 --- a/lld/ELF/Arch/X86.cpp +++ b/lld/ELF/Arch/X86.cpp @@ -23,63 +23,63 @@ namespace { class X86 : public TargetInfo { public: X86(); - int getTlsGdRelaxSkip(RelType type) const override; - RelExpr getRelExpr(RelType type, const Symbol &s, - const uint8_t *loc) const override; - int64_t getImplicitAddend(const uint8_t *buf, RelType type) const override; - void writeGotPltHeader(uint8_t *buf) const override; - RelType getDynRel(RelType type) const override; - void writeGotPlt(uint8_t *buf, const Symbol &s) const override; - void writeIgotPlt(uint8_t *buf, const Symbol &s) const override; - void writePltHeader(uint8_t *buf) const override; - void writePlt(uint8_t *buf, uint64_t gotPltEntryAddr, uint64_t pltEntryAddr, - int32_t index, unsigned relOff) const override; - void relocateOne(uint8_t *loc, RelType type, uint64_t val) const override; - - RelExpr adjustRelaxExpr(RelType type, const uint8_t *data, - RelExpr expr) const override; - void relaxTlsGdToIe(uint8_t *loc, RelType type, uint64_t val) const override; - void relaxTlsGdToLe(uint8_t *loc, RelType type, uint64_t val) const override; - void relaxTlsIeToLe(uint8_t *loc, RelType type, uint64_t val) const override; - void relaxTlsLdToLe(uint8_t *loc, RelType type, uint64_t val) const override; + int getTlsGdRelaxSkip(RelType Type) const override; + RelExpr getRelExpr(RelType Type, const Symbol &S, + const uint8_t *Loc) const override; + int64_t getImplicitAddend(const uint8_t *Buf, RelType Type) const override; + void writeGotPltHeader(uint8_t *Buf) const override; + RelType getDynRel(RelType Type) const override; + void writeGotPlt(uint8_t *Buf, const Symbol &S) const override; + void writeIgotPlt(uint8_t *Buf, const Symbol &S) const override; + void writePltHeader(uint8_t *Buf) const override; + void writePlt(uint8_t *Buf, uint64_t GotPltEntryAddr, uint64_t PltEntryAddr, + int32_t Index, unsigned RelOff) const override; + void relocateOne(uint8_t *Loc, RelType Type, uint64_t Val) const override; + + RelExpr adjustRelaxExpr(RelType Type, const uint8_t *Data, + RelExpr Expr) const override; + void relaxTlsGdToIe(uint8_t *Loc, RelType Type, uint64_t Val) const override; + void relaxTlsGdToLe(uint8_t *Loc, RelType Type, uint64_t Val) const override; + void relaxTlsIeToLe(uint8_t *Loc, RelType Type, uint64_t Val) const override; + void relaxTlsLdToLe(uint8_t *Loc, RelType Type, uint64_t Val) const override; }; } // namespace X86::X86() { - copyRel = R_386_COPY; - gotRel = R_386_GLOB_DAT; - noneRel = R_386_NONE; - pltRel = R_386_JUMP_SLOT; - iRelativeRel = R_386_IRELATIVE; - relativeRel = R_386_RELATIVE; - symbolicRel = R_386_32; - tlsGotRel = R_386_TLS_TPOFF; - tlsModuleIndexRel = R_386_TLS_DTPMOD32; - tlsOffsetRel = R_386_TLS_DTPOFF32; - pltEntrySize = 16; - pltHeaderSize = 16; - trapInstr = {0xcc, 0xcc, 0xcc, 0xcc}; // 0xcc = INT3 + CopyRel = R_386_COPY; + GotRel = R_386_GLOB_DAT; + NoneRel = R_386_NONE; + PltRel = R_386_JUMP_SLOT; + IRelativeRel = R_386_IRELATIVE; + RelativeRel = R_386_RELATIVE; + SymbolicRel = R_386_32; + TlsGotRel = R_386_TLS_TPOFF; + TlsModuleIndexRel = R_386_TLS_DTPMOD32; + TlsOffsetRel = R_386_TLS_DTPOFF32; + PltEntrySize = 16; + PltHeaderSize = 16; + TrapInstr = {0xcc, 0xcc, 0xcc, 0xcc}; // 0xcc = INT3 // Align to the non-PAE large page size (known as a superpage or huge page). // FreeBSD automatically promotes large, superpage-aligned allocations. - defaultImageBase = 0x400000; + DefaultImageBase = 0x400000; } -int X86::getTlsGdRelaxSkip(RelType type) const { +int X86::getTlsGdRelaxSkip(RelType Type) const { return 2; } -RelExpr X86::getRelExpr(RelType type, const Symbol &s, - const uint8_t *loc) const { +RelExpr X86::getRelExpr(RelType Type, const Symbol &S, + const uint8_t *Loc) const { // There are 4 different TLS variable models with varying degrees of // flexibility and performance. LocalExec and InitialExec models are fast but // less-flexible models. If they are in use, we set DF_STATIC_TLS flag in the // dynamic section to let runtime know about that. - if (type == R_386_TLS_LE || type == R_386_TLS_LE_32 || type == R_386_TLS_IE || - type == R_386_TLS_GOTIE) - config->hasStaticTlsModel = true; + if (Type == R_386_TLS_LE || Type == R_386_TLS_LE_32 || Type == R_386_TLS_IE || + Type == R_386_TLS_GOTIE) + Config->HasStaticTlsModel = true; - switch (type) { + switch (Type) { case R_386_8: case R_386_16: case R_386_32: @@ -137,7 +137,7 @@ RelExpr X86::getRelExpr(RelType type, const Symbol &s, // instruction. That means a ModRM byte is at Loc[-1]. By taking a look at // the byte, we can determine whether the instruction uses the operand as an // absolute address (R_GOT) or a register-relative address (R_GOTPLT). - return (loc[-1] & 0xc7) == 0x5 ? R_GOT : R_GOTPLT; + return (Loc[-1] & 0xc7) == 0x5 ? R_GOT : R_GOTPLT; case R_386_TLS_GOTIE: return R_GOTPLT; case R_386_GOTOFF: @@ -149,17 +149,17 @@ RelExpr X86::getRelExpr(RelType type, const Symbol &s, case R_386_NONE: return R_NONE; default: - error(getErrorLocation(loc) + "unknown relocation (" + Twine(type) + - ") against symbol " + toString(s)); + error(getErrorLocation(Loc) + "unknown relocation (" + Twine(Type) + + ") against symbol " + toString(S)); return R_NONE; } } -RelExpr X86::adjustRelaxExpr(RelType type, const uint8_t *data, - RelExpr expr) const { - switch (expr) { +RelExpr X86::adjustRelaxExpr(RelType Type, const uint8_t *Data, + RelExpr Expr) const { + switch (Expr) { default: - return expr; + return Expr; case R_RELAX_TLS_GD_TO_IE: return R_RELAX_TLS_GD_TO_IE_GOTPLT; case R_RELAX_TLS_GD_TO_LE: @@ -167,84 +167,84 @@ RelExpr X86::adjustRelaxExpr(RelType type, const uint8_t *data, } } -void X86::writeGotPltHeader(uint8_t *buf) const { - write32le(buf, mainPart->dynamic->getVA()); +void X86::writeGotPltHeader(uint8_t *Buf) const { + write32le(Buf, Main->Dynamic->getVA()); } -void X86::writeGotPlt(uint8_t *buf, const Symbol &s) const { +void X86::writeGotPlt(uint8_t *Buf, const Symbol &S) const { // Entries in .got.plt initially points back to the corresponding // PLT entries with a fixed offset to skip the first instruction. - write32le(buf, s.getPltVA() + 6); + write32le(Buf, S.getPltVA() + 6); } -void X86::writeIgotPlt(uint8_t *buf, const Symbol &s) const { +void X86::writeIgotPlt(uint8_t *Buf, const Symbol &S) const { // An x86 entry is the address of the ifunc resolver function. - write32le(buf, s.getVA()); + write32le(Buf, S.getVA()); } -RelType X86::getDynRel(RelType type) const { - if (type == R_386_TLS_LE) +RelType X86::getDynRel(RelType Type) const { + if (Type == R_386_TLS_LE) return R_386_TLS_TPOFF; - if (type == R_386_TLS_LE_32) + if (Type == R_386_TLS_LE_32) return R_386_TLS_TPOFF32; - return type; + return Type; } -void X86::writePltHeader(uint8_t *buf) const { - if (config->isPic) { - const uint8_t v[] = { +void X86::writePltHeader(uint8_t *Buf) const { + if (Config->Pic) { + const uint8_t V[] = { 0xff, 0xb3, 0x04, 0x00, 0x00, 0x00, // pushl 4(%ebx) 0xff, 0xa3, 0x08, 0x00, 0x00, 0x00, // jmp *8(%ebx) 0x90, 0x90, 0x90, 0x90 // nop }; - memcpy(buf, v, sizeof(v)); + memcpy(Buf, V, sizeof(V)); return; } - const uint8_t pltData[] = { + const uint8_t PltData[] = { 0xff, 0x35, 0, 0, 0, 0, // pushl (GOTPLT+4) 0xff, 0x25, 0, 0, 0, 0, // jmp *(GOTPLT+8) 0x90, 0x90, 0x90, 0x90, // nop }; - memcpy(buf, pltData, sizeof(pltData)); - uint32_t gotPlt = in.gotPlt->getVA(); - write32le(buf + 2, gotPlt + 4); - write32le(buf + 8, gotPlt + 8); + memcpy(Buf, PltData, sizeof(PltData)); + uint32_t GotPlt = In.GotPlt->getVA(); + write32le(Buf + 2, GotPlt + 4); + write32le(Buf + 8, GotPlt + 8); } -void X86::writePlt(uint8_t *buf, uint64_t gotPltEntryAddr, - uint64_t pltEntryAddr, int32_t index, - unsigned relOff) const { - if (config->isPic) { - const uint8_t inst[] = { +void X86::writePlt(uint8_t *Buf, uint64_t GotPltEntryAddr, + uint64_t PltEntryAddr, int32_t Index, + unsigned RelOff) const { + if (Config->Pic) { + const uint8_t Inst[] = { 0xff, 0xa3, 0, 0, 0, 0, // jmp *foo@GOT(%ebx) 0x68, 0, 0, 0, 0, // pushl $reloc_offset 0xe9, 0, 0, 0, 0, // jmp .PLT0@PC }; - memcpy(buf, inst, sizeof(inst)); - write32le(buf + 2, gotPltEntryAddr - in.gotPlt->getVA()); + memcpy(Buf, Inst, sizeof(Inst)); + write32le(Buf + 2, GotPltEntryAddr - In.GotPlt->getVA()); } else { - const uint8_t inst[] = { + const uint8_t Inst[] = { 0xff, 0x25, 0, 0, 0, 0, // jmp *foo@GOT 0x68, 0, 0, 0, 0, // pushl $reloc_offset 0xe9, 0, 0, 0, 0, // jmp .PLT0@PC }; - memcpy(buf, inst, sizeof(inst)); - write32le(buf + 2, gotPltEntryAddr); + memcpy(Buf, Inst, sizeof(Inst)); + write32le(Buf + 2, GotPltEntryAddr); } - write32le(buf + 7, relOff); - write32le(buf + 12, -pltHeaderSize - pltEntrySize * index - 16); + write32le(Buf + 7, RelOff); + write32le(Buf + 12, -PltHeaderSize - PltEntrySize * Index - 16); } -int64_t X86::getImplicitAddend(const uint8_t *buf, RelType type) const { - switch (type) { +int64_t X86::getImplicitAddend(const uint8_t *Buf, RelType Type) const { + switch (Type) { case R_386_8: case R_386_PC8: - return SignExtend64<8>(*buf); + return SignExtend64<8>(*Buf); case R_386_16: case R_386_PC16: - return SignExtend64<16>(read16le(buf)); + return SignExtend64<16>(read16le(Buf)); case R_386_32: case R_386_GOT32: case R_386_GOT32X: @@ -254,28 +254,28 @@ int64_t X86::getImplicitAddend(const uint8_t *buf, RelType type) const { case R_386_PLT32: case R_386_TLS_LDO_32: case R_386_TLS_LE: - return SignExtend64<32>(read32le(buf)); + return SignExtend64<32>(read32le(Buf)); default: return 0; } } -void X86::relocateOne(uint8_t *loc, RelType type, uint64_t val) const { - switch (type) { +void X86::relocateOne(uint8_t *Loc, RelType Type, uint64_t Val) const { + switch (Type) { case R_386_8: // R_386_{PC,}{8,16} are not part of the i386 psABI, but they are // being used for some 16-bit programs such as boot loaders, so // we want to support them. - checkIntUInt(loc, val, 8, type); - *loc = val; + checkIntUInt(Loc, Val, 8, Type); + *Loc = Val; break; case R_386_PC8: - checkInt(loc, val, 8, type); - *loc = val; + checkInt(Loc, Val, 8, Type); + *Loc = Val; break; case R_386_16: - checkIntUInt(loc, val, 16, type); - write16le(loc, val); + checkIntUInt(Loc, Val, 16, Type); + write16le(Loc, Val); break; case R_386_PC16: // R_386_PC16 is normally used with 16 bit code. In that situation @@ -288,8 +288,8 @@ void X86::relocateOne(uint8_t *loc, RelType type, uint64_t val) const { // current location subtracted from it. // We just check that Val fits in 17 bits. This misses some cases, but // should have no false positives. - checkInt(loc, val, 17, type); - write16le(loc, val); + checkInt(Loc, Val, 17, Type); + write16le(Loc, Val); break; case R_386_32: case R_386_GOT32: @@ -310,86 +310,86 @@ void X86::relocateOne(uint8_t *loc, RelType type, uint64_t val) const { case R_386_TLS_LE_32: case R_386_TLS_TPOFF: case R_386_TLS_TPOFF32: - checkInt(loc, val, 32, type); - write32le(loc, val); + checkInt(Loc, Val, 32, Type); + write32le(Loc, Val); break; default: llvm_unreachable("unknown relocation"); } } -void X86::relaxTlsGdToLe(uint8_t *loc, RelType type, uint64_t val) const { +void X86::relaxTlsGdToLe(uint8_t *Loc, RelType Type, uint64_t Val) const { // Convert // leal x@tlsgd(, %ebx, 1), // call __tls_get_addr@plt // to // movl %gs:0,%eax // subl $x@ntpoff,%eax - const uint8_t inst[] = { + const uint8_t Inst[] = { 0x65, 0xa1, 0x00, 0x00, 0x00, 0x00, // movl %gs:0, %eax 0x81, 0xe8, 0, 0, 0, 0, // subl Val(%ebx), %eax }; - memcpy(loc - 3, inst, sizeof(inst)); - write32le(loc + 5, val); + memcpy(Loc - 3, Inst, sizeof(Inst)); + write32le(Loc + 5, Val); } -void X86::relaxTlsGdToIe(uint8_t *loc, RelType type, uint64_t val) const { +void X86::relaxTlsGdToIe(uint8_t *Loc, RelType Type, uint64_t Val) const { // Convert // leal x@tlsgd(, %ebx, 1), // call __tls_get_addr@plt // to // movl %gs:0, %eax // addl x@gotntpoff(%ebx), %eax - const uint8_t inst[] = { + const uint8_t Inst[] = { 0x65, 0xa1, 0x00, 0x00, 0x00, 0x00, // movl %gs:0, %eax 0x03, 0x83, 0, 0, 0, 0, // addl Val(%ebx), %eax }; - memcpy(loc - 3, inst, sizeof(inst)); - write32le(loc + 5, val); + memcpy(Loc - 3, Inst, sizeof(Inst)); + write32le(Loc + 5, Val); } // In some conditions, relocations can be optimized to avoid using GOT. // This function does that for Initial Exec to Local Exec case. -void X86::relaxTlsIeToLe(uint8_t *loc, RelType type, uint64_t val) const { +void X86::relaxTlsIeToLe(uint8_t *Loc, RelType Type, uint64_t Val) const { // Ulrich's document section 6.2 says that @gotntpoff can // be used with MOVL or ADDL instructions. // @indntpoff is similar to @gotntpoff, but for use in // position dependent code. - uint8_t reg = (loc[-1] >> 3) & 7; + uint8_t Reg = (Loc[-1] >> 3) & 7; - if (type == R_386_TLS_IE) { - if (loc[-1] == 0xa1) { + if (Type == R_386_TLS_IE) { + if (Loc[-1] == 0xa1) { // "movl foo@indntpoff,%eax" -> "movl $foo,%eax" // This case is different from the generic case below because // this is a 5 byte instruction while below is 6 bytes. - loc[-1] = 0xb8; - } else if (loc[-2] == 0x8b) { + Loc[-1] = 0xb8; + } else if (Loc[-2] == 0x8b) { // "movl foo@indntpoff,%reg" -> "movl $foo,%reg" - loc[-2] = 0xc7; - loc[-1] = 0xc0 | reg; + Loc[-2] = 0xc7; + Loc[-1] = 0xc0 | Reg; } else { // "addl foo@indntpoff,%reg" -> "addl $foo,%reg" - loc[-2] = 0x81; - loc[-1] = 0xc0 | reg; + Loc[-2] = 0x81; + Loc[-1] = 0xc0 | Reg; } } else { - assert(type == R_386_TLS_GOTIE); - if (loc[-2] == 0x8b) { + assert(Type == R_386_TLS_GOTIE); + if (Loc[-2] == 0x8b) { // "movl foo@gottpoff(%rip),%reg" -> "movl $foo,%reg" - loc[-2] = 0xc7; - loc[-1] = 0xc0 | reg; + Loc[-2] = 0xc7; + Loc[-1] = 0xc0 | Reg; } else { // "addl foo@gotntpoff(%rip),%reg" -> "leal foo(%reg),%reg" - loc[-2] = 0x8d; - loc[-1] = 0x80 | (reg << 3) | reg; + Loc[-2] = 0x8d; + Loc[-1] = 0x80 | (Reg << 3) | Reg; } } - write32le(loc, val); + write32le(Loc, Val); } -void X86::relaxTlsLdToLe(uint8_t *loc, RelType type, uint64_t val) const { - if (type == R_386_TLS_LDO_32) { - write32le(loc, val); +void X86::relaxTlsLdToLe(uint8_t *Loc, RelType Type, uint64_t Val) const { + if (Type == R_386_TLS_LDO_32) { + write32le(Loc, Val); return; } @@ -400,45 +400,45 @@ void X86::relaxTlsLdToLe(uint8_t *loc, RelType type, uint64_t val) const { // movl %gs:0,%eax // nop // leal 0(%esi,1),%esi - const uint8_t inst[] = { + const uint8_t Inst[] = { 0x65, 0xa1, 0x00, 0x00, 0x00, 0x00, // movl %gs:0,%eax 0x90, // nop 0x8d, 0x74, 0x26, 0x00, // leal 0(%esi,1),%esi }; - memcpy(loc - 2, inst, sizeof(inst)); + memcpy(Loc - 2, Inst, sizeof(Inst)); } namespace { class RetpolinePic : public X86 { public: RetpolinePic(); - void writeGotPlt(uint8_t *buf, const Symbol &s) const override; - void writePltHeader(uint8_t *buf) const override; - void writePlt(uint8_t *buf, uint64_t gotPltEntryAddr, uint64_t pltEntryAddr, - int32_t index, unsigned relOff) const override; + void writeGotPlt(uint8_t *Buf, const Symbol &S) const override; + void writePltHeader(uint8_t *Buf) const override; + void writePlt(uint8_t *Buf, uint64_t GotPltEntryAddr, uint64_t PltEntryAddr, + int32_t Index, unsigned RelOff) const override; }; class RetpolineNoPic : public X86 { public: RetpolineNoPic(); - void writeGotPlt(uint8_t *buf, const Symbol &s) const override; - void writePltHeader(uint8_t *buf) const override; - void writePlt(uint8_t *buf, uint64_t gotPltEntryAddr, uint64_t pltEntryAddr, - int32_t index, unsigned relOff) const override; + void writeGotPlt(uint8_t *Buf, const Symbol &S) const override; + void writePltHeader(uint8_t *Buf) const override; + void writePlt(uint8_t *Buf, uint64_t GotPltEntryAddr, uint64_t PltEntryAddr, + int32_t Index, unsigned RelOff) const override; }; } // namespace RetpolinePic::RetpolinePic() { - pltHeaderSize = 48; - pltEntrySize = 32; + PltHeaderSize = 48; + PltEntrySize = 32; } -void RetpolinePic::writeGotPlt(uint8_t *buf, const Symbol &s) const { - write32le(buf, s.getPltVA() + 17); +void RetpolinePic::writeGotPlt(uint8_t *Buf, const Symbol &S) const { + write32le(Buf, S.getPltVA() + 17); } -void RetpolinePic::writePltHeader(uint8_t *buf) const { - const uint8_t insn[] = { +void RetpolinePic::writePltHeader(uint8_t *Buf) const { + const uint8_t Insn[] = { 0xff, 0xb3, 4, 0, 0, 0, // 0: pushl 4(%ebx) 0x50, // 6: pushl %eax 0x8b, 0x83, 8, 0, 0, 0, // 7: mov 8(%ebx), %eax @@ -455,13 +455,13 @@ void RetpolinePic::writePltHeader(uint8_t *buf) const { 0xc3, // 2e: ret 0xcc, // 2f: int3; padding }; - memcpy(buf, insn, sizeof(insn)); + memcpy(Buf, Insn, sizeof(Insn)); } -void RetpolinePic::writePlt(uint8_t *buf, uint64_t gotPltEntryAddr, - uint64_t pltEntryAddr, int32_t index, - unsigned relOff) const { - const uint8_t insn[] = { +void RetpolinePic::writePlt(uint8_t *Buf, uint64_t GotPltEntryAddr, + uint64_t PltEntryAddr, int32_t Index, + unsigned RelOff) const { + const uint8_t Insn[] = { 0x50, // pushl %eax 0x8b, 0x83, 0, 0, 0, 0, // mov foo@GOT(%ebx), %eax 0xe8, 0, 0, 0, 0, // call plt+0x20 @@ -470,28 +470,28 @@ void RetpolinePic::writePlt(uint8_t *buf, uint64_t gotPltEntryAddr, 0xe9, 0, 0, 0, 0, // jmp plt+0 0xcc, 0xcc, 0xcc, 0xcc, 0xcc, // int3; padding }; - memcpy(buf, insn, sizeof(insn)); - - uint32_t ebx = in.gotPlt->getVA(); - unsigned off = pltHeaderSize + pltEntrySize * index; - write32le(buf + 3, gotPltEntryAddr - ebx); - write32le(buf + 8, -off - 12 + 32); - write32le(buf + 13, -off - 17 + 18); - write32le(buf + 18, relOff); - write32le(buf + 23, -off - 27); + memcpy(Buf, Insn, sizeof(Insn)); + + uint32_t Ebx = In.GotPlt->getVA(); + unsigned Off = PltHeaderSize + PltEntrySize * Index; + write32le(Buf + 3, GotPltEntryAddr - Ebx); + write32le(Buf + 8, -Off - 12 + 32); + write32le(Buf + 13, -Off - 17 + 18); + write32le(Buf + 18, RelOff); + write32le(Buf + 23, -Off - 27); } RetpolineNoPic::RetpolineNoPic() { - pltHeaderSize = 48; - pltEntrySize = 32; + PltHeaderSize = 48; + PltEntrySize = 32; } -void RetpolineNoPic::writeGotPlt(uint8_t *buf, const Symbol &s) const { - write32le(buf, s.getPltVA() + 16); +void RetpolineNoPic::writeGotPlt(uint8_t *Buf, const Symbol &S) const { + write32le(Buf, S.getPltVA() + 16); } -void RetpolineNoPic::writePltHeader(uint8_t *buf) const { - const uint8_t insn[] = { +void RetpolineNoPic::writePltHeader(uint8_t *Buf) const { + const uint8_t Insn[] = { 0xff, 0x35, 0, 0, 0, 0, // 0: pushl GOTPLT+4 0x50, // 6: pushl %eax 0xa1, 0, 0, 0, 0, // 7: mov GOTPLT+8, %eax @@ -509,17 +509,17 @@ void RetpolineNoPic::writePltHeader(uint8_t *buf) const { 0xc3, // 2e: ret 0xcc, // 2f: int3; padding }; - memcpy(buf, insn, sizeof(insn)); + memcpy(Buf, Insn, sizeof(Insn)); - uint32_t gotPlt = in.gotPlt->getVA(); - write32le(buf + 2, gotPlt + 4); - write32le(buf + 8, gotPlt + 8); + uint32_t GotPlt = In.GotPlt->getVA(); + write32le(Buf + 2, GotPlt + 4); + write32le(Buf + 8, GotPlt + 8); } -void RetpolineNoPic::writePlt(uint8_t *buf, uint64_t gotPltEntryAddr, - uint64_t pltEntryAddr, int32_t index, - unsigned relOff) const { - const uint8_t insn[] = { +void RetpolineNoPic::writePlt(uint8_t *Buf, uint64_t GotPltEntryAddr, + uint64_t PltEntryAddr, int32_t Index, + unsigned RelOff) const { + const uint8_t Insn[] = { 0x50, // 0: pushl %eax 0xa1, 0, 0, 0, 0, // 1: mov foo_in_GOT, %eax 0xe8, 0, 0, 0, 0, // 6: call plt+0x20 @@ -529,26 +529,26 @@ void RetpolineNoPic::writePlt(uint8_t *buf, uint64_t gotPltEntryAddr, 0xcc, 0xcc, 0xcc, 0xcc, 0xcc, // 1a: int3; padding 0xcc, // 1f: int3; padding }; - memcpy(buf, insn, sizeof(insn)); - - unsigned off = pltHeaderSize + pltEntrySize * index; - write32le(buf + 2, gotPltEntryAddr); - write32le(buf + 7, -off - 11 + 32); - write32le(buf + 12, -off - 16 + 17); - write32le(buf + 17, relOff); - write32le(buf + 22, -off - 26); + memcpy(Buf, Insn, sizeof(Insn)); + + unsigned Off = PltHeaderSize + PltEntrySize * Index; + write32le(Buf + 2, GotPltEntryAddr); + write32le(Buf + 7, -Off - 11 + 32); + write32le(Buf + 12, -Off - 16 + 17); + write32le(Buf + 17, RelOff); + write32le(Buf + 22, -Off - 26); } TargetInfo *elf::getX86TargetInfo() { - if (config->zRetpolineplt) { - if (config->isPic) { - static RetpolinePic t; - return &t; + if (Config->ZRetpolineplt) { + if (Config->Pic) { + static RetpolinePic T; + return &T; } - static RetpolineNoPic t; - return &t; + static RetpolineNoPic T; + return &T; } - static X86 t; - return &t; + static X86 T; + return &T; } diff --git a/lld/ELF/Arch/X86_64.cpp b/lld/ELF/Arch/X86_64.cpp index de67aa5c33dc4c..33c031c440aa12 100644 --- a/lld/ELF/Arch/X86_64.cpp +++ b/lld/ELF/Arch/X86_64.cpp @@ -25,58 +25,58 @@ namespace { class X86_64 : public TargetInfo { public: X86_64(); - int getTlsGdRelaxSkip(RelType type) const override; - RelExpr getRelExpr(RelType type, const Symbol &s, - const uint8_t *loc) const override; - RelType getDynRel(RelType type) const override; - void writeGotPltHeader(uint8_t *buf) const override; - void writeGotPlt(uint8_t *buf, const Symbol &s) const override; - void writePltHeader(uint8_t *buf) const override; - void writePlt(uint8_t *buf, uint64_t gotPltEntryAddr, uint64_t pltEntryAddr, - int32_t index, unsigned relOff) const override; - void relocateOne(uint8_t *loc, RelType type, uint64_t val) const override; - - RelExpr adjustRelaxExpr(RelType type, const uint8_t *data, - RelExpr expr) const override; - void relaxGot(uint8_t *loc, RelType type, uint64_t val) const override; - void relaxTlsGdToIe(uint8_t *loc, RelType type, uint64_t val) const override; - void relaxTlsGdToLe(uint8_t *loc, RelType type, uint64_t val) const override; - void relaxTlsIeToLe(uint8_t *loc, RelType type, uint64_t val) const override; - void relaxTlsLdToLe(uint8_t *loc, RelType type, uint64_t val) const override; - bool adjustPrologueForCrossSplitStack(uint8_t *loc, uint8_t *end, - uint8_t stOther) const override; + int getTlsGdRelaxSkip(RelType Type) const override; + RelExpr getRelExpr(RelType Type, const Symbol &S, + const uint8_t *Loc) const override; + RelType getDynRel(RelType Type) const override; + void writeGotPltHeader(uint8_t *Buf) const override; + void writeGotPlt(uint8_t *Buf, const Symbol &S) const override; + void writePltHeader(uint8_t *Buf) const override; + void writePlt(uint8_t *Buf, uint64_t GotPltEntryAddr, uint64_t PltEntryAddr, + int32_t Index, unsigned RelOff) const override; + void relocateOne(uint8_t *Loc, RelType Type, uint64_t Val) const override; + + RelExpr adjustRelaxExpr(RelType Type, const uint8_t *Data, + RelExpr Expr) const override; + void relaxGot(uint8_t *Loc, RelType Type, uint64_t Val) const override; + void relaxTlsGdToIe(uint8_t *Loc, RelType Type, uint64_t Val) const override; + void relaxTlsGdToLe(uint8_t *Loc, RelType Type, uint64_t Val) const override; + void relaxTlsIeToLe(uint8_t *Loc, RelType Type, uint64_t Val) const override; + void relaxTlsLdToLe(uint8_t *Loc, RelType Type, uint64_t Val) const override; + bool adjustPrologueForCrossSplitStack(uint8_t *Loc, uint8_t *End, + uint8_t StOther) const override; }; } // namespace X86_64::X86_64() { - copyRel = R_X86_64_COPY; - gotRel = R_X86_64_GLOB_DAT; - noneRel = R_X86_64_NONE; - pltRel = R_X86_64_JUMP_SLOT; - relativeRel = R_X86_64_RELATIVE; - iRelativeRel = R_X86_64_IRELATIVE; - symbolicRel = R_X86_64_64; - tlsDescRel = R_X86_64_TLSDESC; - tlsGotRel = R_X86_64_TPOFF64; - tlsModuleIndexRel = R_X86_64_DTPMOD64; - tlsOffsetRel = R_X86_64_DTPOFF64; - pltEntrySize = 16; - pltHeaderSize = 16; - trapInstr = {0xcc, 0xcc, 0xcc, 0xcc}; // 0xcc = INT3 + CopyRel = R_X86_64_COPY; + GotRel = R_X86_64_GLOB_DAT; + NoneRel = R_X86_64_NONE; + PltRel = R_X86_64_JUMP_SLOT; + RelativeRel = R_X86_64_RELATIVE; + IRelativeRel = R_X86_64_IRELATIVE; + SymbolicRel = R_X86_64_64; + TlsDescRel = R_X86_64_TLSDESC; + TlsGotRel = R_X86_64_TPOFF64; + TlsModuleIndexRel = R_X86_64_DTPMOD64; + TlsOffsetRel = R_X86_64_DTPOFF64; + PltEntrySize = 16; + PltHeaderSize = 16; + TrapInstr = {0xcc, 0xcc, 0xcc, 0xcc}; // 0xcc = INT3 // Align to the large page size (known as a superpage or huge page). // FreeBSD automatically promotes large, superpage-aligned allocations. - defaultImageBase = 0x200000; + DefaultImageBase = 0x200000; } -int X86_64::getTlsGdRelaxSkip(RelType type) const { return 2; } +int X86_64::getTlsGdRelaxSkip(RelType Type) const { return 2; } -RelExpr X86_64::getRelExpr(RelType type, const Symbol &s, - const uint8_t *loc) const { - if (type == R_X86_64_GOTTPOFF) - config->hasStaticTlsModel = true; +RelExpr X86_64::getRelExpr(RelType Type, const Symbol &S, + const uint8_t *Loc) const { + if (Type == R_X86_64_GOTTPOFF) + Config->HasStaticTlsModel = true; - switch (type) { + switch (Type) { case R_X86_64_8: case R_X86_64_16: case R_X86_64_32: @@ -122,62 +122,62 @@ RelExpr X86_64::getRelExpr(RelType type, const Symbol &s, case R_X86_64_NONE: return R_NONE; default: - error(getErrorLocation(loc) + "unknown relocation (" + Twine(type) + - ") against symbol " + toString(s)); + error(getErrorLocation(Loc) + "unknown relocation (" + Twine(Type) + + ") against symbol " + toString(S)); return R_NONE; } } -void X86_64::writeGotPltHeader(uint8_t *buf) const { +void X86_64::writeGotPltHeader(uint8_t *Buf) const { // The first entry holds the value of _DYNAMIC. It is not clear why that is // required, but it is documented in the psabi and the glibc dynamic linker // seems to use it (note that this is relevant for linking ld.so, not any // other program). - write64le(buf, mainPart->dynamic->getVA()); + write64le(Buf, Main->Dynamic->getVA()); } -void X86_64::writeGotPlt(uint8_t *buf, const Symbol &s) const { +void X86_64::writeGotPlt(uint8_t *Buf, const Symbol &S) const { // See comments in X86::writeGotPlt. - write64le(buf, s.getPltVA() + 6); + write64le(Buf, S.getPltVA() + 6); } -void X86_64::writePltHeader(uint8_t *buf) const { - const uint8_t pltData[] = { +void X86_64::writePltHeader(uint8_t *Buf) const { + const uint8_t PltData[] = { 0xff, 0x35, 0, 0, 0, 0, // pushq GOTPLT+8(%rip) 0xff, 0x25, 0, 0, 0, 0, // jmp *GOTPLT+16(%rip) 0x0f, 0x1f, 0x40, 0x00, // nop }; - memcpy(buf, pltData, sizeof(pltData)); - uint64_t gotPlt = in.gotPlt->getVA(); - uint64_t plt = in.plt->getVA(); - write32le(buf + 2, gotPlt - plt + 2); // GOTPLT+8 - write32le(buf + 8, gotPlt - plt + 4); // GOTPLT+16 + memcpy(Buf, PltData, sizeof(PltData)); + uint64_t GotPlt = In.GotPlt->getVA(); + uint64_t Plt = In.Plt->getVA(); + write32le(Buf + 2, GotPlt - Plt + 2); // GOTPLT+8 + write32le(Buf + 8, GotPlt - Plt + 4); // GOTPLT+16 } -void X86_64::writePlt(uint8_t *buf, uint64_t gotPltEntryAddr, - uint64_t pltEntryAddr, int32_t index, - unsigned relOff) const { - const uint8_t inst[] = { +void X86_64::writePlt(uint8_t *Buf, uint64_t GotPltEntryAddr, + uint64_t PltEntryAddr, int32_t Index, + unsigned RelOff) const { + const uint8_t Inst[] = { 0xff, 0x25, 0, 0, 0, 0, // jmpq *got(%rip) 0x68, 0, 0, 0, 0, // pushq 0xe9, 0, 0, 0, 0, // jmpq plt[0] }; - memcpy(buf, inst, sizeof(inst)); + memcpy(Buf, Inst, sizeof(Inst)); - write32le(buf + 2, gotPltEntryAddr - pltEntryAddr - 6); - write32le(buf + 7, index); - write32le(buf + 12, -pltHeaderSize - pltEntrySize * index - 16); + write32le(Buf + 2, GotPltEntryAddr - PltEntryAddr - 6); + write32le(Buf + 7, Index); + write32le(Buf + 12, -PltHeaderSize - PltEntrySize * Index - 16); } -RelType X86_64::getDynRel(RelType type) const { - if (type == R_X86_64_64 || type == R_X86_64_PC64 || type == R_X86_64_SIZE32 || - type == R_X86_64_SIZE64) - return type; +RelType X86_64::getDynRel(RelType Type) const { + if (Type == R_X86_64_64 || Type == R_X86_64_PC64 || Type == R_X86_64_SIZE32 || + Type == R_X86_64_SIZE64) + return Type; return R_X86_64_NONE; } -void X86_64::relaxTlsGdToLe(uint8_t *loc, RelType type, uint64_t val) const { - if (type == R_X86_64_TLSGD) { +void X86_64::relaxTlsGdToLe(uint8_t *Loc, RelType Type, uint64_t Val) const { + if (Type == R_X86_64_TLSGD) { // Convert // .byte 0x66 // leaq x@tlsgd(%rip), %rdi @@ -185,39 +185,39 @@ void X86_64::relaxTlsGdToLe(uint8_t *loc, RelType type, uint64_t val) const { // rex64 // call __tls_get_addr@plt // to the following two instructions. - const uint8_t inst[] = { + const uint8_t Inst[] = { 0x64, 0x48, 0x8b, 0x04, 0x25, 0x00, 0x00, 0x00, 0x00, // mov %fs:0x0,%rax 0x48, 0x8d, 0x80, 0, 0, 0, 0, // lea x@tpoff,%rax }; - memcpy(loc - 4, inst, sizeof(inst)); + memcpy(Loc - 4, Inst, sizeof(Inst)); // The original code used a pc relative relocation and so we have to // compensate for the -4 in had in the addend. - write32le(loc + 8, val + 4); + write32le(Loc + 8, Val + 4); } else { // Convert // lea x@tlsgd(%rip), %rax // call *(%rax) // to the following two instructions. - assert(type == R_X86_64_GOTPC32_TLSDESC); - if (memcmp(loc - 3, "\x48\x8d\x05", 3)) { - error(getErrorLocation(loc - 3) + "R_X86_64_GOTPC32_TLSDESC must be used " + assert(Type == R_X86_64_GOTPC32_TLSDESC); + if (memcmp(Loc - 3, "\x48\x8d\x05", 3)) { + error(getErrorLocation(Loc - 3) + "R_X86_64_GOTPC32_TLSDESC must be used " "in callq *x@tlsdesc(%rip), %rax"); return; } // movq $x@tpoff(%rip),%rax - loc[-2] = 0xc7; - loc[-1] = 0xc0; - write32le(loc, val + 4); + Loc[-2] = 0xc7; + Loc[-1] = 0xc0; + write32le(Loc, Val + 4); // xchg ax,ax - loc[4] = 0x66; - loc[5] = 0x90; + Loc[4] = 0x66; + Loc[5] = 0x90; } } -void X86_64::relaxTlsGdToIe(uint8_t *loc, RelType type, uint64_t val) const { - if (type == R_X86_64_TLSGD) { +void X86_64::relaxTlsGdToIe(uint8_t *Loc, RelType Type, uint64_t Val) const { + if (Type == R_X86_64_TLSGD) { // Convert // .byte 0x66 // leaq x@tlsgd(%rip), %rdi @@ -225,96 +225,96 @@ void X86_64::relaxTlsGdToIe(uint8_t *loc, RelType type, uint64_t val) const { // rex64 // call __tls_get_addr@plt // to the following two instructions. - const uint8_t inst[] = { + const uint8_t Inst[] = { 0x64, 0x48, 0x8b, 0x04, 0x25, 0x00, 0x00, 0x00, 0x00, // mov %fs:0x0,%rax 0x48, 0x03, 0x05, 0, 0, 0, 0, // addq x@gottpoff(%rip),%rax }; - memcpy(loc - 4, inst, sizeof(inst)); + memcpy(Loc - 4, Inst, sizeof(Inst)); // Both code sequences are PC relatives, but since we are moving the // constant forward by 8 bytes we have to subtract the value by 8. - write32le(loc + 8, val - 8); + write32le(Loc + 8, Val - 8); } else { // Convert // lea x@tlsgd(%rip), %rax // call *(%rax) // to the following two instructions. - assert(type == R_X86_64_GOTPC32_TLSDESC); - if (memcmp(loc - 3, "\x48\x8d\x05", 3)) { - error(getErrorLocation(loc - 3) + "R_X86_64_GOTPC32_TLSDESC must be used " + assert(Type == R_X86_64_GOTPC32_TLSDESC); + if (memcmp(Loc - 3, "\x48\x8d\x05", 3)) { + error(getErrorLocation(Loc - 3) + "R_X86_64_GOTPC32_TLSDESC must be used " "in callq *x@tlsdesc(%rip), %rax"); return; } // movq x@gottpoff(%rip),%rax - loc[-2] = 0x8b; - write32le(loc, val); + Loc[-2] = 0x8b; + write32le(Loc, Val); // xchg ax,ax - loc[4] = 0x66; - loc[5] = 0x90; + Loc[4] = 0x66; + Loc[5] = 0x90; } } // In some conditions, R_X86_64_GOTTPOFF relocation can be optimized to // R_X86_64_TPOFF32 so that it does not use GOT. -void X86_64::relaxTlsIeToLe(uint8_t *loc, RelType type, uint64_t val) const { - uint8_t *inst = loc - 3; - uint8_t reg = loc[-1] >> 3; - uint8_t *regSlot = loc - 1; +void X86_64::relaxTlsIeToLe(uint8_t *Loc, RelType Type, uint64_t Val) const { + uint8_t *Inst = Loc - 3; + uint8_t Reg = Loc[-1] >> 3; + uint8_t *RegSlot = Loc - 1; // Note that ADD with RSP or R12 is converted to ADD instead of LEA // because LEA with these registers needs 4 bytes to encode and thus // wouldn't fit the space. - if (memcmp(inst, "\x48\x03\x25", 3) == 0) { + if (memcmp(Inst, "\x48\x03\x25", 3) == 0) { // "addq foo@gottpoff(%rip),%rsp" -> "addq $foo,%rsp" - memcpy(inst, "\x48\x81\xc4", 3); - } else if (memcmp(inst, "\x4c\x03\x25", 3) == 0) { + memcpy(Inst, "\x48\x81\xc4", 3); + } else if (memcmp(Inst, "\x4c\x03\x25", 3) == 0) { // "addq foo@gottpoff(%rip),%r12" -> "addq $foo,%r12" - memcpy(inst, "\x49\x81\xc4", 3); - } else if (memcmp(inst, "\x4c\x03", 2) == 0) { + memcpy(Inst, "\x49\x81\xc4", 3); + } else if (memcmp(Inst, "\x4c\x03", 2) == 0) { // "addq foo@gottpoff(%rip),%r[8-15]" -> "leaq foo(%r[8-15]),%r[8-15]" - memcpy(inst, "\x4d\x8d", 2); - *regSlot = 0x80 | (reg << 3) | reg; - } else if (memcmp(inst, "\x48\x03", 2) == 0) { + memcpy(Inst, "\x4d\x8d", 2); + *RegSlot = 0x80 | (Reg << 3) | Reg; + } else if (memcmp(Inst, "\x48\x03", 2) == 0) { // "addq foo@gottpoff(%rip),%reg -> "leaq foo(%reg),%reg" - memcpy(inst, "\x48\x8d", 2); - *regSlot = 0x80 | (reg << 3) | reg; - } else if (memcmp(inst, "\x4c\x8b", 2) == 0) { + memcpy(Inst, "\x48\x8d", 2); + *RegSlot = 0x80 | (Reg << 3) | Reg; + } else if (memcmp(Inst, "\x4c\x8b", 2) == 0) { // "movq foo@gottpoff(%rip),%r[8-15]" -> "movq $foo,%r[8-15]" - memcpy(inst, "\x49\xc7", 2); - *regSlot = 0xc0 | reg; - } else if (memcmp(inst, "\x48\x8b", 2) == 0) { + memcpy(Inst, "\x49\xc7", 2); + *RegSlot = 0xc0 | Reg; + } else if (memcmp(Inst, "\x48\x8b", 2) == 0) { // "movq foo@gottpoff(%rip),%reg" -> "movq $foo,%reg" - memcpy(inst, "\x48\xc7", 2); - *regSlot = 0xc0 | reg; + memcpy(Inst, "\x48\xc7", 2); + *RegSlot = 0xc0 | Reg; } else { - error(getErrorLocation(loc - 3) + + error(getErrorLocation(Loc - 3) + "R_X86_64_GOTTPOFF must be used in MOVQ or ADDQ instructions only"); } // The original code used a PC relative relocation. // Need to compensate for the -4 it had in the addend. - write32le(loc, val + 4); + write32le(Loc, Val + 4); } -void X86_64::relaxTlsLdToLe(uint8_t *loc, RelType type, uint64_t val) const { - if (type == R_X86_64_DTPOFF64) { - write64le(loc, val); +void X86_64::relaxTlsLdToLe(uint8_t *Loc, RelType Type, uint64_t Val) const { + if (Type == R_X86_64_DTPOFF64) { + write64le(Loc, Val); return; } - if (type == R_X86_64_DTPOFF32) { - write32le(loc, val); + if (Type == R_X86_64_DTPOFF32) { + write32le(Loc, Val); return; } - const uint8_t inst[] = { + const uint8_t Inst[] = { 0x66, 0x66, // .word 0x6666 0x66, // .byte 0x66 0x64, 0x48, 0x8b, 0x04, 0x25, 0x00, 0x00, 0x00, 0x00, // mov %fs:0,%rax }; - if (loc[4] == 0xe8) { + if (Loc[4] == 0xe8) { // Convert // leaq bar@tlsld(%rip), %rdi # 48 8d 3d // callq __tls_get_addr@PLT # e8 @@ -324,11 +324,11 @@ void X86_64::relaxTlsLdToLe(uint8_t *loc, RelType type, uint64_t val) const { // .byte 0x66 // mov %fs:0,%rax // leaq bar@tpoff(%rax), %rcx - memcpy(loc - 3, inst, sizeof(inst)); + memcpy(Loc - 3, Inst, sizeof(Inst)); return; } - if (loc[4] == 0xff && loc[5] == 0x15) { + if (Loc[4] == 0xff && Loc[5] == 0x15) { // Convert // leaq x@tlsld(%rip),%rdi # 48 8d 3d // call *__tls_get_addr@GOTPCREL(%rip) # ff 15 @@ -337,36 +337,36 @@ void X86_64::relaxTlsLdToLe(uint8_t *loc, RelType type, uint64_t val) const { // movq %fs:0,%rax // See "Table 11.9: LD -> LE Code Transition (LP64)" in // https://raw.githubusercontent.com/wiki/hjl-tools/x86-psABI/x86-64-psABI-1.0.pdf - loc[-3] = 0x66; - memcpy(loc - 2, inst, sizeof(inst)); + Loc[-3] = 0x66; + memcpy(Loc - 2, Inst, sizeof(Inst)); return; } - error(getErrorLocation(loc - 3) + + error(getErrorLocation(Loc - 3) + "expected R_X86_64_PLT32 or R_X86_64_GOTPCRELX after R_X86_64_TLSLD"); } -void X86_64::relocateOne(uint8_t *loc, RelType type, uint64_t val) const { - switch (type) { +void X86_64::relocateOne(uint8_t *Loc, RelType Type, uint64_t Val) const { + switch (Type) { case R_X86_64_8: - checkIntUInt(loc, val, 8, type); - *loc = val; + checkIntUInt(Loc, Val, 8, Type); + *Loc = Val; break; case R_X86_64_PC8: - checkInt(loc, val, 8, type); - *loc = val; + checkInt(Loc, Val, 8, Type); + *Loc = Val; break; case R_X86_64_16: - checkIntUInt(loc, val, 16, type); - write16le(loc, val); + checkIntUInt(Loc, Val, 16, Type); + write16le(Loc, Val); break; case R_X86_64_PC16: - checkInt(loc, val, 16, type); - write16le(loc, val); + checkInt(Loc, Val, 16, Type); + write16le(Loc, Val); break; case R_X86_64_32: - checkUInt(loc, val, 32, type); - write32le(loc, val); + checkUInt(Loc, Val, 32, Type); + write32le(Loc, Val); break; case R_X86_64_32S: case R_X86_64_TPOFF32: @@ -383,8 +383,8 @@ void X86_64::relocateOne(uint8_t *loc, RelType type, uint64_t val) const { case R_X86_64_TLSLD: case R_X86_64_DTPOFF32: case R_X86_64_SIZE32: - checkInt(loc, val, 32, type); - write32le(loc, val); + checkInt(Loc, Val, 32, Type); + write32le(Loc, Val); break; case R_X86_64_64: case R_X86_64_DTPOFF64: @@ -393,37 +393,37 @@ void X86_64::relocateOne(uint8_t *loc, RelType type, uint64_t val) const { case R_X86_64_GOT64: case R_X86_64_GOTOFF64: case R_X86_64_GOTPC64: - write64le(loc, val); + write64le(Loc, Val); break; default: llvm_unreachable("unknown relocation"); } } -RelExpr X86_64::adjustRelaxExpr(RelType type, const uint8_t *data, - RelExpr relExpr) const { - if (type != R_X86_64_GOTPCRELX && type != R_X86_64_REX_GOTPCRELX) - return relExpr; - const uint8_t op = data[-2]; - const uint8_t modRm = data[-1]; +RelExpr X86_64::adjustRelaxExpr(RelType Type, const uint8_t *Data, + RelExpr RelExpr) const { + if (Type != R_X86_64_GOTPCRELX && Type != R_X86_64_REX_GOTPCRELX) + return RelExpr; + const uint8_t Op = Data[-2]; + const uint8_t ModRm = Data[-1]; // FIXME: When PIC is disabled and foo is defined locally in the // lower 32 bit address space, memory operand in mov can be converted into // immediate operand. Otherwise, mov must be changed to lea. We support only // latter relaxation at this moment. - if (op == 0x8b) + if (Op == 0x8b) return R_RELAX_GOT_PC; // Relax call and jmp. - if (op == 0xff && (modRm == 0x15 || modRm == 0x25)) + if (Op == 0xff && (ModRm == 0x15 || ModRm == 0x25)) return R_RELAX_GOT_PC; // Relaxation of test, adc, add, and, cmp, or, sbb, sub, xor. // If PIC then no relaxation is available. // We also don't relax test/binop instructions without REX byte, // they are 32bit operations and not common to have. - assert(type == R_X86_64_REX_GOTPCRELX); - return config->isPic ? relExpr : R_RELAX_GOT_PC_NOPIC; + assert(Type == R_X86_64_REX_GOTPCRELX); + return Config->Pic ? RelExpr : R_RELAX_GOT_PC_NOPIC; } // A subset of relaxations can only be applied for no-PIC. This method @@ -431,11 +431,11 @@ RelExpr X86_64::adjustRelaxExpr(RelType type, const uint8_t *data, // "Intel 64 and IA-32 Architectures Software Developer's Manual V2" // (http://www.intel.com/content/dam/www/public/us/en/documents/manuals/ // 64-ia-32-architectures-software-developer-instruction-set-reference-manual-325383.pdf) -static void relaxGotNoPic(uint8_t *loc, uint64_t val, uint8_t op, - uint8_t modRm) { - const uint8_t rex = loc[-3]; +static void relaxGotNoPic(uint8_t *Loc, uint64_t Val, uint8_t Op, + uint8_t ModRm) { + const uint8_t Rex = Loc[-3]; // Convert "test %reg, foo@GOTPCREL(%rip)" to "test $foo, %reg". - if (op == 0x85) { + if (Op == 0x85) { // See "TEST-Logical Compare" (4-428 Vol. 2B), // TEST r/m64, r64 uses "full" ModR / M byte (no opcode extension). @@ -452,11 +452,11 @@ static void relaxGotNoPic(uint8_t *loc, uint64_t val, uint8_t op, // 0x38 == 00 111 000 binary. // We transfer reg2 to reg1 here as operand. // See "2.1.3 ModR/M and SIB Bytes" (Vol. 2A 2-3). - loc[-1] = 0xc0 | (modRm & 0x38) >> 3; // ModR/M byte. + Loc[-1] = 0xc0 | (ModRm & 0x38) >> 3; // ModR/M byte. // Change opcode from TEST r/m64, r64 to TEST r/m64, imm32 // See "TEST-Logical Compare" (4-428 Vol. 2B). - loc[-2] = 0xf7; + Loc[-2] = 0xf7; // Move R bit to the B bit in REX byte. // REX byte is encoded as 0100WRXB, where @@ -469,8 +469,8 @@ static void relaxGotNoPic(uint8_t *loc, uint64_t val, uint8_t op, // REX.B This 1-bit value is an extension to the MODRM.rm field or the // SIB.base field. // See "2.2.1.2 More on REX Prefix Fields " (2-8 Vol. 2A). - loc[-3] = (rex & ~0x4) | (rex & 0x4) >> 2; - write32le(loc, val); + Loc[-3] = (Rex & ~0x4) | (Rex & 0x4) >> 2; + write32le(Loc, Val); return; } @@ -480,7 +480,7 @@ static void relaxGotNoPic(uint8_t *loc, uint64_t val, uint8_t op, // Convert "binop foo@GOTPCREL(%rip), %reg" to "binop $foo, %reg". // Logic is close to one for test instruction above, but we also // write opcode extension here, see below for details. - loc[-1] = 0xc0 | (modRm & 0x38) >> 3 | (op & 0x3c); // ModR/M byte. + Loc[-1] = 0xc0 | (ModRm & 0x38) >> 3 | (Op & 0x3c); // ModR/M byte. // Primary opcode is 0x81, opcode extension is one of: // 000b = ADD, 001b is OR, 010b is ADC, 011b is SBB, @@ -489,67 +489,67 @@ static void relaxGotNoPic(uint8_t *loc, uint64_t val, uint8_t op, // See "3.2 INSTRUCTIONS (A-M)" (Vol. 2A 3-15), // "INSTRUCTION SET REFERENCE, N-Z" (Vol. 2B 4-1) for // descriptions about each operation. - loc[-2] = 0x81; - loc[-3] = (rex & ~0x4) | (rex & 0x4) >> 2; - write32le(loc, val); + Loc[-2] = 0x81; + Loc[-3] = (Rex & ~0x4) | (Rex & 0x4) >> 2; + write32le(Loc, Val); } -void X86_64::relaxGot(uint8_t *loc, RelType type, uint64_t val) const { - const uint8_t op = loc[-2]; - const uint8_t modRm = loc[-1]; +void X86_64::relaxGot(uint8_t *Loc, RelType Type, uint64_t Val) const { + const uint8_t Op = Loc[-2]; + const uint8_t ModRm = Loc[-1]; // Convert "mov foo@GOTPCREL(%rip),%reg" to "lea foo(%rip),%reg". - if (op == 0x8b) { - loc[-2] = 0x8d; - write32le(loc, val); + if (Op == 0x8b) { + Loc[-2] = 0x8d; + write32le(Loc, Val); return; } - if (op != 0xff) { + if (Op != 0xff) { // We are relaxing a rip relative to an absolute, so compensate // for the old -4 addend. - assert(!config->isPic); - relaxGotNoPic(loc, val + 4, op, modRm); + assert(!Config->Pic); + relaxGotNoPic(Loc, Val + 4, Op, ModRm); return; } // Convert call/jmp instructions. - if (modRm == 0x15) { + if (ModRm == 0x15) { // ABI says we can convert "call *foo@GOTPCREL(%rip)" to "nop; call foo". // Instead we convert to "addr32 call foo" where addr32 is an instruction // prefix. That makes result expression to be a single instruction. - loc[-2] = 0x67; // addr32 prefix - loc[-1] = 0xe8; // call - write32le(loc, val); + Loc[-2] = 0x67; // addr32 prefix + Loc[-1] = 0xe8; // call + write32le(Loc, Val); return; } // Convert "jmp *foo@GOTPCREL(%rip)" to "jmp foo; nop". // jmp doesn't return, so it is fine to use nop here, it is just a stub. - assert(modRm == 0x25); - loc[-2] = 0xe9; // jmp - loc[3] = 0x90; // nop - write32le(loc - 1, val + 1); + assert(ModRm == 0x25); + Loc[-2] = 0xe9; // jmp + Loc[3] = 0x90; // nop + write32le(Loc - 1, Val + 1); } // A split-stack prologue starts by checking the amount of stack remaining // in one of two ways: // A) Comparing of the stack pointer to a field in the tcb. // B) Or a load of a stack pointer offset with an lea to r10 or r11. -bool X86_64::adjustPrologueForCrossSplitStack(uint8_t *loc, uint8_t *end, - uint8_t stOther) const { - if (!config->is64) { +bool X86_64::adjustPrologueForCrossSplitStack(uint8_t *Loc, uint8_t *End, + uint8_t StOther) const { + if (!Config->Is64) { error("Target doesn't support split stacks."); return false; } - if (loc + 8 >= end) + if (Loc + 8 >= End) return false; // Replace "cmp %fs:0x70,%rsp" and subsequent branch // with "stc, nopl 0x0(%rax,%rax,1)" - if (memcmp(loc, "\x64\x48\x3b\x24\x25", 5) == 0) { - memcpy(loc, "\xf9\x0f\x1f\x84\x00\x00\x00\x00", 8); + if (memcmp(Loc, "\x64\x48\x3b\x24\x25", 5) == 0) { + memcpy(Loc, "\xf9\x0f\x1f\x84\x00\x00\x00\x00", 8); return true; } @@ -557,11 +557,11 @@ bool X86_64::adjustPrologueForCrossSplitStack(uint8_t *loc, uint8_t *end, // be r10 or r11. The lea instruction feeds a subsequent compare which checks // if there is X available stack space. Making X larger effectively reserves // that much additional space. The stack grows downward so subtract the value. - if (memcmp(loc, "\x4c\x8d\x94\x24", 4) == 0 || - memcmp(loc, "\x4c\x8d\x9c\x24", 4) == 0) { + if (memcmp(Loc, "\x4c\x8d\x94\x24", 4) == 0 || + memcmp(Loc, "\x4c\x8d\x9c\x24", 4) == 0) { // The offset bytes are encoded four bytes after the start of the // instruction. - write32le(loc + 4, read32le(loc + 4) - 0x4000); + write32le(Loc + 4, read32le(Loc + 4) - 0x4000); return true; } return false; @@ -580,33 +580,33 @@ namespace { class Retpoline : public X86_64 { public: Retpoline(); - void writeGotPlt(uint8_t *buf, const Symbol &s) const override; - void writePltHeader(uint8_t *buf) const override; - void writePlt(uint8_t *buf, uint64_t gotPltEntryAddr, uint64_t pltEntryAddr, - int32_t index, unsigned relOff) const override; + void writeGotPlt(uint8_t *Buf, const Symbol &S) const override; + void writePltHeader(uint8_t *Buf) const override; + void writePlt(uint8_t *Buf, uint64_t GotPltEntryAddr, uint64_t PltEntryAddr, + int32_t Index, unsigned RelOff) const override; }; class RetpolineZNow : public X86_64 { public: RetpolineZNow(); - void writeGotPlt(uint8_t *buf, const Symbol &s) const override {} - void writePltHeader(uint8_t *buf) const override; - void writePlt(uint8_t *buf, uint64_t gotPltEntryAddr, uint64_t pltEntryAddr, - int32_t index, unsigned relOff) const override; + void writeGotPlt(uint8_t *Buf, const Symbol &S) const override {} + void writePltHeader(uint8_t *Buf) const override; + void writePlt(uint8_t *Buf, uint64_t GotPltEntryAddr, uint64_t PltEntryAddr, + int32_t Index, unsigned RelOff) const override; }; } // namespace Retpoline::Retpoline() { - pltHeaderSize = 48; - pltEntrySize = 32; + PltHeaderSize = 48; + PltEntrySize = 32; } -void Retpoline::writeGotPlt(uint8_t *buf, const Symbol &s) const { - write64le(buf, s.getPltVA() + 17); +void Retpoline::writeGotPlt(uint8_t *Buf, const Symbol &S) const { + write64le(Buf, S.getPltVA() + 17); } -void Retpoline::writePltHeader(uint8_t *buf) const { - const uint8_t insn[] = { +void Retpoline::writePltHeader(uint8_t *Buf) const { + const uint8_t Insn[] = { 0xff, 0x35, 0, 0, 0, 0, // 0: pushq GOTPLT+8(%rip) 0x4c, 0x8b, 0x1d, 0, 0, 0, 0, // 6: mov GOTPLT+16(%rip), %r11 0xe8, 0x0e, 0x00, 0x00, 0x00, // d: callq next @@ -619,18 +619,18 @@ void Retpoline::writePltHeader(uint8_t *buf) const { 0xcc, 0xcc, 0xcc, 0xcc, 0xcc, 0xcc, 0xcc, // 25: int3; padding 0xcc, 0xcc, 0xcc, 0xcc, // 2c: int3; padding }; - memcpy(buf, insn, sizeof(insn)); + memcpy(Buf, Insn, sizeof(Insn)); - uint64_t gotPlt = in.gotPlt->getVA(); - uint64_t plt = in.plt->getVA(); - write32le(buf + 2, gotPlt - plt - 6 + 8); - write32le(buf + 9, gotPlt - plt - 13 + 16); + uint64_t GotPlt = In.GotPlt->getVA(); + uint64_t Plt = In.Plt->getVA(); + write32le(Buf + 2, GotPlt - Plt - 6 + 8); + write32le(Buf + 9, GotPlt - Plt - 13 + 16); } -void Retpoline::writePlt(uint8_t *buf, uint64_t gotPltEntryAddr, - uint64_t pltEntryAddr, int32_t index, - unsigned relOff) const { - const uint8_t insn[] = { +void Retpoline::writePlt(uint8_t *Buf, uint64_t GotPltEntryAddr, + uint64_t PltEntryAddr, int32_t Index, + unsigned RelOff) const { + const uint8_t Insn[] = { 0x4c, 0x8b, 0x1d, 0, 0, 0, 0, // 0: mov foo@GOTPLT(%rip), %r11 0xe8, 0, 0, 0, 0, // 7: callq plt+0x20 0xe9, 0, 0, 0, 0, // c: jmp plt+0x12 @@ -638,24 +638,24 @@ void Retpoline::writePlt(uint8_t *buf, uint64_t gotPltEntryAddr, 0xe9, 0, 0, 0, 0, // 16: jmp plt+0 0xcc, 0xcc, 0xcc, 0xcc, 0xcc, // 1b: int3; padding }; - memcpy(buf, insn, sizeof(insn)); + memcpy(Buf, Insn, sizeof(Insn)); - uint64_t off = pltHeaderSize + pltEntrySize * index; + uint64_t Off = PltHeaderSize + PltEntrySize * Index; - write32le(buf + 3, gotPltEntryAddr - pltEntryAddr - 7); - write32le(buf + 8, -off - 12 + 32); - write32le(buf + 13, -off - 17 + 18); - write32le(buf + 18, index); - write32le(buf + 23, -off - 27); + write32le(Buf + 3, GotPltEntryAddr - PltEntryAddr - 7); + write32le(Buf + 8, -Off - 12 + 32); + write32le(Buf + 13, -Off - 17 + 18); + write32le(Buf + 18, Index); + write32le(Buf + 23, -Off - 27); } RetpolineZNow::RetpolineZNow() { - pltHeaderSize = 32; - pltEntrySize = 16; + PltHeaderSize = 32; + PltEntrySize = 16; } -void RetpolineZNow::writePltHeader(uint8_t *buf) const { - const uint8_t insn[] = { +void RetpolineZNow::writePltHeader(uint8_t *Buf) const { + const uint8_t Insn[] = { 0xe8, 0x0b, 0x00, 0x00, 0x00, // 0: call next 0xf3, 0x90, // 5: loop: pause 0x0f, 0xae, 0xe8, // 7: lfence @@ -667,35 +667,35 @@ void RetpolineZNow::writePltHeader(uint8_t *buf) const { 0xcc, 0xcc, 0xcc, 0xcc, 0xcc, // 1a: int3; padding 0xcc, // 1f: int3; padding }; - memcpy(buf, insn, sizeof(insn)); + memcpy(Buf, Insn, sizeof(Insn)); } -void RetpolineZNow::writePlt(uint8_t *buf, uint64_t gotPltEntryAddr, - uint64_t pltEntryAddr, int32_t index, - unsigned relOff) const { - const uint8_t insn[] = { +void RetpolineZNow::writePlt(uint8_t *Buf, uint64_t GotPltEntryAddr, + uint64_t PltEntryAddr, int32_t Index, + unsigned RelOff) const { + const uint8_t Insn[] = { 0x4c, 0x8b, 0x1d, 0, 0, 0, 0, // mov foo@GOTPLT(%rip), %r11 0xe9, 0, 0, 0, 0, // jmp plt+0 0xcc, 0xcc, 0xcc, 0xcc, // int3; padding }; - memcpy(buf, insn, sizeof(insn)); + memcpy(Buf, Insn, sizeof(Insn)); - write32le(buf + 3, gotPltEntryAddr - pltEntryAddr - 7); - write32le(buf + 8, -pltHeaderSize - pltEntrySize * index - 12); + write32le(Buf + 3, GotPltEntryAddr - PltEntryAddr - 7); + write32le(Buf + 8, -PltHeaderSize - PltEntrySize * Index - 12); } static TargetInfo *getTargetInfo() { - if (config->zRetpolineplt) { - if (config->zNow) { - static RetpolineZNow t; - return &t; + if (Config->ZRetpolineplt) { + if (Config->ZNow) { + static RetpolineZNow T; + return &T; } - static Retpoline t; - return &t; + static Retpoline T; + return &T; } - static X86_64 t; - return &t; + static X86_64 T; + return &T; } TargetInfo *elf::getX86_64TargetInfo() { return getTargetInfo(); } diff --git a/lld/ELF/CallGraphSort.cpp b/lld/ELF/CallGraphSort.cpp index 12f89e4f5d3477..eacaca72d8d6cf 100644 --- a/lld/ELF/CallGraphSort.cpp +++ b/lld/ELF/CallGraphSort.cpp @@ -51,24 +51,24 @@ using namespace lld::elf; namespace { struct Edge { - int from; - uint64_t weight; + int From; + uint64_t Weight; }; struct Cluster { - Cluster(int sec, size_t s) : sections{sec}, size(s) {} + Cluster(int Sec, size_t S) : Sections{Sec}, Size(S) {} double getDensity() const { - if (size == 0) + if (Size == 0) return 0; - return double(weight) / double(size); + return double(Weight) / double(Size); } - std::vector sections; - size_t size = 0; - uint64_t weight = 0; - uint64_t initialWeight = 0; - Edge bestPred = {-1, 0}; + std::vector Sections; + size_t Size = 0; + uint64_t Weight = 0; + uint64_t InitialWeight = 0; + Edge BestPred = {-1, 0}; }; class CallGraphSort { @@ -78,8 +78,8 @@ class CallGraphSort { DenseMap run(); private: - std::vector clusters; - std::vector sections; + std::vector Clusters; + std::vector Sections; void groupClusters(); }; @@ -99,23 +99,23 @@ using SectionPair = // Symbols, and generate a graph between InputSections with the provided // weights. CallGraphSort::CallGraphSort() { - MapVector &profile = config->callGraphProfile; - DenseMap secToCluster; - - auto getOrCreateNode = [&](const InputSectionBase *isec) -> int { - auto res = secToCluster.insert(std::make_pair(isec, clusters.size())); - if (res.second) { - sections.push_back(isec); - clusters.emplace_back(clusters.size(), isec->getSize()); + MapVector &Profile = Config->CallGraphProfile; + DenseMap SecToCluster; + + auto GetOrCreateNode = [&](const InputSectionBase *IS) -> int { + auto Res = SecToCluster.insert(std::make_pair(IS, Clusters.size())); + if (Res.second) { + Sections.push_back(IS); + Clusters.emplace_back(Clusters.size(), IS->getSize()); } - return res.first->second; + return Res.first->second; }; // Create the graph. - for (std::pair &c : profile) { - const auto *fromSB = cast(c.first.first->repl); - const auto *toSB = cast(c.first.second->repl); - uint64_t weight = c.second; + for (std::pair &C : Profile) { + const auto *FromSB = cast(C.first.first->Repl); + const auto *ToSB = cast(C.first.second->Repl); + uint64_t Weight = C.second; // Ignore edges between input sections belonging to different output // sections. This is done because otherwise we would end up with clusters @@ -123,94 +123,94 @@ CallGraphSort::CallGraphSort() { // output. This messes with the cluster size and density calculations. We // would also end up moving input sections in other output sections without // moving them closer to what calls them. - if (fromSB->getOutputSection() != toSB->getOutputSection()) + if (FromSB->getOutputSection() != ToSB->getOutputSection()) continue; - int from = getOrCreateNode(fromSB); - int to = getOrCreateNode(toSB); + int From = GetOrCreateNode(FromSB); + int To = GetOrCreateNode(ToSB); - clusters[to].weight += weight; + Clusters[To].Weight += Weight; - if (from == to) + if (From == To) continue; // Remember the best edge. - Cluster &toC = clusters[to]; - if (toC.bestPred.from == -1 || toC.bestPred.weight < weight) { - toC.bestPred.from = from; - toC.bestPred.weight = weight; + Cluster &ToC = Clusters[To]; + if (ToC.BestPred.From == -1 || ToC.BestPred.Weight < Weight) { + ToC.BestPred.From = From; + ToC.BestPred.Weight = Weight; } } - for (Cluster &c : clusters) - c.initialWeight = c.weight; + for (Cluster &C : Clusters) + C.InitialWeight = C.Weight; } // It's bad to merge clusters which would degrade the density too much. -static bool isNewDensityBad(Cluster &a, Cluster &b) { - double newDensity = double(a.weight + b.weight) / double(a.size + b.size); - return newDensity < a.getDensity() / MAX_DENSITY_DEGRADATION; +static bool isNewDensityBad(Cluster &A, Cluster &B) { + double NewDensity = double(A.Weight + B.Weight) / double(A.Size + B.Size); + return NewDensity < A.getDensity() / MAX_DENSITY_DEGRADATION; } -static void mergeClusters(Cluster &into, Cluster &from) { - into.sections.insert(into.sections.end(), from.sections.begin(), - from.sections.end()); - into.size += from.size; - into.weight += from.weight; - from.sections.clear(); - from.size = 0; - from.weight = 0; +static void mergeClusters(Cluster &Into, Cluster &From) { + Into.Sections.insert(Into.Sections.end(), From.Sections.begin(), + From.Sections.end()); + Into.Size += From.Size; + Into.Weight += From.Weight; + From.Sections.clear(); + From.Size = 0; + From.Weight = 0; } // Group InputSections into clusters using the Call-Chain Clustering heuristic // then sort the clusters by density. void CallGraphSort::groupClusters() { - std::vector sortedSecs(clusters.size()); - std::vector secToCluster(clusters.size()); + std::vector SortedSecs(Clusters.size()); + std::vector SecToCluster(Clusters.size()); - for (size_t i = 0; i < clusters.size(); ++i) { - sortedSecs[i] = i; - secToCluster[i] = &clusters[i]; + for (size_t I = 0; I < Clusters.size(); ++I) { + SortedSecs[I] = I; + SecToCluster[I] = &Clusters[I]; } - llvm::stable_sort(sortedSecs, [&](int a, int b) { - return clusters[a].getDensity() > clusters[b].getDensity(); + llvm::stable_sort(SortedSecs, [&](int A, int B) { + return Clusters[A].getDensity() > Clusters[B].getDensity(); }); - for (int si : sortedSecs) { - // clusters[si] is the same as secToClusters[si] here because it has not + for (int SI : SortedSecs) { + // Clusters[SI] is the same as SecToClusters[SI] here because it has not // been merged into another cluster yet. - Cluster &c = clusters[si]; + Cluster &C = Clusters[SI]; // Don't consider merging if the edge is unlikely. - if (c.bestPred.from == -1 || c.bestPred.weight * 10 <= c.initialWeight) + if (C.BestPred.From == -1 || C.BestPred.Weight * 10 <= C.InitialWeight) continue; - Cluster *predC = secToCluster[c.bestPred.from]; - if (predC == &c) + Cluster *PredC = SecToCluster[C.BestPred.From]; + if (PredC == &C) continue; - if (c.size + predC->size > MAX_CLUSTER_SIZE) + if (C.Size + PredC->Size > MAX_CLUSTER_SIZE) continue; - if (isNewDensityBad(*predC, c)) + if (isNewDensityBad(*PredC, C)) continue; // NOTE: Consider using a disjoint-set to track section -> cluster mapping // if this is ever slow. - for (int si : c.sections) - secToCluster[si] = predC; + for (int SI : C.Sections) + SecToCluster[SI] = PredC; - mergeClusters(*predC, c); + mergeClusters(*PredC, C); } // Remove empty or dead nodes. Invalidates all cluster indices. - llvm::erase_if(clusters, [](const Cluster &c) { - return c.size == 0 || c.sections.empty(); + llvm::erase_if(Clusters, [](const Cluster &C) { + return C.Size == 0 || C.Sections.empty(); }); // Sort by density. - llvm::stable_sort(clusters, [](const Cluster &a, const Cluster &b) { - return a.getDensity() > b.getDensity(); + llvm::stable_sort(Clusters, [](const Cluster &A, const Cluster &B) { + return A.getDensity() > B.getDensity(); }); } @@ -218,35 +218,35 @@ DenseMap CallGraphSort::run() { groupClusters(); // Generate order. - DenseMap orderMap; - ssize_t curOrder = 1; - - for (const Cluster &c : clusters) - for (int secIndex : c.sections) - orderMap[sections[secIndex]] = curOrder++; - - if (!config->printSymbolOrder.empty()) { - std::error_code ec; - raw_fd_ostream os(config->printSymbolOrder, ec, sys::fs::OF_None); - if (ec) { - error("cannot open " + config->printSymbolOrder + ": " + ec.message()); - return orderMap; + DenseMap OrderMap; + ssize_t CurOrder = 1; + + for (const Cluster &C : Clusters) + for (int SecIndex : C.Sections) + OrderMap[Sections[SecIndex]] = CurOrder++; + + if (!Config->PrintSymbolOrder.empty()) { + std::error_code EC; + raw_fd_ostream OS(Config->PrintSymbolOrder, EC, sys::fs::F_None); + if (EC) { + error("cannot open " + Config->PrintSymbolOrder + ": " + EC.message()); + return OrderMap; } - // Print the symbols ordered by C3, in the order of increasing curOrder - // Instead of sorting all the orderMap, just repeat the loops above. - for (const Cluster &c : clusters) - for (int secIndex : c.sections) + // Print the symbols ordered by C3, in the order of increasing CurOrder + // Instead of sorting all the OrderMap, just repeat the loops above. + for (const Cluster &C : Clusters) + for (int SecIndex : C.Sections) // Search all the symbols in the file of the section // and find out a Defined symbol with name that is within the section. - for (Symbol *sym: sections[secIndex]->file->getSymbols()) - if (!sym->isSection()) // Filter out section-type symbols here. - if (auto *d = dyn_cast(sym)) - if (sections[secIndex] == d->section) - os << sym->getName() << "\n"; + for (Symbol *Sym: Sections[SecIndex]->File->getSymbols()) + if (!Sym->isSection()) // Filter out section-type symbols here. + if (auto *D = dyn_cast(Sym)) + if (Sections[SecIndex] == D->Section) + OS << Sym->getName() << "\n"; } - return orderMap; + return OrderMap; } // Sort sections by the profile data provided by -callgraph-profile-file diff --git a/lld/ELF/Config.h b/lld/ELF/Config.h index c038b50da81d4d..3b3087987e6f69 100644 --- a/lld/ELF/Config.h +++ b/lld/ELF/Config.h @@ -62,17 +62,17 @@ enum class Target2Policy { Abs, Rel, GotRel }; enum class ARMVFPArgKind { Default, Base, VFP, ToolChain }; struct SymbolVersion { - llvm::StringRef name; - bool isExternCpp; - bool hasWildcard; + llvm::StringRef Name; + bool IsExternCpp; + bool HasWildcard; }; // This struct contains symbols version definition that // can be found in version script if it is used for link. struct VersionDefinition { - llvm::StringRef name; - uint16_t id; - std::vector patterns; + llvm::StringRef Name; + uint16_t Id = 0; + std::vector Globals; }; // This struct contains the global configuration for the linker. @@ -80,175 +80,177 @@ struct VersionDefinition { // and such fields have the same name as the corresponding options. // Most fields are initialized by the driver. struct Configuration { - uint8_t osabi = 0; - uint32_t andFeatures = 0; - llvm::CachePruningPolicy thinLTOCachePolicy; - llvm::StringMap sectionStartMap; - llvm::StringRef chroot; - llvm::StringRef dynamicLinker; - llvm::StringRef dwoDir; - llvm::StringRef entry; - llvm::StringRef emulation; - llvm::StringRef fini; - llvm::StringRef init; - llvm::StringRef ltoAAPipeline; - llvm::StringRef ltoCSProfileFile; - llvm::StringRef ltoNewPmPasses; - llvm::StringRef ltoObjPath; - llvm::StringRef ltoSampleProfile; - llvm::StringRef mapFile; - llvm::StringRef outputFile; - llvm::StringRef optRemarksFilename; - llvm::StringRef optRemarksPasses; - llvm::StringRef optRemarksFormat; - llvm::StringRef progName; - llvm::StringRef printSymbolOrder; - llvm::StringRef soName; - llvm::StringRef sysroot; - llvm::StringRef thinLTOCacheDir; - llvm::StringRef thinLTOIndexOnlyArg; - std::pair thinLTOObjectSuffixReplace; - std::pair thinLTOPrefixReplace; - std::string rpath; - std::vector versionDefinitions; - std::vector auxiliaryList; - std::vector filterList; - std::vector searchPaths; - std::vector symbolOrderingFile; - std::vector undefined; - std::vector dynamicList; - std::vector buildIdVector; + uint8_t OSABI = 0; + uint32_t AndFeatures = 0; + llvm::CachePruningPolicy ThinLTOCachePolicy; + llvm::StringMap SectionStartMap; + llvm::StringRef Chroot; + llvm::StringRef DynamicLinker; + llvm::StringRef DwoDir; + llvm::StringRef Entry; + llvm::StringRef Emulation; + llvm::StringRef Fini; + llvm::StringRef Init; + llvm::StringRef LTOAAPipeline; + llvm::StringRef LTOCSProfileFile; + llvm::StringRef LTONewPmPasses; + llvm::StringRef LTOObjPath; + llvm::StringRef LTOSampleProfile; + llvm::StringRef MapFile; + llvm::StringRef OutputFile; + llvm::StringRef OptRemarksFilename; + llvm::StringRef OptRemarksPasses; + llvm::StringRef OptRemarksFormat; + llvm::StringRef ProgName; + llvm::StringRef PrintSymbolOrder; + llvm::StringRef SoName; + llvm::StringRef Sysroot; + llvm::StringRef ThinLTOCacheDir; + llvm::StringRef ThinLTOIndexOnlyArg; + std::pair ThinLTOObjectSuffixReplace; + std::pair ThinLTOPrefixReplace; + std::string Rpath; + std::vector VersionDefinitions; + std::vector AuxiliaryList; + std::vector FilterList; + std::vector SearchPaths; + std::vector SymbolOrderingFile; + std::vector Undefined; + std::vector DynamicList; + std::vector VersionScriptGlobals; + std::vector VersionScriptLocals; + std::vector BuildIdVector; llvm::MapVector, uint64_t> - callGraphProfile; - bool allowMultipleDefinition; - bool allowShlibUndefined; - bool androidPackDynRelocs; - bool armHasBlx = false; - bool armHasMovtMovw = false; - bool armJ1J2BranchEncoding = false; - bool asNeeded = false; - bool bsymbolic; - bool bsymbolicFunctions; - bool callGraphProfileSort; - bool checkSections; - bool compressDebugSections; - bool cref; - bool defineCommon; - bool demangle = true; - bool dependentLibraries; - bool disableVerify; - bool ehFrameHdr; - bool emitLLVM; - bool emitRelocs; - bool enableNewDtags; - bool executeOnly; - bool exportDynamic; - bool fixCortexA53Errata843419; - bool forceBTI; - bool formatBinary = false; - bool requireCET; - bool gcSections; - bool gdbIndex; - bool gnuHash = false; - bool gnuUnique; - bool hasDynamicList = false; - bool hasDynSymTab; - bool ignoreDataAddressEquality; - bool ignoreFunctionAddressEquality; - bool ltoCSProfileGenerate; - bool ltoDebugPassManager; - bool ltoNewPassManager; - bool mergeArmExidx; - bool mipsN32Abi = false; - bool nmagic; - bool noinhibitExec; - bool nostdlib; - bool oFormatBinary; - bool omagic; - bool optRemarksWithHotness; - bool pacPlt; - bool picThunk; - bool pie; - bool printGcSections; - bool printIcfSections; - bool relocatable; - bool relrPackDynRelocs; - bool saveTemps; - bool singleRoRx; - bool shared; - bool isStatic = false; - bool sysvHash = false; - bool target1Rel; - bool trace; - bool thinLTOEmitImportsFiles; - bool thinLTOIndexOnly; - bool tocOptimize; - bool undefinedVersion; - bool useAndroidRelrTags = false; - bool warnBackrefs; - bool warnCommon; - bool warnIfuncTextrel; - bool warnMissingEntry; - bool warnSymbolOrdering; - bool writeAddends; - bool zCombreloc; - bool zCopyreloc; - bool zExecstack; - bool zGlobal; - bool zHazardplt; - bool zIfuncNoplt; - bool zInitfirst; - bool zInterpose; - bool zKeepTextSectionPrefix; - bool zNodefaultlib; - bool zNodelete; - bool zNodlopen; - bool zNow; - bool zOrigin; - bool zRelro; - bool zRodynamic; - bool zSeparateCode; - bool zText; - bool zRetpolineplt; - bool zWxneeded; - DiscardPolicy discard; - ICFLevel icf; - OrphanHandlingPolicy orphanHandling; - SortSectionPolicy sortSection; - StripPolicy strip; - UnresolvedPolicy unresolvedSymbols; - Target2Policy target2; - ARMVFPArgKind armVFPArgs = ARMVFPArgKind::Default; - BuildIdKind buildId = BuildIdKind::None; - ELFKind ekind = ELFNoneKind; - uint16_t emachine = llvm::ELF::EM_NONE; - llvm::Optional imageBase; - uint64_t commonPageSize; - uint64_t maxPageSize; - uint64_t mipsGotSize; - uint64_t zStackSize; - unsigned ltoPartitions; - unsigned ltoo; - unsigned optimize; - unsigned thinLTOJobs; - int32_t splitStackAdjustSize; + CallGraphProfile; + bool AllowMultipleDefinition; + bool AllowShlibUndefined; + bool AndroidPackDynRelocs; + bool ARMHasBlx = false; + bool ARMHasMovtMovw = false; + bool ARMJ1J2BranchEncoding = false; + bool AsNeeded = false; + bool Bsymbolic; + bool BsymbolicFunctions; + bool CallGraphProfileSort; + bool CheckSections; + bool CompressDebugSections; + bool Cref; + bool DefineCommon; + bool Demangle = true; + bool DependentLibraries; + bool DisableVerify; + bool EhFrameHdr; + bool EmitLLVM; + bool EmitRelocs; + bool EnableNewDtags; + bool ExecuteOnly; + bool ExportDynamic; + bool FixCortexA53Errata843419; + bool ForceBTI; + bool FormatBinary = false; + bool RequireCET; + bool GcSections; + bool GdbIndex; + bool GnuHash = false; + bool GnuUnique; + bool HasDynamicList = false; + bool HasDynSymTab; + bool IgnoreDataAddressEquality; + bool IgnoreFunctionAddressEquality; + bool LTOCSProfileGenerate; + bool LTODebugPassManager; + bool LTONewPassManager; + bool MergeArmExidx; + bool MipsN32Abi = false; + bool Nmagic; + bool NoinhibitExec; + bool Nostdlib; + bool OFormatBinary; + bool Omagic; + bool OptRemarksWithHotness; + bool PacPlt; + bool PicThunk; + bool Pie; + bool PrintGcSections; + bool PrintIcfSections; + bool Relocatable; + bool RelrPackDynRelocs; + bool SaveTemps; + bool SingleRoRx; + bool Shared; + bool Static = false; + bool SysvHash = false; + bool Target1Rel; + bool Trace; + bool ThinLTOEmitImportsFiles; + bool ThinLTOIndexOnly; + bool TocOptimize; + bool UndefinedVersion; + bool UseAndroidRelrTags = false; + bool WarnBackrefs; + bool WarnCommon; + bool WarnIfuncTextrel; + bool WarnMissingEntry; + bool WarnSymbolOrdering; + bool WriteAddends; + bool ZCombreloc; + bool ZCopyreloc; + bool ZExecstack; + bool ZGlobal; + bool ZHazardplt; + bool ZIfuncNoplt; + bool ZInitfirst; + bool ZInterpose; + bool ZKeepTextSectionPrefix; + bool ZNodefaultlib; + bool ZNodelete; + bool ZNodlopen; + bool ZNow; + bool ZOrigin; + bool ZRelro; + bool ZRodynamic; + bool ZText; + bool ZRetpolineplt; + bool ZWxneeded; + DiscardPolicy Discard; + ICFLevel ICF; + OrphanHandlingPolicy OrphanHandling; + SortSectionPolicy SortSection; + StripPolicy Strip; + UnresolvedPolicy UnresolvedSymbols; + Target2Policy Target2; + ARMVFPArgKind ARMVFPArgs = ARMVFPArgKind::Default; + BuildIdKind BuildId = BuildIdKind::None; + ELFKind EKind = ELFNoneKind; + uint16_t DefaultSymbolVersion = llvm::ELF::VER_NDX_GLOBAL; + uint16_t EMachine = llvm::ELF::EM_NONE; + llvm::Optional ImageBase; + uint64_t CommonPageSize; + uint64_t MaxPageSize; + uint64_t MipsGotSize; + uint64_t ZStackSize; + unsigned LTOPartitions; + unsigned LTOO; + unsigned Optimize; + unsigned ThinLTOJobs; + int32_t SplitStackAdjustSize; // The following config options do not directly correspond to any // particualr command line options. // True if we need to pass through relocations in input files to the // output file. Usually false because we consume relocations. - bool copyRelocs; + bool CopyRelocs; // True if the target is ELF64. False if ELF32. - bool is64; + bool Is64; // True if the target is little-endian. False if big-endian. - bool isLE; + bool IsLE; - // endianness::little if isLE is true. endianness::big otherwise. - llvm::support::endianness endianness; + // endianness::little if IsLE is true. endianness::big otherwise. + llvm::support::endianness Endianness; // True if the target is the little-endian MIPS64. // @@ -262,7 +264,7 @@ struct Configuration { // name whatever that means. A fun hypothesis is that "EL" is short for // little-endian written in the little-endian order, but I don't know // if that's true.) - bool isMips64EL; + bool IsMips64EL; // True if we need to set the DF_STATIC_TLS flag to an output file, // which works as a hint to the dynamic loader that the file contains @@ -276,10 +278,10 @@ struct Configuration { // Since the flag is updated by multi-threaded code, we use std::atomic. // (Writing to a variable is not considered thread-safe even if the // variable is boolean and we always set the same value from all threads.) - std::atomic hasStaticTlsModel{false}; + std::atomic HasStaticTlsModel{false}; // Holds set of ELF header flags for the target. - uint32_t eflags = 0; + uint32_t EFlags = 0; // The ELF spec defines two types of relocation table entries, RELA and // REL. RELA is a triplet of (offset, info, addend) while REL is a @@ -295,29 +297,23 @@ struct Configuration { // Each ABI defines its relocation type. IsRela is true if target // uses RELA. As far as we know, all 64-bit ABIs are using RELA. A // few 32-bit ABIs are using RELA too. - bool isRela; + bool IsRela; // True if we are creating position-independent code. - bool isPic; + bool Pic; // 4 for ELF32, 8 for ELF64. - int wordsize; + int Wordsize; }; // The only instance of Configuration struct. -extern Configuration *config; +extern Configuration *Config; -// The first two elements of versionDefinitions represent VER_NDX_LOCAL and -// VER_NDX_GLOBAL. This helper returns other elements. -static inline ArrayRef namedVersionDefs() { - return llvm::makeArrayRef(config->versionDefinitions).slice(2); -} - -static inline void errorOrWarn(const Twine &msg) { - if (!config->noinhibitExec) - error(msg); +static inline void errorOrWarn(const Twine &Msg) { + if (!Config->NoinhibitExec) + error(Msg); else - warn(msg); + warn(Msg); } } // namespace elf } // namespace lld diff --git a/lld/ELF/DWARF.cpp b/lld/ELF/DWARF.cpp index 9ef83caf4f70ca..9266320765aa65 100644 --- a/lld/ELF/DWARF.cpp +++ b/lld/ELF/DWARF.cpp @@ -25,33 +25,32 @@ using namespace llvm::object; using namespace lld; using namespace lld::elf; -template LLDDwarfObj::LLDDwarfObj(ObjFile *obj) { - for (InputSectionBase *sec : obj->getSections()) { - if (!sec) +template LLDDwarfObj::LLDDwarfObj(ObjFile *Obj) { + for (InputSectionBase *Sec : Obj->getSections()) { + if (!Sec) continue; - if (LLDDWARFSection *m = - StringSwitch(sec->name) - .Case(".debug_addr", &addrSection) - .Case(".debug_gnu_pubnames", &gnuPubnamesSection) - .Case(".debug_gnu_pubtypes", &gnuPubtypesSection) - .Case(".debug_info", &infoSection) - .Case(".debug_ranges", &rangesSection) - .Case(".debug_rnglists", &rnglistsSection) - .Case(".debug_str_offsets", &strOffsetsSection) - .Case(".debug_line", &lineSection) + if (LLDDWARFSection *M = + StringSwitch(Sec->Name) + .Case(".debug_addr", &AddrSection) + .Case(".debug_gnu_pubnames", &GnuPubNamesSection) + .Case(".debug_gnu_pubtypes", &GnuPubTypesSection) + .Case(".debug_info", &InfoSection) + .Case(".debug_ranges", &RangeSection) + .Case(".debug_rnglists", &RngListsSection) + .Case(".debug_line", &LineSection) .Default(nullptr)) { - m->Data = toStringRef(sec->data()); - m->sec = sec; + M->Data = toStringRef(Sec->data()); + M->Sec = Sec; continue; } - if (sec->name == ".debug_abbrev") - abbrevSection = toStringRef(sec->data()); - else if (sec->name == ".debug_str") - strSection = toStringRef(sec->data()); - else if (sec->name == ".debug_line_str") - lineStrSection = toStringRef(sec->data()); + if (Sec->Name == ".debug_abbrev") + AbbrevSection = toStringRef(Sec->data()); + else if (Sec->Name == ".debug_str") + StrSection = toStringRef(Sec->data()); + else if (Sec->Name == ".debug_line_str") + LineStringSection = toStringRef(Sec->data()); } } @@ -59,17 +58,17 @@ namespace { template struct LLDRelocationResolver { // In the ELF ABIs, S sepresents the value of the symbol in the relocation // entry. For Rela, the addend is stored as part of the relocation entry. - static uint64_t resolve(object::RelocationRef ref, uint64_t s, + static uint64_t Resolve(object::RelocationRef Ref, uint64_t S, uint64_t /* A */) { - return s + ref.getRawDataRefImpl().p; + return S + Ref.getRawDataRefImpl().p; } }; template struct LLDRelocationResolver> { // For Rel, the addend A is supplied by the caller. - static uint64_t resolve(object::RelocationRef /*Ref*/, uint64_t s, - uint64_t a) { - return s + a; + static uint64_t Resolve(object::RelocationRef /*Ref*/, uint64_t S, + uint64_t A) { + return S + A; } }; } // namespace @@ -80,48 +79,47 @@ template struct LLDRelocationResolver> { template template Optional -LLDDwarfObj::findAux(const InputSectionBase &sec, uint64_t pos, - ArrayRef rels) const { - auto it = - partition_point(rels, [=](const RelTy &a) { return a.r_offset < pos; }); - if (it == rels.end() || it->r_offset != pos) +LLDDwarfObj::findAux(const InputSectionBase &Sec, uint64_t Pos, + ArrayRef Rels) const { + auto It = + llvm::bsearch(Rels, [=](const RelTy &A) { return Pos <= A.r_offset; }); + if (It == Rels.end() || It->r_offset != Pos) return None; - const RelTy &rel = *it; + const RelTy &Rel = *It; - const ObjFile *file = sec.getFile(); - uint32_t symIndex = rel.getSymbol(config->isMips64EL); - const typename ELFT::Sym &sym = file->template getELFSyms()[symIndex]; - uint32_t secIndex = file->getSectionIndex(sym); + const ObjFile *File = Sec.getFile(); + uint32_t SymIndex = Rel.getSymbol(Config->IsMips64EL); + const typename ELFT::Sym &Sym = File->template getELFSyms()[SymIndex]; + uint32_t SecIndex = File->getSectionIndex(Sym); // An undefined symbol may be a symbol defined in a discarded section. We // shall still resolve it. This is important for --gdb-index: the end address // offset of an entry in .debug_ranges is relocated. If it is not resolved, // its zero value will terminate the decoding of .debug_ranges prematurely. - Symbol &s = file->getRelocTargetSym(rel); - uint64_t val = 0; - if (auto *dr = dyn_cast(&s)) { - val = dr->value; + Symbol &S = File->getRelocTargetSym(Rel); + uint64_t Val = 0; + if (auto *DR = dyn_cast(&S)) { + Val = DR->Value; // FIXME: We should be consistent about always adding the file // offset or not. - if (dr->section->flags & ELF::SHF_ALLOC) - val += cast(dr->section)->getOffsetInFile(); + if (DR->Section->Flags & ELF::SHF_ALLOC) + Val += cast(DR->Section)->getOffsetInFile(); } - DataRefImpl d; - d.p = getAddend(rel); - return RelocAddrEntry{secIndex, RelocationRef(d, nullptr), - val, Optional(), - 0, LLDRelocationResolver::resolve}; + DataRefImpl D; + D.p = getAddend(Rel); + return RelocAddrEntry{SecIndex, RelocationRef(D, nullptr), + LLDRelocationResolver::Resolve, Val}; } template -Optional LLDDwarfObj::find(const llvm::DWARFSection &s, - uint64_t pos) const { - auto &sec = static_cast(s); - if (sec.sec->areRelocsRela) - return findAux(*sec.sec, pos, sec.sec->template relas()); - return findAux(*sec.sec, pos, sec.sec->template rels()); +Optional LLDDwarfObj::find(const llvm::DWARFSection &S, + uint64_t Pos) const { + auto &Sec = static_cast(S); + if (Sec.Sec->AreRelocsRela) + return findAux(*Sec.Sec, Pos, Sec.Sec->template relas()); + return findAux(*Sec.Sec, Pos, Sec.Sec->template rels()); } template class elf::LLDDwarfObj; diff --git a/lld/ELF/DWARF.h b/lld/ELF/DWARF.h index 51ec9092f17235..09796158e32d82 100644 --- a/lld/ELF/DWARF.h +++ b/lld/ELF/DWARF.h @@ -20,75 +20,70 @@ namespace elf { class InputSection; struct LLDDWARFSection final : public llvm::DWARFSection { - InputSectionBase *sec = nullptr; + InputSectionBase *Sec = nullptr; }; template class LLDDwarfObj final : public llvm::DWARFObject { public: - explicit LLDDwarfObj(ObjFile *obj); + explicit LLDDwarfObj(ObjFile *Obj); void forEachInfoSections( - llvm::function_ref f) const override { - f(infoSection); + llvm::function_ref F) const override { + F(InfoSection); } - const llvm::DWARFSection &getRangesSection() const override { - return rangesSection; + const llvm::DWARFSection &getRangeSection() const override { + return RangeSection; } const llvm::DWARFSection &getRnglistsSection() const override { - return rnglistsSection; - } - - const llvm::DWARFSection &getStrOffsetsSection() const override { - return strOffsetsSection; + return RngListsSection; } const llvm::DWARFSection &getLineSection() const override { - return lineSection; + return LineSection; } const llvm::DWARFSection &getAddrSection() const override { - return addrSection; + return AddrSection; } - const llvm::DWARFSection &getGnuPubnamesSection() const override { - return gnuPubnamesSection; + const llvm::DWARFSection &getGnuPubNamesSection() const override { + return GnuPubNamesSection; } - const llvm::DWARFSection &getGnuPubtypesSection() const override { - return gnuPubtypesSection; + const llvm::DWARFSection &getGnuPubTypesSection() const override { + return GnuPubTypesSection; } StringRef getFileName() const override { return ""; } - StringRef getAbbrevSection() const override { return abbrevSection; } - StringRef getStrSection() const override { return strSection; } - StringRef getLineStrSection() const override { return lineStrSection; } + StringRef getAbbrevSection() const override { return AbbrevSection; } + StringRef getStringSection() const override { return StrSection; } + StringRef getLineStringSection() const override { return LineStringSection; } bool isLittleEndian() const override { return ELFT::TargetEndianness == llvm::support::little; } - llvm::Optional find(const llvm::DWARFSection &sec, - uint64_t pos) const override; + llvm::Optional find(const llvm::DWARFSection &Sec, + uint64_t Pos) const override; private: template - llvm::Optional findAux(const InputSectionBase &sec, - uint64_t pos, - ArrayRef rels) const; - - LLDDWARFSection gnuPubnamesSection; - LLDDWARFSection gnuPubtypesSection; - LLDDWARFSection infoSection; - LLDDWARFSection rangesSection; - LLDDWARFSection rnglistsSection; - LLDDWARFSection strOffsetsSection; - LLDDWARFSection lineSection; - LLDDWARFSection addrSection; - StringRef abbrevSection; - StringRef strSection; - StringRef lineStrSection; + llvm::Optional findAux(const InputSectionBase &Sec, + uint64_t Pos, + ArrayRef Rels) const; + + LLDDWARFSection GnuPubNamesSection; + LLDDWARFSection GnuPubTypesSection; + LLDDWARFSection InfoSection; + LLDDWARFSection RangeSection; + LLDDWARFSection RngListsSection; + LLDDWARFSection LineSection; + LLDDWARFSection AddrSection; + StringRef AbbrevSection; + StringRef StrSection; + StringRef LineStringSection; }; } // namespace elf diff --git a/lld/ELF/Driver.cpp b/lld/ELF/Driver.cpp index 36cda3a1e3d51b..008a6cd7954b40 100644 --- a/lld/ELF/Driver.cpp +++ b/lld/ELF/Driver.cpp @@ -68,49 +68,49 @@ using namespace llvm::support; using namespace lld; using namespace lld::elf; -Configuration *elf::config; -LinkerDriver *elf::driver; +Configuration *elf::Config; +LinkerDriver *elf::Driver; -static void setConfigs(opt::InputArgList &args); -static void readConfigs(opt::InputArgList &args); +static void setConfigs(opt::InputArgList &Args); +static void readConfigs(opt::InputArgList &Args); -bool elf::link(ArrayRef args, bool canExitEarly, - raw_ostream &error) { - errorHandler().logName = args::getFilenameWithoutExe(args[0]); - errorHandler().errorLimitExceededMsg = +bool elf::link(ArrayRef Args, bool CanExitEarly, + raw_ostream &Error) { + errorHandler().LogName = args::getFilenameWithoutExe(Args[0]); + errorHandler().ErrorLimitExceededMsg = "too many errors emitted, stopping now (use " "-error-limit=0 to see all errors)"; - errorHandler().errorOS = &error; - errorHandler().exitEarly = canExitEarly; - enableColors(error.has_colors()); + errorHandler().ErrorOS = &Error; + errorHandler().ExitEarly = CanExitEarly; + errorHandler().ColorDiagnostics = Error.has_colors(); - inputSections.clear(); - outputSections.clear(); - binaryFiles.clear(); - bitcodeFiles.clear(); - objectFiles.clear(); - sharedFiles.clear(); + InputSections.clear(); + OutputSections.clear(); + BinaryFiles.clear(); + BitcodeFiles.clear(); + ObjectFiles.clear(); + SharedFiles.clear(); - config = make(); - driver = make(); - script = make(); - symtab = make(); + Config = make(); + Driver = make(); + Script = make(); + Symtab = make(); - tar = nullptr; - memset(&in, 0, sizeof(in)); + Tar = nullptr; + memset(&In, 0, sizeof(In)); - partitions = {Partition()}; + Partitions = {Partition()}; - SharedFile::vernauxNum = 0; + SharedFile::VernauxNum = 0; - config->progName = args[0]; + Config->ProgName = Args[0]; - driver->main(args); + Driver->main(Args); // Exit immediately if we don't need to return to the caller. // This saves time because the overhead of calling destructors // for all globally-allocated objects is not negligible. - if (canExitEarly) + if (CanExitEarly) exitLld(errorCount() ? 1 : 0); freeArena(); @@ -118,16 +118,16 @@ bool elf::link(ArrayRef args, bool canExitEarly, } // Parses a linker -m option. -static std::tuple parseEmulation(StringRef emul) { - uint8_t osabi = 0; - StringRef s = emul; - if (s.endswith("_fbsd")) { - s = s.drop_back(5); - osabi = ELFOSABI_FREEBSD; +static std::tuple parseEmulation(StringRef Emul) { + uint8_t OSABI = 0; + StringRef S = Emul; + if (S.endswith("_fbsd")) { + S = S.drop_back(5); + OSABI = ELFOSABI_FREEBSD; } - std::pair ret = - StringSwitch>(s) + std::pair Ret = + StringSwitch>(S) .Cases("aarch64elf", "aarch64linux", "aarch64_elf64_le_vec", {ELF64LEKind, EM_AARCH64}) .Cases("armelf", "armelf_linux_eabi", {ELF32LEKind, EM_ARM}) @@ -146,101 +146,99 @@ static std::tuple parseEmulation(StringRef emul) { .Case("elf_iamcu", {ELF32LEKind, EM_IAMCU}) .Default({ELFNoneKind, EM_NONE}); - if (ret.first == ELFNoneKind) - error("unknown emulation: " + emul); - return std::make_tuple(ret.first, ret.second, osabi); + if (Ret.first == ELFNoneKind) + error("unknown emulation: " + Emul); + return std::make_tuple(Ret.first, Ret.second, OSABI); } // Returns slices of MB by parsing MB as an archive file. // Each slice consists of a member file in the archive. std::vector> static getArchiveMembers( - MemoryBufferRef mb) { - std::unique_ptr file = - CHECK(Archive::create(mb), - mb.getBufferIdentifier() + ": failed to parse archive"); - - std::vector> v; - Error err = Error::success(); - bool addToTar = file->isThin() && tar; - for (const ErrorOr &cOrErr : file->children(err)) { - Archive::Child c = - CHECK(cOrErr, mb.getBufferIdentifier() + + MemoryBufferRef MB) { + std::unique_ptr File = + CHECK(Archive::create(MB), + MB.getBufferIdentifier() + ": failed to parse archive"); + + std::vector> V; + Error Err = Error::success(); + bool AddToTar = File->isThin() && Tar; + for (const ErrorOr &COrErr : File->children(Err)) { + Archive::Child C = + CHECK(COrErr, MB.getBufferIdentifier() + ": could not get the child of the archive"); - MemoryBufferRef mbref = - CHECK(c.getMemoryBufferRef(), - mb.getBufferIdentifier() + + MemoryBufferRef MBRef = + CHECK(C.getMemoryBufferRef(), + MB.getBufferIdentifier() + ": could not get the buffer for a child of the archive"); - if (addToTar) - tar->append(relativeToRoot(check(c.getFullName())), mbref.getBuffer()); - v.push_back(std::make_pair(mbref, c.getChildOffset())); + if (AddToTar) + Tar->append(relativeToRoot(check(C.getFullName())), MBRef.getBuffer()); + V.push_back(std::make_pair(MBRef, C.getChildOffset())); } - if (err) - fatal(mb.getBufferIdentifier() + ": Archive::children failed: " + - toString(std::move(err))); + if (Err) + fatal(MB.getBufferIdentifier() + ": Archive::children failed: " + + toString(std::move(Err))); // Take ownership of memory buffers created for members of thin archives. - for (std::unique_ptr &mb : file->takeThinBuffers()) - make>(std::move(mb)); + for (std::unique_ptr &MB : File->takeThinBuffers()) + make>(std::move(MB)); - return v; + return V; } // Opens a file and create a file object. Path has to be resolved already. -void LinkerDriver::addFile(StringRef path, bool withLOption) { +void LinkerDriver::addFile(StringRef Path, bool WithLOption) { using namespace sys::fs; - Optional buffer = readFile(path); - if (!buffer.hasValue()) + Optional Buffer = readFile(Path); + if (!Buffer.hasValue()) return; - MemoryBufferRef mbref = *buffer; + MemoryBufferRef MBRef = *Buffer; - if (config->formatBinary) { - files.push_back(make(mbref)); + if (Config->FormatBinary) { + Files.push_back(make(MBRef)); return; } - switch (identify_magic(mbref.getBuffer())) { + switch (identify_magic(MBRef.getBuffer())) { case file_magic::unknown: - readLinkerScript(mbref); + readLinkerScript(MBRef); return; case file_magic::archive: { // Handle -whole-archive. - if (inWholeArchive) { - for (const auto &p : getArchiveMembers(mbref)) - files.push_back(createObjectFile(p.first, path, p.second)); + if (InWholeArchive) { + for (const auto &P : getArchiveMembers(MBRef)) + Files.push_back(createObjectFile(P.first, Path, P.second)); return; } - std::unique_ptr file = - CHECK(Archive::create(mbref), path + ": failed to parse archive"); + std::unique_ptr File = + CHECK(Archive::create(MBRef), Path + ": failed to parse archive"); // If an archive file has no symbol table, it is likely that a user // is attempting LTO and using a default ar command that doesn't // understand the LLVM bitcode file. It is a pretty common error, so // we'll handle it as if it had a symbol table. - if (!file->isEmpty() && !file->hasSymbolTable()) { + if (!File->isEmpty() && !File->hasSymbolTable()) { // Check if all members are bitcode files. If not, ignore, which is the // default action without the LTO hack described above. - for (const std::pair &p : - getArchiveMembers(mbref)) - if (identify_magic(p.first.getBuffer()) != file_magic::bitcode) { - error(path + ": archive has no index; run ranlib to add one"); + for (const std::pair &P : + getArchiveMembers(MBRef)) + if (identify_magic(P.first.getBuffer()) != file_magic::bitcode) return; - } - for (const std::pair &p : - getArchiveMembers(mbref)) - files.push_back(make(p.first, path, p.second)); + for (const std::pair &P : + getArchiveMembers(MBRef)) + Files.push_back(make(P.first, Path, P.second)); return; } // Handle the regular case. - files.push_back(make(std::move(file))); + Files.push_back(make(std::move(File))); return; } case file_magic::elf_shared_object: - if (config->isStatic || config->relocatable) { - error("attempted static link of dynamic object " + path); + if (Config->Static || Config->Relocatable) { + error("attempted static link of dynamic object " + Path); return; } @@ -254,27 +252,27 @@ void LinkerDriver::addFile(StringRef path, bool withLOption) { // If a file was specified by -lfoo, the directory part is not // significant, as a user did not specify it. This behavior is // compatible with GNU. - files.push_back( - make(mbref, withLOption ? path::filename(path) : path)); + Files.push_back( + make(MBRef, WithLOption ? path::filename(Path) : Path)); return; case file_magic::bitcode: case file_magic::elf_relocatable: - if (inLib) - files.push_back(make(mbref, "", 0)); + if (InLib) + Files.push_back(make(MBRef, "", 0)); else - files.push_back(createObjectFile(mbref)); + Files.push_back(createObjectFile(MBRef)); break; default: - error(path + ": unknown file type"); + error(Path + ": unknown file type"); } } // Add a given library by searching it from input search paths. -void LinkerDriver::addLibrary(StringRef name) { - if (Optional path = searchLibrary(name)) - addFile(*path, /*withLOption=*/true); +void LinkerDriver::addLibrary(StringRef Name) { + if (Optional Path = searchLibrary(Name)) + addFile(*Path, /*WithLOption=*/true); else - error("unable to find library -l" + name); + error("unable to find library -l" + Name); } // This function is called on startup. We need this for LTO since @@ -293,121 +291,117 @@ static void initLLVM() { static void checkOptions() { // The MIPS ABI as of 2016 does not support the GNU-style symbol lookup // table which is a relatively new feature. - if (config->emachine == EM_MIPS && config->gnuHash) + if (Config->EMachine == EM_MIPS && Config->GnuHash) error("the .gnu.hash section is not compatible with the MIPS target"); - if (config->fixCortexA53Errata843419 && config->emachine != EM_AARCH64) + if (Config->FixCortexA53Errata843419 && Config->EMachine != EM_AARCH64) error("--fix-cortex-a53-843419 is only supported on AArch64 targets"); - if (config->tocOptimize && config->emachine != EM_PPC64) + if (Config->TocOptimize && Config->EMachine != EM_PPC64) error("--toc-optimize is only supported on the PowerPC64 target"); - if (config->pie && config->shared) + if (Config->Pie && Config->Shared) error("-shared and -pie may not be used together"); - if (!config->shared && !config->filterList.empty()) + if (!Config->Shared && !Config->FilterList.empty()) error("-F may not be used without -shared"); - if (!config->shared && !config->auxiliaryList.empty()) + if (!Config->Shared && !Config->AuxiliaryList.empty()) error("-f may not be used without -shared"); - if (!config->relocatable && !config->defineCommon) + if (!Config->Relocatable && !Config->DefineCommon) error("-no-define-common not supported in non relocatable output"); - if (config->strip == StripPolicy::All && config->emitRelocs) - error("--strip-all and --emit-relocs may not be used together"); - - if (config->zText && config->zIfuncNoplt) + if (Config->ZText && Config->ZIfuncNoplt) error("-z text and -z ifunc-noplt may not be used together"); - if (config->relocatable) { - if (config->shared) + if (Config->Relocatable) { + if (Config->Shared) error("-r and -shared may not be used together"); - if (config->gcSections) + if (Config->GcSections) error("-r and --gc-sections may not be used together"); - if (config->gdbIndex) + if (Config->GdbIndex) error("-r and --gdb-index may not be used together"); - if (config->icf != ICFLevel::None) + if (Config->ICF != ICFLevel::None) error("-r and --icf may not be used together"); - if (config->pie) + if (Config->Pie) error("-r and -pie may not be used together"); } - if (config->executeOnly) { - if (config->emachine != EM_AARCH64) + if (Config->ExecuteOnly) { + if (Config->EMachine != EM_AARCH64) error("-execute-only is only supported on AArch64 targets"); - if (config->singleRoRx && !script->hasSectionsCommand) + if (Config->SingleRoRx && !Script->HasSectionsCommand) error("-execute-only and -no-rosegment cannot be used together"); } - if (config->zRetpolineplt && config->requireCET) + if (Config->ZRetpolineplt && Config->RequireCET) error("--require-cet may not be used with -z retpolineplt"); - if (config->emachine != EM_AARCH64) { - if (config->pacPlt) + if (Config->EMachine != EM_AARCH64) { + if (Config->PacPlt) error("--pac-plt only supported on AArch64"); - if (config->forceBTI) + if (Config->ForceBTI) error("--force-bti only supported on AArch64"); } } -static const char *getReproduceOption(opt::InputArgList &args) { - if (auto *arg = args.getLastArg(OPT_reproduce)) - return arg->getValue(); +static const char *getReproduceOption(opt::InputArgList &Args) { + if (auto *Arg = Args.getLastArg(OPT_reproduce)) + return Arg->getValue(); return getenv("LLD_REPRODUCE"); } -static bool hasZOption(opt::InputArgList &args, StringRef key) { - for (auto *arg : args.filtered(OPT_z)) - if (key == arg->getValue()) +static bool hasZOption(opt::InputArgList &Args, StringRef Key) { + for (auto *Arg : Args.filtered(OPT_z)) + if (Key == Arg->getValue()) return true; return false; } -static bool getZFlag(opt::InputArgList &args, StringRef k1, StringRef k2, +static bool getZFlag(opt::InputArgList &Args, StringRef K1, StringRef K2, bool Default) { - for (auto *arg : args.filtered_reverse(OPT_z)) { - if (k1 == arg->getValue()) + for (auto *Arg : Args.filtered_reverse(OPT_z)) { + if (K1 == Arg->getValue()) return true; - if (k2 == arg->getValue()) + if (K2 == Arg->getValue()) return false; } return Default; } -static bool isKnownZFlag(StringRef s) { - return s == "combreloc" || s == "copyreloc" || s == "defs" || - s == "execstack" || s == "global" || s == "hazardplt" || - s == "ifunc-noplt" || s == "initfirst" || s == "interpose" || - s == "keep-text-section-prefix" || s == "lazy" || s == "muldefs" || - s == "separate-code" || s == "nocombreloc" || s == "nocopyreloc" || - s == "nodefaultlib" || s == "nodelete" || s == "nodlopen" || - s == "noexecstack" || s == "nokeep-text-section-prefix" || - s == "norelro" || s == "noseparate-code" || s == "notext" || - s == "now" || s == "origin" || s == "relro" || s == "retpolineplt" || - s == "rodynamic" || s == "text" || s == "wxneeded" || - s.startswith("common-page-size") || s.startswith("max-page-size=") || - s.startswith("stack-size="); +static bool isKnownZFlag(StringRef S) { + return S == "combreloc" || S == "copyreloc" || S == "defs" || + S == "execstack" || S == "global" || S == "hazardplt" || + S == "ifunc-noplt" || S == "initfirst" || S == "interpose" || + S == "keep-text-section-prefix" || S == "lazy" || S == "muldefs" || + S == "nocombreloc" || S == "nocopyreloc" || S == "nodefaultlib" || + S == "nodelete" || S == "nodlopen" || S == "noexecstack" || + S == "nokeep-text-section-prefix" || S == "norelro" || S == "notext" || + S == "now" || S == "origin" || S == "relro" || S == "retpolineplt" || + S == "rodynamic" || S == "text" || S == "wxneeded" || + S.startswith("common-page-size") || S.startswith("max-page-size=") || + S.startswith("stack-size="); } // Report an error for an unknown -z option. -static void checkZOptions(opt::InputArgList &args) { - for (auto *arg : args.filtered(OPT_z)) - if (!isKnownZFlag(arg->getValue())) - error("unknown -z value: " + StringRef(arg->getValue())); +static void checkZOptions(opt::InputArgList &Args) { + for (auto *Arg : Args.filtered(OPT_z)) + if (!isKnownZFlag(Arg->getValue())) + error("unknown -z value: " + StringRef(Arg->getValue())); } -void LinkerDriver::main(ArrayRef argsArr) { - ELFOptTable parser; - opt::InputArgList args = parser.parse(argsArr.slice(1)); +void LinkerDriver::main(ArrayRef ArgsArr) { + ELFOptTable Parser; + opt::InputArgList Args = Parser.parse(ArgsArr.slice(1)); // Interpret this flag early because error() depends on them. - errorHandler().errorLimit = args::getInteger(args, OPT_error_limit, 20); - checkZOptions(args); + errorHandler().ErrorLimit = args::getInteger(Args, OPT_error_limit, 20); + checkZOptions(Args); // Handle -help - if (args.hasArg(OPT_help)) { + if (Args.hasArg(OPT_help)) { printHelp(); return; } @@ -427,39 +421,39 @@ void LinkerDriver::main(ArrayRef argsArr) { // lot of "configure" scripts out there that are generated by old version // of Libtool. We cannot convince every software developer to migrate to // the latest version and re-generate scripts. So we have this hack. - if (args.hasArg(OPT_v) || args.hasArg(OPT_version)) + if (Args.hasArg(OPT_v) || Args.hasArg(OPT_version)) message(getLLDVersion() + " (compatible with GNU linkers)"); - if (const char *path = getReproduceOption(args)) { + if (const char *Path = getReproduceOption(Args)) { // Note that --reproduce is a debug option so you can ignore it // if you are trying to understand the whole picture of the code. - Expected> errOrWriter = - TarWriter::create(path, path::stem(path)); - if (errOrWriter) { - tar = std::move(*errOrWriter); - tar->append("response.txt", createResponseFile(args)); - tar->append("version.txt", getLLDVersion() + "\n"); + Expected> ErrOrWriter = + TarWriter::create(Path, path::stem(Path)); + if (ErrOrWriter) { + Tar = std::move(*ErrOrWriter); + Tar->append("response.txt", createResponseFile(Args)); + Tar->append("version.txt", getLLDVersion() + "\n"); } else { - error("--reproduce: " + toString(errOrWriter.takeError())); + error("--reproduce: " + toString(ErrOrWriter.takeError())); } } - readConfigs(args); + readConfigs(Args); // The behavior of -v or --version is a bit strange, but this is // needed for compatibility with GNU linkers. - if (args.hasArg(OPT_v) && !args.hasArg(OPT_INPUT)) + if (Args.hasArg(OPT_v) && !Args.hasArg(OPT_INPUT)) return; - if (args.hasArg(OPT_version)) + if (Args.hasArg(OPT_version)) return; initLLVM(); - createFiles(args); + createFiles(Args); if (errorCount()) return; inferMachineType(); - setConfigs(args); + setConfigs(Args); checkOptions(); if (errorCount()) return; @@ -467,178 +461,177 @@ void LinkerDriver::main(ArrayRef argsArr) { // The Target instance handles target-specific stuff, such as applying // relocations or writing a PLT section. It also contains target-dependent // values such as a default image base address. - target = getTarget(); + Target = getTarget(); - switch (config->ekind) { + switch (Config->EKind) { case ELF32LEKind: - link(args); + link(Args); return; case ELF32BEKind: - link(args); + link(Args); return; case ELF64LEKind: - link(args); + link(Args); return; case ELF64BEKind: - link(args); + link(Args); return; default: llvm_unreachable("unknown Config->EKind"); } } -static std::string getRpath(opt::InputArgList &args) { - std::vector v = args::getStrings(args, OPT_rpath); - return llvm::join(v.begin(), v.end(), ":"); +static std::string getRpath(opt::InputArgList &Args) { + std::vector V = args::getStrings(Args, OPT_rpath); + return llvm::join(V.begin(), V.end(), ":"); } // Determines what we should do if there are remaining unresolved // symbols after the name resolution. -static UnresolvedPolicy getUnresolvedSymbolPolicy(opt::InputArgList &args) { - UnresolvedPolicy errorOrWarn = args.hasFlag(OPT_error_unresolved_symbols, +static UnresolvedPolicy getUnresolvedSymbolPolicy(opt::InputArgList &Args) { + UnresolvedPolicy ErrorOrWarn = Args.hasFlag(OPT_error_unresolved_symbols, OPT_warn_unresolved_symbols, true) ? UnresolvedPolicy::ReportError : UnresolvedPolicy::Warn; // Process the last of -unresolved-symbols, -no-undefined or -z defs. - for (auto *arg : llvm::reverse(args)) { - switch (arg->getOption().getID()) { + for (auto *Arg : llvm::reverse(Args)) { + switch (Arg->getOption().getID()) { case OPT_unresolved_symbols: { - StringRef s = arg->getValue(); - if (s == "ignore-all" || s == "ignore-in-object-files") + StringRef S = Arg->getValue(); + if (S == "ignore-all" || S == "ignore-in-object-files") return UnresolvedPolicy::Ignore; - if (s == "ignore-in-shared-libs" || s == "report-all") - return errorOrWarn; - error("unknown --unresolved-symbols value: " + s); + if (S == "ignore-in-shared-libs" || S == "report-all") + return ErrorOrWarn; + error("unknown --unresolved-symbols value: " + S); continue; } case OPT_no_undefined: - return errorOrWarn; + return ErrorOrWarn; case OPT_z: - if (StringRef(arg->getValue()) == "defs") - return errorOrWarn; + if (StringRef(Arg->getValue()) == "defs") + return ErrorOrWarn; continue; } } // -shared implies -unresolved-symbols=ignore-all because missing // symbols are likely to be resolved at runtime using other DSOs. - if (config->shared) + if (Config->Shared) return UnresolvedPolicy::Ignore; - return errorOrWarn; + return ErrorOrWarn; } -static Target2Policy getTarget2(opt::InputArgList &args) { - StringRef s = args.getLastArgValue(OPT_target2, "got-rel"); - if (s == "rel") +static Target2Policy getTarget2(opt::InputArgList &Args) { + StringRef S = Args.getLastArgValue(OPT_target2, "got-rel"); + if (S == "rel") return Target2Policy::Rel; - if (s == "abs") + if (S == "abs") return Target2Policy::Abs; - if (s == "got-rel") + if (S == "got-rel") return Target2Policy::GotRel; - error("unknown --target2 option: " + s); + error("unknown --target2 option: " + S); return Target2Policy::GotRel; } -static bool isOutputFormatBinary(opt::InputArgList &args) { - StringRef s = args.getLastArgValue(OPT_oformat, "elf"); - if (s == "binary") +static bool isOutputFormatBinary(opt::InputArgList &Args) { + StringRef S = Args.getLastArgValue(OPT_oformat, "elf"); + if (S == "binary") return true; - if (!s.startswith("elf")) - error("unknown --oformat value: " + s); + if (!S.startswith("elf")) + error("unknown --oformat value: " + S); return false; } -static DiscardPolicy getDiscard(opt::InputArgList &args) { - if (args.hasArg(OPT_relocatable)) +static DiscardPolicy getDiscard(opt::InputArgList &Args) { + if (Args.hasArg(OPT_relocatable)) return DiscardPolicy::None; - auto *arg = - args.getLastArg(OPT_discard_all, OPT_discard_locals, OPT_discard_none); - if (!arg) + auto *Arg = + Args.getLastArg(OPT_discard_all, OPT_discard_locals, OPT_discard_none); + if (!Arg) return DiscardPolicy::Default; - if (arg->getOption().getID() == OPT_discard_all) + if (Arg->getOption().getID() == OPT_discard_all) return DiscardPolicy::All; - if (arg->getOption().getID() == OPT_discard_locals) + if (Arg->getOption().getID() == OPT_discard_locals) return DiscardPolicy::Locals; return DiscardPolicy::None; } -static StringRef getDynamicLinker(opt::InputArgList &args) { - auto *arg = args.getLastArg(OPT_dynamic_linker, OPT_no_dynamic_linker); - if (!arg || arg->getOption().getID() == OPT_no_dynamic_linker) +static StringRef getDynamicLinker(opt::InputArgList &Args) { + auto *Arg = Args.getLastArg(OPT_dynamic_linker, OPT_no_dynamic_linker); + if (!Arg || Arg->getOption().getID() == OPT_no_dynamic_linker) return ""; - return arg->getValue(); + return Arg->getValue(); } -static ICFLevel getICF(opt::InputArgList &args) { - auto *arg = args.getLastArg(OPT_icf_none, OPT_icf_safe, OPT_icf_all); - if (!arg || arg->getOption().getID() == OPT_icf_none) +static ICFLevel getICF(opt::InputArgList &Args) { + auto *Arg = Args.getLastArg(OPT_icf_none, OPT_icf_safe, OPT_icf_all); + if (!Arg || Arg->getOption().getID() == OPT_icf_none) return ICFLevel::None; - if (arg->getOption().getID() == OPT_icf_safe) + if (Arg->getOption().getID() == OPT_icf_safe) return ICFLevel::Safe; return ICFLevel::All; } -static StripPolicy getStrip(opt::InputArgList &args) { - if (args.hasArg(OPT_relocatable)) +static StripPolicy getStrip(opt::InputArgList &Args) { + if (Args.hasArg(OPT_relocatable)) return StripPolicy::None; - auto *arg = args.getLastArg(OPT_strip_all, OPT_strip_debug); - if (!arg) + auto *Arg = Args.getLastArg(OPT_strip_all, OPT_strip_debug); + if (!Arg) return StripPolicy::None; - if (arg->getOption().getID() == OPT_strip_all) + if (Arg->getOption().getID() == OPT_strip_all) return StripPolicy::All; return StripPolicy::Debug; } -static uint64_t parseSectionAddress(StringRef s, opt::InputArgList &args, - const opt::Arg &arg) { - uint64_t va = 0; - if (s.startswith("0x")) - s = s.drop_front(2); - if (!to_integer(s, va, 16)) - error("invalid argument: " + arg.getAsString(args)); - return va; +static uint64_t parseSectionAddress(StringRef S, const opt::Arg &Arg) { + uint64_t VA = 0; + if (S.startswith("0x")) + S = S.drop_front(2); + if (!to_integer(S, VA, 16)) + error("invalid argument: " + toString(Arg)); + return VA; } -static StringMap getSectionStartMap(opt::InputArgList &args) { - StringMap ret; - for (auto *arg : args.filtered(OPT_section_start)) { - StringRef name; - StringRef addr; - std::tie(name, addr) = StringRef(arg->getValue()).split('='); - ret[name] = parseSectionAddress(addr, args, *arg); +static StringMap getSectionStartMap(opt::InputArgList &Args) { + StringMap Ret; + for (auto *Arg : Args.filtered(OPT_section_start)) { + StringRef Name; + StringRef Addr; + std::tie(Name, Addr) = StringRef(Arg->getValue()).split('='); + Ret[Name] = parseSectionAddress(Addr, *Arg); } - if (auto *arg = args.getLastArg(OPT_Ttext)) - ret[".text"] = parseSectionAddress(arg->getValue(), args, *arg); - if (auto *arg = args.getLastArg(OPT_Tdata)) - ret[".data"] = parseSectionAddress(arg->getValue(), args, *arg); - if (auto *arg = args.getLastArg(OPT_Tbss)) - ret[".bss"] = parseSectionAddress(arg->getValue(), args, *arg); - return ret; + if (auto *Arg = Args.getLastArg(OPT_Ttext)) + Ret[".text"] = parseSectionAddress(Arg->getValue(), *Arg); + if (auto *Arg = Args.getLastArg(OPT_Tdata)) + Ret[".data"] = parseSectionAddress(Arg->getValue(), *Arg); + if (auto *Arg = Args.getLastArg(OPT_Tbss)) + Ret[".bss"] = parseSectionAddress(Arg->getValue(), *Arg); + return Ret; } -static SortSectionPolicy getSortSection(opt::InputArgList &args) { - StringRef s = args.getLastArgValue(OPT_sort_section); - if (s == "alignment") +static SortSectionPolicy getSortSection(opt::InputArgList &Args) { + StringRef S = Args.getLastArgValue(OPT_sort_section); + if (S == "alignment") return SortSectionPolicy::Alignment; - if (s == "name") + if (S == "name") return SortSectionPolicy::Name; - if (!s.empty()) - error("unknown --sort-section rule: " + s); + if (!S.empty()) + error("unknown --sort-section rule: " + S); return SortSectionPolicy::Default; } -static OrphanHandlingPolicy getOrphanHandling(opt::InputArgList &args) { - StringRef s = args.getLastArgValue(OPT_orphan_handling, "place"); - if (s == "warn") +static OrphanHandlingPolicy getOrphanHandling(opt::InputArgList &Args) { + StringRef S = Args.getLastArgValue(OPT_orphan_handling, "place"); + if (S == "warn") return OrphanHandlingPolicy::Warn; - if (s == "error") + if (S == "error") return OrphanHandlingPolicy::Error; - if (s != "place") - error("unknown --orphan-handling mode: " + s); + if (S != "place") + error("unknown --orphan-handling mode: " + S); return OrphanHandlingPolicy::Place; } @@ -646,416 +639,410 @@ static OrphanHandlingPolicy getOrphanHandling(opt::InputArgList &args) { // synonym for "sha1" because all our hash functions including // -build-id=sha1 are actually tree hashes for performance reasons. static std::pair> -getBuildId(opt::InputArgList &args) { - auto *arg = args.getLastArg(OPT_build_id, OPT_build_id_eq); - if (!arg) +getBuildId(opt::InputArgList &Args) { + auto *Arg = Args.getLastArg(OPT_build_id, OPT_build_id_eq); + if (!Arg) return {BuildIdKind::None, {}}; - if (arg->getOption().getID() == OPT_build_id) + if (Arg->getOption().getID() == OPT_build_id) return {BuildIdKind::Fast, {}}; - StringRef s = arg->getValue(); - if (s == "fast") + StringRef S = Arg->getValue(); + if (S == "fast") return {BuildIdKind::Fast, {}}; - if (s == "md5") + if (S == "md5") return {BuildIdKind::Md5, {}}; - if (s == "sha1" || s == "tree") + if (S == "sha1" || S == "tree") return {BuildIdKind::Sha1, {}}; - if (s == "uuid") + if (S == "uuid") return {BuildIdKind::Uuid, {}}; - if (s.startswith("0x")) - return {BuildIdKind::Hexstring, parseHex(s.substr(2))}; + if (S.startswith("0x")) + return {BuildIdKind::Hexstring, parseHex(S.substr(2))}; - if (s != "none") - error("unknown --build-id style: " + s); + if (S != "none") + error("unknown --build-id style: " + S); return {BuildIdKind::None, {}}; } -static std::pair getPackDynRelocs(opt::InputArgList &args) { - StringRef s = args.getLastArgValue(OPT_pack_dyn_relocs, "none"); - if (s == "android") +static std::pair getPackDynRelocs(opt::InputArgList &Args) { + StringRef S = Args.getLastArgValue(OPT_pack_dyn_relocs, "none"); + if (S == "android") return {true, false}; - if (s == "relr") + if (S == "relr") return {false, true}; - if (s == "android+relr") + if (S == "android+relr") return {true, true}; - if (s != "none") - error("unknown -pack-dyn-relocs format: " + s); + if (S != "none") + error("unknown -pack-dyn-relocs format: " + S); return {false, false}; } -static void readCallGraph(MemoryBufferRef mb) { +static void readCallGraph(MemoryBufferRef MB) { // Build a map from symbol name to section - DenseMap map; - for (InputFile *file : objectFiles) - for (Symbol *sym : file->getSymbols()) - map[sym->getName()] = sym; - - auto findSection = [&](StringRef name) -> InputSectionBase * { - Symbol *sym = map.lookup(name); - if (!sym) { - if (config->warnSymbolOrdering) - warn(mb.getBufferIdentifier() + ": no such symbol: " + name); + DenseMap Map; + for (InputFile *File : ObjectFiles) + for (Symbol *Sym : File->getSymbols()) + Map[Sym->getName()] = Sym; + + auto FindSection = [&](StringRef Name) -> InputSectionBase * { + Symbol *Sym = Map.lookup(Name); + if (!Sym) { + if (Config->WarnSymbolOrdering) + warn(MB.getBufferIdentifier() + ": no such symbol: " + Name); return nullptr; } - maybeWarnUnorderableSymbol(sym); + maybeWarnUnorderableSymbol(Sym); - if (Defined *dr = dyn_cast_or_null(sym)) - return dyn_cast_or_null(dr->section); + if (Defined *DR = dyn_cast_or_null(Sym)) + return dyn_cast_or_null(DR->Section); return nullptr; }; - for (StringRef line : args::getLines(mb)) { - SmallVector fields; - line.split(fields, ' '); - uint64_t count; + for (StringRef Line : args::getLines(MB)) { + SmallVector Fields; + Line.split(Fields, ' '); + uint64_t Count; - if (fields.size() != 3 || !to_integer(fields[2], count)) { - error(mb.getBufferIdentifier() + ": parse error"); + if (Fields.size() != 3 || !to_integer(Fields[2], Count)) { + error(MB.getBufferIdentifier() + ": parse error"); return; } - if (InputSectionBase *from = findSection(fields[0])) - if (InputSectionBase *to = findSection(fields[1])) - config->callGraphProfile[std::make_pair(from, to)] += count; + if (InputSectionBase *From = FindSection(Fields[0])) + if (InputSectionBase *To = FindSection(Fields[1])) + Config->CallGraphProfile[std::make_pair(From, To)] += Count; } } template static void readCallGraphsFromObjectFiles() { - for (auto file : objectFiles) { - auto *obj = cast>(file); + for (auto File : ObjectFiles) { + auto *Obj = cast>(File); - for (const Elf_CGProfile_Impl &cgpe : obj->cgProfile) { - auto *fromSym = dyn_cast(&obj->getSymbol(cgpe.cgp_from)); - auto *toSym = dyn_cast(&obj->getSymbol(cgpe.cgp_to)); - if (!fromSym || !toSym) + for (const Elf_CGProfile_Impl &CGPE : Obj->CGProfile) { + auto *FromSym = dyn_cast(&Obj->getSymbol(CGPE.cgp_from)); + auto *ToSym = dyn_cast(&Obj->getSymbol(CGPE.cgp_to)); + if (!FromSym || !ToSym) continue; - auto *from = dyn_cast_or_null(fromSym->section); - auto *to = dyn_cast_or_null(toSym->section); - if (from && to) - config->callGraphProfile[{from, to}] += cgpe.cgp_weight; + auto *From = dyn_cast_or_null(FromSym->Section); + auto *To = dyn_cast_or_null(ToSym->Section); + if (From && To) + Config->CallGraphProfile[{From, To}] += CGPE.cgp_weight; } } } -static bool getCompressDebugSections(opt::InputArgList &args) { - StringRef s = args.getLastArgValue(OPT_compress_debug_sections, "none"); - if (s == "none") +static bool getCompressDebugSections(opt::InputArgList &Args) { + StringRef S = Args.getLastArgValue(OPT_compress_debug_sections, "none"); + if (S == "none") return false; - if (s != "zlib") - error("unknown --compress-debug-sections value: " + s); + if (S != "zlib") + error("unknown --compress-debug-sections value: " + S); if (!zlib::isAvailable()) error("--compress-debug-sections: zlib is not available"); return true; } -static std::pair getOldNewOptions(opt::InputArgList &args, - unsigned id) { - auto *arg = args.getLastArg(id); - if (!arg) +static std::pair getOldNewOptions(opt::InputArgList &Args, + unsigned Id) { + auto *Arg = Args.getLastArg(Id); + if (!Arg) return {"", ""}; - StringRef s = arg->getValue(); - std::pair ret = s.split(';'); - if (ret.second.empty()) - error(arg->getSpelling() + " expects 'old;new' format, but got " + s); - return ret; + StringRef S = Arg->getValue(); + std::pair Ret = S.split(';'); + if (Ret.second.empty()) + error(Arg->getSpelling() + " expects 'old;new' format, but got " + S); + return Ret; } // Parse the symbol ordering file and warn for any duplicate entries. -static std::vector getSymbolOrderingFile(MemoryBufferRef mb) { - SetVector names; - for (StringRef s : args::getLines(mb)) - if (!names.insert(s) && config->warnSymbolOrdering) - warn(mb.getBufferIdentifier() + ": duplicate ordered symbol: " + s); +static std::vector getSymbolOrderingFile(MemoryBufferRef MB) { + SetVector Names; + for (StringRef S : args::getLines(MB)) + if (!Names.insert(S) && Config->WarnSymbolOrdering) + warn(MB.getBufferIdentifier() + ": duplicate ordered symbol: " + S); - return names.takeVector(); + return Names.takeVector(); } -static void parseClangOption(StringRef opt, const Twine &msg) { - std::string err; - raw_string_ostream os(err); +static void parseClangOption(StringRef Opt, const Twine &Msg) { + std::string Err; + raw_string_ostream OS(Err); - const char *argv[] = {config->progName.data(), opt.data()}; - if (cl::ParseCommandLineOptions(2, argv, "", &os)) + const char *Argv[] = {Config->ProgName.data(), Opt.data()}; + if (cl::ParseCommandLineOptions(2, Argv, "", &OS)) return; - os.flush(); - error(msg + ": " + StringRef(err).trim()); + OS.flush(); + error(Msg + ": " + StringRef(Err).trim()); } // Initializes Config members by the command line options. -static void readConfigs(opt::InputArgList &args) { - errorHandler().verbose = args.hasArg(OPT_verbose); - errorHandler().fatalWarnings = - args.hasFlag(OPT_fatal_warnings, OPT_no_fatal_warnings, false); - errorHandler().vsDiagnostics = - args.hasArg(OPT_visual_studio_diagnostics_format, false); - threadsEnabled = args.hasFlag(OPT_threads, OPT_no_threads, true); - - config->allowMultipleDefinition = - args.hasFlag(OPT_allow_multiple_definition, +static void readConfigs(opt::InputArgList &Args) { + errorHandler().Verbose = Args.hasArg(OPT_verbose); + errorHandler().FatalWarnings = + Args.hasFlag(OPT_fatal_warnings, OPT_no_fatal_warnings, false); + ThreadsEnabled = Args.hasFlag(OPT_threads, OPT_no_threads, true); + + Config->AllowMultipleDefinition = + Args.hasFlag(OPT_allow_multiple_definition, OPT_no_allow_multiple_definition, false) || - hasZOption(args, "muldefs"); - config->allowShlibUndefined = - args.hasFlag(OPT_allow_shlib_undefined, OPT_no_allow_shlib_undefined, - args.hasArg(OPT_shared)); - config->auxiliaryList = args::getStrings(args, OPT_auxiliary); - config->bsymbolic = args.hasArg(OPT_Bsymbolic); - config->bsymbolicFunctions = args.hasArg(OPT_Bsymbolic_functions); - config->checkSections = - args.hasFlag(OPT_check_sections, OPT_no_check_sections, true); - config->chroot = args.getLastArgValue(OPT_chroot); - config->compressDebugSections = getCompressDebugSections(args); - config->cref = args.hasFlag(OPT_cref, OPT_no_cref, false); - config->defineCommon = args.hasFlag(OPT_define_common, OPT_no_define_common, - !args.hasArg(OPT_relocatable)); - config->demangle = args.hasFlag(OPT_demangle, OPT_no_demangle, true); - config->dependentLibraries = args.hasFlag(OPT_dependent_libraries, OPT_no_dependent_libraries, true); - config->disableVerify = args.hasArg(OPT_disable_verify); - config->discard = getDiscard(args); - config->dwoDir = args.getLastArgValue(OPT_plugin_opt_dwo_dir_eq); - config->dynamicLinker = getDynamicLinker(args); - config->ehFrameHdr = - args.hasFlag(OPT_eh_frame_hdr, OPT_no_eh_frame_hdr, false); - config->emitLLVM = args.hasArg(OPT_plugin_opt_emit_llvm, false); - config->emitRelocs = args.hasArg(OPT_emit_relocs); - config->callGraphProfileSort = args.hasFlag( + hasZOption(Args, "muldefs"); + Config->AllowShlibUndefined = + Args.hasFlag(OPT_allow_shlib_undefined, OPT_no_allow_shlib_undefined, + Args.hasArg(OPT_shared)); + Config->AuxiliaryList = args::getStrings(Args, OPT_auxiliary); + Config->Bsymbolic = Args.hasArg(OPT_Bsymbolic); + Config->BsymbolicFunctions = Args.hasArg(OPT_Bsymbolic_functions); + Config->CheckSections = + Args.hasFlag(OPT_check_sections, OPT_no_check_sections, true); + Config->Chroot = Args.getLastArgValue(OPT_chroot); + Config->CompressDebugSections = getCompressDebugSections(Args); + Config->Cref = Args.hasFlag(OPT_cref, OPT_no_cref, false); + Config->DefineCommon = Args.hasFlag(OPT_define_common, OPT_no_define_common, + !Args.hasArg(OPT_relocatable)); + Config->Demangle = Args.hasFlag(OPT_demangle, OPT_no_demangle, true); + Config->DependentLibraries = Args.hasFlag(OPT_dependent_libraries, OPT_no_dependent_libraries, true); + Config->DisableVerify = Args.hasArg(OPT_disable_verify); + Config->Discard = getDiscard(Args); + Config->DwoDir = Args.getLastArgValue(OPT_plugin_opt_dwo_dir_eq); + Config->DynamicLinker = getDynamicLinker(Args); + Config->EhFrameHdr = + Args.hasFlag(OPT_eh_frame_hdr, OPT_no_eh_frame_hdr, false); + Config->EmitLLVM = Args.hasArg(OPT_plugin_opt_emit_llvm, false); + Config->EmitRelocs = Args.hasArg(OPT_emit_relocs); + Config->CallGraphProfileSort = Args.hasFlag( OPT_call_graph_profile_sort, OPT_no_call_graph_profile_sort, true); - config->enableNewDtags = - args.hasFlag(OPT_enable_new_dtags, OPT_disable_new_dtags, true); - config->entry = args.getLastArgValue(OPT_entry); - config->executeOnly = - args.hasFlag(OPT_execute_only, OPT_no_execute_only, false); - config->exportDynamic = - args.hasFlag(OPT_export_dynamic, OPT_no_export_dynamic, false); - config->filterList = args::getStrings(args, OPT_filter); - config->fini = args.getLastArgValue(OPT_fini, "_fini"); - config->fixCortexA53Errata843419 = args.hasArg(OPT_fix_cortex_a53_843419); - config->forceBTI = args.hasArg(OPT_force_bti); - config->requireCET = args.hasArg(OPT_require_cet); - config->gcSections = args.hasFlag(OPT_gc_sections, OPT_no_gc_sections, false); - config->gnuUnique = args.hasFlag(OPT_gnu_unique, OPT_no_gnu_unique, true); - config->gdbIndex = args.hasFlag(OPT_gdb_index, OPT_no_gdb_index, false); - config->icf = getICF(args); - config->ignoreDataAddressEquality = - args.hasArg(OPT_ignore_data_address_equality); - config->ignoreFunctionAddressEquality = - args.hasArg(OPT_ignore_function_address_equality); - config->init = args.getLastArgValue(OPT_init, "_init"); - config->ltoAAPipeline = args.getLastArgValue(OPT_lto_aa_pipeline); - config->ltoCSProfileGenerate = args.hasArg(OPT_lto_cs_profile_generate); - config->ltoCSProfileFile = args.getLastArgValue(OPT_lto_cs_profile_file); - config->ltoDebugPassManager = args.hasArg(OPT_lto_debug_pass_manager); - config->ltoNewPassManager = args.hasArg(OPT_lto_new_pass_manager); - config->ltoNewPmPasses = args.getLastArgValue(OPT_lto_newpm_passes); - config->ltoo = args::getInteger(args, OPT_lto_O, 2); - config->ltoObjPath = args.getLastArgValue(OPT_plugin_opt_obj_path_eq); - config->ltoPartitions = args::getInteger(args, OPT_lto_partitions, 1); - config->ltoSampleProfile = args.getLastArgValue(OPT_lto_sample_profile); - config->mapFile = args.getLastArgValue(OPT_Map); - config->mipsGotSize = args::getInteger(args, OPT_mips_got_size, 0xfff0); - config->mergeArmExidx = - args.hasFlag(OPT_merge_exidx_entries, OPT_no_merge_exidx_entries, true); - config->nmagic = args.hasFlag(OPT_nmagic, OPT_no_nmagic, false); - config->noinhibitExec = args.hasArg(OPT_noinhibit_exec); - config->nostdlib = args.hasArg(OPT_nostdlib); - config->oFormatBinary = isOutputFormatBinary(args); - config->omagic = args.hasFlag(OPT_omagic, OPT_no_omagic, false); - config->optRemarksFilename = args.getLastArgValue(OPT_opt_remarks_filename); - config->optRemarksPasses = args.getLastArgValue(OPT_opt_remarks_passes); - config->optRemarksWithHotness = args.hasArg(OPT_opt_remarks_with_hotness); - config->optRemarksFormat = args.getLastArgValue(OPT_opt_remarks_format); - config->optimize = args::getInteger(args, OPT_O, 1); - config->orphanHandling = getOrphanHandling(args); - config->outputFile = args.getLastArgValue(OPT_o); - config->pacPlt = args.hasArg(OPT_pac_plt); - config->pie = args.hasFlag(OPT_pie, OPT_no_pie, false); - config->printIcfSections = - args.hasFlag(OPT_print_icf_sections, OPT_no_print_icf_sections, false); - config->printGcSections = - args.hasFlag(OPT_print_gc_sections, OPT_no_print_gc_sections, false); - config->printSymbolOrder = - args.getLastArgValue(OPT_print_symbol_order); - config->rpath = getRpath(args); - config->relocatable = args.hasArg(OPT_relocatable); - config->saveTemps = args.hasArg(OPT_save_temps); - config->searchPaths = args::getStrings(args, OPT_library_path); - config->sectionStartMap = getSectionStartMap(args); - config->shared = args.hasArg(OPT_shared); - config->singleRoRx = args.hasArg(OPT_no_rosegment); - config->soName = args.getLastArgValue(OPT_soname); - config->sortSection = getSortSection(args); - config->splitStackAdjustSize = args::getInteger(args, OPT_split_stack_adjust_size, 16384); - config->strip = getStrip(args); - config->sysroot = args.getLastArgValue(OPT_sysroot); - config->target1Rel = args.hasFlag(OPT_target1_rel, OPT_target1_abs, false); - config->target2 = getTarget2(args); - config->thinLTOCacheDir = args.getLastArgValue(OPT_thinlto_cache_dir); - config->thinLTOCachePolicy = CHECK( - parseCachePruningPolicy(args.getLastArgValue(OPT_thinlto_cache_policy)), + Config->EnableNewDtags = + Args.hasFlag(OPT_enable_new_dtags, OPT_disable_new_dtags, true); + Config->Entry = Args.getLastArgValue(OPT_entry); + Config->ExecuteOnly = + Args.hasFlag(OPT_execute_only, OPT_no_execute_only, false); + Config->ExportDynamic = + Args.hasFlag(OPT_export_dynamic, OPT_no_export_dynamic, false); + Config->FilterList = args::getStrings(Args, OPT_filter); + Config->Fini = Args.getLastArgValue(OPT_fini, "_fini"); + Config->FixCortexA53Errata843419 = Args.hasArg(OPT_fix_cortex_a53_843419); + Config->ForceBTI = Args.hasArg(OPT_force_bti); + Config->RequireCET = Args.hasArg(OPT_require_cet); + Config->GcSections = Args.hasFlag(OPT_gc_sections, OPT_no_gc_sections, false); + Config->GnuUnique = Args.hasFlag(OPT_gnu_unique, OPT_no_gnu_unique, true); + Config->GdbIndex = Args.hasFlag(OPT_gdb_index, OPT_no_gdb_index, false); + Config->ICF = getICF(Args); + Config->IgnoreDataAddressEquality = + Args.hasArg(OPT_ignore_data_address_equality); + Config->IgnoreFunctionAddressEquality = + Args.hasArg(OPT_ignore_function_address_equality); + Config->Init = Args.getLastArgValue(OPT_init, "_init"); + Config->LTOAAPipeline = Args.getLastArgValue(OPT_lto_aa_pipeline); + Config->LTOCSProfileGenerate = Args.hasArg(OPT_lto_cs_profile_generate); + Config->LTOCSProfileFile = Args.getLastArgValue(OPT_lto_cs_profile_file); + Config->LTODebugPassManager = Args.hasArg(OPT_lto_debug_pass_manager); + Config->LTONewPassManager = Args.hasArg(OPT_lto_new_pass_manager); + Config->LTONewPmPasses = Args.getLastArgValue(OPT_lto_newpm_passes); + Config->LTOO = args::getInteger(Args, OPT_lto_O, 2); + Config->LTOObjPath = Args.getLastArgValue(OPT_plugin_opt_obj_path_eq); + Config->LTOPartitions = args::getInteger(Args, OPT_lto_partitions, 1); + Config->LTOSampleProfile = Args.getLastArgValue(OPT_lto_sample_profile); + Config->MapFile = Args.getLastArgValue(OPT_Map); + Config->MipsGotSize = args::getInteger(Args, OPT_mips_got_size, 0xfff0); + Config->MergeArmExidx = + Args.hasFlag(OPT_merge_exidx_entries, OPT_no_merge_exidx_entries, true); + Config->Nmagic = Args.hasFlag(OPT_nmagic, OPT_no_nmagic, false); + Config->NoinhibitExec = Args.hasArg(OPT_noinhibit_exec); + Config->Nostdlib = Args.hasArg(OPT_nostdlib); + Config->OFormatBinary = isOutputFormatBinary(Args); + Config->Omagic = Args.hasFlag(OPT_omagic, OPT_no_omagic, false); + Config->OptRemarksFilename = Args.getLastArgValue(OPT_opt_remarks_filename); + Config->OptRemarksPasses = Args.getLastArgValue(OPT_opt_remarks_passes); + Config->OptRemarksWithHotness = Args.hasArg(OPT_opt_remarks_with_hotness); + Config->OptRemarksFormat = Args.getLastArgValue(OPT_opt_remarks_format); + Config->Optimize = args::getInteger(Args, OPT_O, 1); + Config->OrphanHandling = getOrphanHandling(Args); + Config->OutputFile = Args.getLastArgValue(OPT_o); + Config->PacPlt = Args.hasArg(OPT_pac_plt); + Config->Pie = Args.hasFlag(OPT_pie, OPT_no_pie, false); + Config->PrintIcfSections = + Args.hasFlag(OPT_print_icf_sections, OPT_no_print_icf_sections, false); + Config->PrintGcSections = + Args.hasFlag(OPT_print_gc_sections, OPT_no_print_gc_sections, false); + Config->PrintSymbolOrder = + Args.getLastArgValue(OPT_print_symbol_order); + Config->Rpath = getRpath(Args); + Config->Relocatable = Args.hasArg(OPT_relocatable); + Config->SaveTemps = Args.hasArg(OPT_save_temps); + Config->SearchPaths = args::getStrings(Args, OPT_library_path); + Config->SectionStartMap = getSectionStartMap(Args); + Config->Shared = Args.hasArg(OPT_shared); + Config->SingleRoRx = Args.hasArg(OPT_no_rosegment); + Config->SoName = Args.getLastArgValue(OPT_soname); + Config->SortSection = getSortSection(Args); + Config->SplitStackAdjustSize = args::getInteger(Args, OPT_split_stack_adjust_size, 16384); + Config->Strip = getStrip(Args); + Config->Sysroot = Args.getLastArgValue(OPT_sysroot); + Config->Target1Rel = Args.hasFlag(OPT_target1_rel, OPT_target1_abs, false); + Config->Target2 = getTarget2(Args); + Config->ThinLTOCacheDir = Args.getLastArgValue(OPT_thinlto_cache_dir); + Config->ThinLTOCachePolicy = CHECK( + parseCachePruningPolicy(Args.getLastArgValue(OPT_thinlto_cache_policy)), "--thinlto-cache-policy: invalid cache policy"); - config->thinLTOEmitImportsFiles = - args.hasArg(OPT_plugin_opt_thinlto_emit_imports_files); - config->thinLTOIndexOnly = args.hasArg(OPT_plugin_opt_thinlto_index_only) || - args.hasArg(OPT_plugin_opt_thinlto_index_only_eq); - config->thinLTOIndexOnlyArg = - args.getLastArgValue(OPT_plugin_opt_thinlto_index_only_eq); - config->thinLTOJobs = args::getInteger(args, OPT_thinlto_jobs, -1u); - config->thinLTOObjectSuffixReplace = - getOldNewOptions(args, OPT_plugin_opt_thinlto_object_suffix_replace_eq); - config->thinLTOPrefixReplace = - getOldNewOptions(args, OPT_plugin_opt_thinlto_prefix_replace_eq); - config->trace = args.hasArg(OPT_trace); - config->undefined = args::getStrings(args, OPT_undefined); - config->undefinedVersion = - args.hasFlag(OPT_undefined_version, OPT_no_undefined_version, true); - config->useAndroidRelrTags = args.hasFlag( + Config->ThinLTOEmitImportsFiles = + Args.hasArg(OPT_plugin_opt_thinlto_emit_imports_files); + Config->ThinLTOIndexOnly = Args.hasArg(OPT_plugin_opt_thinlto_index_only) || + Args.hasArg(OPT_plugin_opt_thinlto_index_only_eq); + Config->ThinLTOIndexOnlyArg = + Args.getLastArgValue(OPT_plugin_opt_thinlto_index_only_eq); + Config->ThinLTOJobs = args::getInteger(Args, OPT_thinlto_jobs, -1u); + Config->ThinLTOObjectSuffixReplace = + getOldNewOptions(Args, OPT_plugin_opt_thinlto_object_suffix_replace_eq); + Config->ThinLTOPrefixReplace = + getOldNewOptions(Args, OPT_plugin_opt_thinlto_prefix_replace_eq); + Config->Trace = Args.hasArg(OPT_trace); + Config->Undefined = args::getStrings(Args, OPT_undefined); + Config->UndefinedVersion = + Args.hasFlag(OPT_undefined_version, OPT_no_undefined_version, true); + Config->UseAndroidRelrTags = Args.hasFlag( OPT_use_android_relr_tags, OPT_no_use_android_relr_tags, false); - config->unresolvedSymbols = getUnresolvedSymbolPolicy(args); - config->warnBackrefs = - args.hasFlag(OPT_warn_backrefs, OPT_no_warn_backrefs, false); - config->warnCommon = args.hasFlag(OPT_warn_common, OPT_no_warn_common, false); - config->warnIfuncTextrel = - args.hasFlag(OPT_warn_ifunc_textrel, OPT_no_warn_ifunc_textrel, false); - config->warnSymbolOrdering = - args.hasFlag(OPT_warn_symbol_ordering, OPT_no_warn_symbol_ordering, true); - config->zCombreloc = getZFlag(args, "combreloc", "nocombreloc", true); - config->zCopyreloc = getZFlag(args, "copyreloc", "nocopyreloc", true); - config->zExecstack = getZFlag(args, "execstack", "noexecstack", false); - config->zGlobal = hasZOption(args, "global"); - config->zHazardplt = hasZOption(args, "hazardplt"); - config->zIfuncNoplt = hasZOption(args, "ifunc-noplt"); - config->zInitfirst = hasZOption(args, "initfirst"); - config->zInterpose = hasZOption(args, "interpose"); - config->zKeepTextSectionPrefix = getZFlag( - args, "keep-text-section-prefix", "nokeep-text-section-prefix", false); - config->zNodefaultlib = hasZOption(args, "nodefaultlib"); - config->zNodelete = hasZOption(args, "nodelete"); - config->zNodlopen = hasZOption(args, "nodlopen"); - config->zNow = getZFlag(args, "now", "lazy", false); - config->zOrigin = hasZOption(args, "origin"); - config->zRelro = getZFlag(args, "relro", "norelro", true); - config->zRetpolineplt = hasZOption(args, "retpolineplt"); - config->zRodynamic = hasZOption(args, "rodynamic"); - config->zSeparateCode = getZFlag(args, "separate-code", "noseparate-code", false); - config->zStackSize = args::getZOptionValue(args, OPT_z, "stack-size", 0); - config->zText = getZFlag(args, "text", "notext", true); - config->zWxneeded = hasZOption(args, "wxneeded"); + Config->UnresolvedSymbols = getUnresolvedSymbolPolicy(Args); + Config->WarnBackrefs = + Args.hasFlag(OPT_warn_backrefs, OPT_no_warn_backrefs, false); + Config->WarnCommon = Args.hasFlag(OPT_warn_common, OPT_no_warn_common, false); + Config->WarnIfuncTextrel = + Args.hasFlag(OPT_warn_ifunc_textrel, OPT_no_warn_ifunc_textrel, false); + Config->WarnSymbolOrdering = + Args.hasFlag(OPT_warn_symbol_ordering, OPT_no_warn_symbol_ordering, true); + Config->ZCombreloc = getZFlag(Args, "combreloc", "nocombreloc", true); + Config->ZCopyreloc = getZFlag(Args, "copyreloc", "nocopyreloc", true); + Config->ZExecstack = getZFlag(Args, "execstack", "noexecstack", false); + Config->ZGlobal = hasZOption(Args, "global"); + Config->ZHazardplt = hasZOption(Args, "hazardplt"); + Config->ZIfuncNoplt = hasZOption(Args, "ifunc-noplt"); + Config->ZInitfirst = hasZOption(Args, "initfirst"); + Config->ZInterpose = hasZOption(Args, "interpose"); + Config->ZKeepTextSectionPrefix = getZFlag( + Args, "keep-text-section-prefix", "nokeep-text-section-prefix", false); + Config->ZNodefaultlib = hasZOption(Args, "nodefaultlib"); + Config->ZNodelete = hasZOption(Args, "nodelete"); + Config->ZNodlopen = hasZOption(Args, "nodlopen"); + Config->ZNow = getZFlag(Args, "now", "lazy", false); + Config->ZOrigin = hasZOption(Args, "origin"); + Config->ZRelro = getZFlag(Args, "relro", "norelro", true); + Config->ZRetpolineplt = hasZOption(Args, "retpolineplt"); + Config->ZRodynamic = hasZOption(Args, "rodynamic"); + Config->ZStackSize = args::getZOptionValue(Args, OPT_z, "stack-size", 0); + Config->ZText = getZFlag(Args, "text", "notext", true); + Config->ZWxneeded = hasZOption(Args, "wxneeded"); // Parse LTO options. - if (auto *arg = args.getLastArg(OPT_plugin_opt_mcpu_eq)) - parseClangOption(saver.save("-mcpu=" + StringRef(arg->getValue())), - arg->getSpelling()); + if (auto *Arg = Args.getLastArg(OPT_plugin_opt_mcpu_eq)) + parseClangOption(Saver.save("-mcpu=" + StringRef(Arg->getValue())), + Arg->getSpelling()); - for (auto *arg : args.filtered(OPT_plugin_opt)) - parseClangOption(arg->getValue(), arg->getSpelling()); + for (auto *Arg : Args.filtered(OPT_plugin_opt)) + parseClangOption(Arg->getValue(), Arg->getSpelling()); // Parse -mllvm options. - for (auto *arg : args.filtered(OPT_mllvm)) - parseClangOption(arg->getValue(), arg->getSpelling()); + for (auto *Arg : Args.filtered(OPT_mllvm)) + parseClangOption(Arg->getValue(), Arg->getSpelling()); - if (config->ltoo > 3) - error("invalid optimization level for LTO: " + Twine(config->ltoo)); - if (config->ltoPartitions == 0) + if (Config->LTOO > 3) + error("invalid optimization level for LTO: " + Twine(Config->LTOO)); + if (Config->LTOPartitions == 0) error("--lto-partitions: number of threads must be > 0"); - if (config->thinLTOJobs == 0) + if (Config->ThinLTOJobs == 0) error("--thinlto-jobs: number of threads must be > 0"); - if (config->splitStackAdjustSize < 0) + if (Config->SplitStackAdjustSize < 0) error("--split-stack-adjust-size: size must be >= 0"); // Parse ELF{32,64}{LE,BE} and CPU type. - if (auto *arg = args.getLastArg(OPT_m)) { - StringRef s = arg->getValue(); - std::tie(config->ekind, config->emachine, config->osabi) = - parseEmulation(s); - config->mipsN32Abi = (s == "elf32btsmipn32" || s == "elf32ltsmipn32"); - config->emulation = s; + if (auto *Arg = Args.getLastArg(OPT_m)) { + StringRef S = Arg->getValue(); + std::tie(Config->EKind, Config->EMachine, Config->OSABI) = + parseEmulation(S); + Config->MipsN32Abi = (S == "elf32btsmipn32" || S == "elf32ltsmipn32"); + Config->Emulation = S; } // Parse -hash-style={sysv,gnu,both}. - if (auto *arg = args.getLastArg(OPT_hash_style)) { - StringRef s = arg->getValue(); - if (s == "sysv") - config->sysvHash = true; - else if (s == "gnu") - config->gnuHash = true; - else if (s == "both") - config->sysvHash = config->gnuHash = true; + if (auto *Arg = Args.getLastArg(OPT_hash_style)) { + StringRef S = Arg->getValue(); + if (S == "sysv") + Config->SysvHash = true; + else if (S == "gnu") + Config->GnuHash = true; + else if (S == "both") + Config->SysvHash = Config->GnuHash = true; else - error("unknown -hash-style: " + s); + error("unknown -hash-style: " + S); } - if (args.hasArg(OPT_print_map)) - config->mapFile = "-"; + if (Args.hasArg(OPT_print_map)) + Config->MapFile = "-"; // Page alignment can be disabled by the -n (--nmagic) and -N (--omagic). // As PT_GNU_RELRO relies on Paging, do not create it when we have disabled // it. - if (config->nmagic || config->omagic) - config->zRelro = false; + if (Config->Nmagic || Config->Omagic) + Config->ZRelro = false; - std::tie(config->buildId, config->buildIdVector) = getBuildId(args); + std::tie(Config->BuildId, Config->BuildIdVector) = getBuildId(Args); - std::tie(config->androidPackDynRelocs, config->relrPackDynRelocs) = - getPackDynRelocs(args); + std::tie(Config->AndroidPackDynRelocs, Config->RelrPackDynRelocs) = + getPackDynRelocs(Args); - if (auto *arg = args.getLastArg(OPT_symbol_ordering_file)){ - if (args.hasArg(OPT_call_graph_ordering_file)) + if (auto *Arg = Args.getLastArg(OPT_symbol_ordering_file)){ + if (Args.hasArg(OPT_call_graph_ordering_file)) error("--symbol-ordering-file and --call-graph-order-file " "may not be used together"); - if (Optional buffer = readFile(arg->getValue())){ - config->symbolOrderingFile = getSymbolOrderingFile(*buffer); + if (Optional Buffer = readFile(Arg->getValue())){ + Config->SymbolOrderingFile = getSymbolOrderingFile(*Buffer); // Also need to disable CallGraphProfileSort to prevent // LLD order symbols with CGProfile - config->callGraphProfileSort = false; + Config->CallGraphProfileSort = false; } } - assert(config->versionDefinitions.empty()); - config->versionDefinitions.push_back({"local", (uint16_t)VER_NDX_LOCAL, {}}); - config->versionDefinitions.push_back( - {"global", (uint16_t)VER_NDX_GLOBAL, {}}); - // If --retain-symbol-file is used, we'll keep only the symbols listed in // the file and discard all others. - if (auto *arg = args.getLastArg(OPT_retain_symbols_file)) { - config->versionDefinitions[VER_NDX_LOCAL].patterns.push_back( - {"*", /*isExternCpp=*/false, /*hasWildcard=*/true}); - if (Optional buffer = readFile(arg->getValue())) - for (StringRef s : args::getLines(*buffer)) - config->versionDefinitions[VER_NDX_GLOBAL].patterns.push_back( - {s, /*isExternCpp=*/false, /*hasWildcard=*/false}); + if (auto *Arg = Args.getLastArg(OPT_retain_symbols_file)) { + Config->DefaultSymbolVersion = VER_NDX_LOCAL; + if (Optional Buffer = readFile(Arg->getValue())) + for (StringRef S : args::getLines(*Buffer)) + Config->VersionScriptGlobals.push_back( + {S, /*IsExternCpp*/ false, /*HasWildcard*/ false}); } + bool HasExportDynamic = + Args.hasFlag(OPT_export_dynamic, OPT_no_export_dynamic, false); + // Parses -dynamic-list and -export-dynamic-symbol. They make some // symbols private. Note that -export-dynamic takes precedence over them // as it says all symbols should be exported. - if (!config->exportDynamic) { - for (auto *arg : args.filtered(OPT_dynamic_list)) - if (Optional buffer = readFile(arg->getValue())) - readDynamicList(*buffer); - - for (auto *arg : args.filtered(OPT_export_dynamic_symbol)) - config->dynamicList.push_back( - {arg->getValue(), /*isExternCpp=*/false, /*hasWildcard=*/false}); + if (!HasExportDynamic) { + for (auto *Arg : Args.filtered(OPT_dynamic_list)) + if (Optional Buffer = readFile(Arg->getValue())) + readDynamicList(*Buffer); + + for (auto *Arg : Args.filtered(OPT_export_dynamic_symbol)) + Config->DynamicList.push_back( + {Arg->getValue(), /*IsExternCpp*/ false, /*HasWildcard*/ false}); } // If --export-dynamic-symbol=foo is given and symbol foo is defined in // an object file in an archive file, that object file should be pulled // out and linked. (It doesn't have to behave like that from technical // point of view, but this is needed for compatibility with GNU.) - for (auto *arg : args.filtered(OPT_export_dynamic_symbol)) - config->undefined.push_back(arg->getValue()); + for (auto *Arg : Args.filtered(OPT_export_dynamic_symbol)) + Config->Undefined.push_back(Arg->getValue()); - for (auto *arg : args.filtered(OPT_version_script)) - if (Optional path = searchScript(arg->getValue())) { - if (Optional buffer = readFile(*path)) - readVersionScript(*buffer); + for (auto *Arg : Args.filtered(OPT_version_script)) + if (Optional Path = searchScript(Arg->getValue())) { + if (Optional Buffer = readFile(*Path)) + readVersionScript(*Buffer); } else { - error(Twine("cannot find version script ") + arg->getValue()); + error(Twine("cannot find version script ") + Arg->getValue()); } } @@ -1063,18 +1050,18 @@ static void readConfigs(opt::InputArgList &args) { // command line options, but computed based on other Config values. // This function initialize such members. See Config.h for the details // of these values. -static void setConfigs(opt::InputArgList &args) { - ELFKind k = config->ekind; - uint16_t m = config->emachine; - - config->copyRelocs = (config->relocatable || config->emitRelocs); - config->is64 = (k == ELF64LEKind || k == ELF64BEKind); - config->isLE = (k == ELF32LEKind || k == ELF64LEKind); - config->endianness = config->isLE ? endianness::little : endianness::big; - config->isMips64EL = (k == ELF64LEKind && m == EM_MIPS); - config->isPic = config->pie || config->shared; - config->picThunk = args.hasArg(OPT_pic_veneer, config->isPic); - config->wordsize = config->is64 ? 8 : 4; +static void setConfigs(opt::InputArgList &Args) { + ELFKind K = Config->EKind; + uint16_t M = Config->EMachine; + + Config->CopyRelocs = (Config->Relocatable || Config->EmitRelocs); + Config->Is64 = (K == ELF64LEKind || K == ELF64BEKind); + Config->IsLE = (K == ELF32LEKind || K == ELF64LEKind); + Config->Endianness = Config->IsLE ? endianness::little : endianness::big; + Config->IsMips64EL = (K == ELF64LEKind && M == EM_MIPS); + Config->Pic = Config->Pie || Config->Shared; + Config->PicThunk = Args.hasArg(OPT_pic_veneer, Config->Pic); + Config->Wordsize = Config->Is64 ? 8 : 4; // ELF defines two different ways to store relocation addends as shown below: // @@ -1089,150 +1076,150 @@ static void setConfigs(opt::InputArgList &args) { // You cannot choose which one, Rel or Rela, you want to use. Instead each // ABI defines which one you need to use. The following expression expresses // that. - config->isRela = m == EM_AARCH64 || m == EM_AMDGPU || m == EM_HEXAGON || - m == EM_PPC || m == EM_PPC64 || m == EM_RISCV || - m == EM_X86_64; + Config->IsRela = M == EM_AARCH64 || M == EM_AMDGPU || M == EM_HEXAGON || + M == EM_PPC || M == EM_PPC64 || M == EM_RISCV || + M == EM_X86_64; // If the output uses REL relocations we must store the dynamic relocation // addends to the output sections. We also store addends for RELA relocations // if --apply-dynamic-relocs is used. // We default to not writing the addends when using RELA relocations since // any standard conforming tool can find it in r_addend. - config->writeAddends = args.hasFlag(OPT_apply_dynamic_relocs, + Config->WriteAddends = Args.hasFlag(OPT_apply_dynamic_relocs, OPT_no_apply_dynamic_relocs, false) || - !config->isRela; + !Config->IsRela; - config->tocOptimize = - args.hasFlag(OPT_toc_optimize, OPT_no_toc_optimize, m == EM_PPC64); + Config->TocOptimize = + Args.hasFlag(OPT_toc_optimize, OPT_no_toc_optimize, M == EM_PPC64); } // Returns a value of "-format" option. -static bool isFormatBinary(StringRef s) { - if (s == "binary") +static bool isFormatBinary(StringRef S) { + if (S == "binary") return true; - if (s == "elf" || s == "default") + if (S == "elf" || S == "default") return false; - error("unknown -format value: " + s + + error("unknown -format value: " + S + " (supported formats: elf, default, binary)"); return false; } -void LinkerDriver::createFiles(opt::InputArgList &args) { +void LinkerDriver::createFiles(opt::InputArgList &Args) { // For --{push,pop}-state. - std::vector> stack; + std::vector> Stack; // Iterate over argv to process input files and positional arguments. - for (auto *arg : args) { - switch (arg->getOption().getID()) { + for (auto *Arg : Args) { + switch (Arg->getOption().getUnaliasedOption().getID()) { case OPT_library: - addLibrary(arg->getValue()); + addLibrary(Arg->getValue()); break; case OPT_INPUT: - addFile(arg->getValue(), /*withLOption=*/false); + addFile(Arg->getValue(), /*WithLOption=*/false); break; case OPT_defsym: { - StringRef from; - StringRef to; - std::tie(from, to) = StringRef(arg->getValue()).split('='); - if (from.empty() || to.empty()) - error("-defsym: syntax error: " + StringRef(arg->getValue())); + StringRef From; + StringRef To; + std::tie(From, To) = StringRef(Arg->getValue()).split('='); + if (From.empty() || To.empty()) + error("-defsym: syntax error: " + StringRef(Arg->getValue())); else - readDefsym(from, MemoryBufferRef(to, "-defsym")); + readDefsym(From, MemoryBufferRef(To, "-defsym")); break; } case OPT_script: - if (Optional path = searchScript(arg->getValue())) { - if (Optional mb = readFile(*path)) - readLinkerScript(*mb); + if (Optional Path = searchScript(Arg->getValue())) { + if (Optional MB = readFile(*Path)) + readLinkerScript(*MB); break; } - error(Twine("cannot find linker script ") + arg->getValue()); + error(Twine("cannot find linker script ") + Arg->getValue()); break; case OPT_as_needed: - config->asNeeded = true; + Config->AsNeeded = true; break; case OPT_format: - config->formatBinary = isFormatBinary(arg->getValue()); + Config->FormatBinary = isFormatBinary(Arg->getValue()); break; case OPT_no_as_needed: - config->asNeeded = false; + Config->AsNeeded = false; break; case OPT_Bstatic: case OPT_omagic: case OPT_nmagic: - config->isStatic = true; + Config->Static = true; break; case OPT_Bdynamic: - config->isStatic = false; + Config->Static = false; break; case OPT_whole_archive: - inWholeArchive = true; + InWholeArchive = true; break; case OPT_no_whole_archive: - inWholeArchive = false; + InWholeArchive = false; break; case OPT_just_symbols: - if (Optional mb = readFile(arg->getValue())) { - files.push_back(createObjectFile(*mb)); - files.back()->justSymbols = true; + if (Optional MB = readFile(Arg->getValue())) { + Files.push_back(createObjectFile(*MB)); + Files.back()->JustSymbols = true; } break; case OPT_start_group: - if (InputFile::isInGroup) + if (InputFile::IsInGroup) error("nested --start-group"); - InputFile::isInGroup = true; + InputFile::IsInGroup = true; break; case OPT_end_group: - if (!InputFile::isInGroup) + if (!InputFile::IsInGroup) error("stray --end-group"); - InputFile::isInGroup = false; - ++InputFile::nextGroupId; + InputFile::IsInGroup = false; + ++InputFile::NextGroupId; break; case OPT_start_lib: - if (inLib) + if (InLib) error("nested --start-lib"); - if (InputFile::isInGroup) + if (InputFile::IsInGroup) error("may not nest --start-lib in --start-group"); - inLib = true; - InputFile::isInGroup = true; + InLib = true; + InputFile::IsInGroup = true; break; case OPT_end_lib: - if (!inLib) + if (!InLib) error("stray --end-lib"); - inLib = false; - InputFile::isInGroup = false; - ++InputFile::nextGroupId; + InLib = false; + InputFile::IsInGroup = false; + ++InputFile::NextGroupId; break; case OPT_push_state: - stack.emplace_back(config->asNeeded, config->isStatic, inWholeArchive); + Stack.emplace_back(Config->AsNeeded, Config->Static, InWholeArchive); break; case OPT_pop_state: - if (stack.empty()) { + if (Stack.empty()) { error("unbalanced --push-state/--pop-state"); break; } - std::tie(config->asNeeded, config->isStatic, inWholeArchive) = stack.back(); - stack.pop_back(); + std::tie(Config->AsNeeded, Config->Static, InWholeArchive) = Stack.back(); + Stack.pop_back(); break; } } - if (files.empty() && errorCount() == 0) + if (Files.empty() && errorCount() == 0) error("no input files"); } // If -m was not given, infer it from object files. void LinkerDriver::inferMachineType() { - if (config->ekind != ELFNoneKind) + if (Config->EKind != ELFNoneKind) return; - for (InputFile *f : files) { - if (f->ekind == ELFNoneKind) + for (InputFile *F : Files) { + if (F->EKind == ELFNoneKind) continue; - config->ekind = f->ekind; - config->emachine = f->emachine; - config->osabi = f->osabi; - config->mipsN32Abi = config->emachine == EM_MIPS && isMipsN32Abi(f); + Config->EKind = F->EKind; + Config->EMachine = F->EMachine; + Config->OSABI = F->OSABI; + Config->MipsN32Abi = Config->EMachine == EM_MIPS && isMipsN32Abi(F); return; } error("target emulation unknown: -m or at least one .o file required"); @@ -1240,72 +1227,72 @@ void LinkerDriver::inferMachineType() { // Parse -z max-page-size=. The default value is defined by // each target. -static uint64_t getMaxPageSize(opt::InputArgList &args) { - uint64_t val = args::getZOptionValue(args, OPT_z, "max-page-size", - target->defaultMaxPageSize); - if (!isPowerOf2_64(val)) +static uint64_t getMaxPageSize(opt::InputArgList &Args) { + uint64_t Val = args::getZOptionValue(Args, OPT_z, "max-page-size", + Target->DefaultMaxPageSize); + if (!isPowerOf2_64(Val)) error("max-page-size: value isn't a power of 2"); - if (config->nmagic || config->omagic) { - if (val != target->defaultMaxPageSize) + if (Config->Nmagic || Config->Omagic) { + if (Val != Target->DefaultMaxPageSize) warn("-z max-page-size set, but paging disabled by omagic or nmagic"); return 1; } - return val; + return Val; } // Parse -z common-page-size=. The default value is defined by // each target. -static uint64_t getCommonPageSize(opt::InputArgList &args) { - uint64_t val = args::getZOptionValue(args, OPT_z, "common-page-size", - target->defaultCommonPageSize); - if (!isPowerOf2_64(val)) +static uint64_t getCommonPageSize(opt::InputArgList &Args) { + uint64_t Val = args::getZOptionValue(Args, OPT_z, "common-page-size", + Target->DefaultCommonPageSize); + if (!isPowerOf2_64(Val)) error("common-page-size: value isn't a power of 2"); - if (config->nmagic || config->omagic) { - if (val != target->defaultCommonPageSize) + if (Config->Nmagic || Config->Omagic) { + if (Val != Target->DefaultCommonPageSize) warn("-z common-page-size set, but paging disabled by omagic or nmagic"); return 1; } - // commonPageSize can't be larger than maxPageSize. - if (val > config->maxPageSize) - val = config->maxPageSize; - return val; + // CommonPageSize can't be larger than MaxPageSize. + if (Val > Config->MaxPageSize) + Val = Config->MaxPageSize; + return Val; } // Parses -image-base option. -static Optional getImageBase(opt::InputArgList &args) { - // Because we are using "Config->maxPageSize" here, this function has to be +static Optional getImageBase(opt::InputArgList &Args) { + // Because we are using "Config->MaxPageSize" here, this function has to be // called after the variable is initialized. - auto *arg = args.getLastArg(OPT_image_base); - if (!arg) + auto *Arg = Args.getLastArg(OPT_image_base); + if (!Arg) return None; - StringRef s = arg->getValue(); - uint64_t v; - if (!to_integer(s, v)) { - error("-image-base: number expected, but got " + s); + StringRef S = Arg->getValue(); + uint64_t V; + if (!to_integer(S, V)) { + error("-image-base: number expected, but got " + S); return 0; } - if ((v % config->maxPageSize) != 0) - warn("-image-base: address isn't multiple of page size: " + s); - return v; + if ((V % Config->MaxPageSize) != 0) + warn("-image-base: address isn't multiple of page size: " + S); + return V; } // Parses `--exclude-libs=lib,lib,...`. // The library names may be delimited by commas or colons. -static DenseSet getExcludeLibs(opt::InputArgList &args) { - DenseSet ret; - for (auto *arg : args.filtered(OPT_exclude_libs)) { - StringRef s = arg->getValue(); +static DenseSet getExcludeLibs(opt::InputArgList &Args) { + DenseSet Ret; + for (auto *Arg : Args.filtered(OPT_exclude_libs)) { + StringRef S = Arg->getValue(); for (;;) { - size_t pos = s.find_first_of(",:"); - if (pos == StringRef::npos) + size_t Pos = S.find_first_of(",:"); + if (Pos == StringRef::npos) break; - ret.insert(s.substr(0, pos)); - s = s.substr(pos + 1); + Ret.insert(S.substr(0, Pos)); + S = S.substr(Pos + 1); } - ret.insert(s); + Ret.insert(S); } - return ret; + return Ret; } // Handles the -exclude-libs option. If a static library file is specified @@ -1314,71 +1301,71 @@ static DenseSet getExcludeLibs(opt::InputArgList &args) { // A special library name "ALL" means all archive files. // // This is not a popular option, but some programs such as bionic libc use it. -static void excludeLibs(opt::InputArgList &args) { - DenseSet libs = getExcludeLibs(args); - bool all = libs.count("ALL"); - - auto visit = [&](InputFile *file) { - if (!file->archiveName.empty()) - if (all || libs.count(path::filename(file->archiveName))) - for (Symbol *sym : file->getSymbols()) - if (!sym->isLocal() && sym->file == file) - sym->versionId = VER_NDX_LOCAL; +static void excludeLibs(opt::InputArgList &Args) { + DenseSet Libs = getExcludeLibs(Args); + bool All = Libs.count("ALL"); + + auto Visit = [&](InputFile *File) { + if (!File->ArchiveName.empty()) + if (All || Libs.count(path::filename(File->ArchiveName))) + for (Symbol *Sym : File->getSymbols()) + if (!Sym->isLocal() && Sym->File == File) + Sym->VersionId = VER_NDX_LOCAL; }; - for (InputFile *file : objectFiles) - visit(file); + for (InputFile *File : ObjectFiles) + Visit(File); - for (BitcodeFile *file : bitcodeFiles) - visit(file); + for (BitcodeFile *File : BitcodeFiles) + Visit(File); } // Force Sym to be entered in the output. Used for -u or equivalent. -static void handleUndefined(Symbol *sym) { +static void handleUndefined(Symbol *Sym) { // Since a symbol may not be used inside the program, LTO may // eliminate it. Mark the symbol as "used" to prevent it. - sym->isUsedInRegularObj = true; + Sym->IsUsedInRegularObj = true; - if (sym->isLazy()) - sym->fetch(); + if (Sym->isLazy()) + Sym->fetch(); } // As an extention to GNU linkers, lld supports a variant of `-u` // which accepts wildcard patterns. All symbols that match a given // pattern are handled as if they were given by `-u`. -static void handleUndefinedGlob(StringRef arg) { - Expected pat = GlobPattern::create(arg); - if (!pat) { - error("--undefined-glob: " + toString(pat.takeError())); +static void handleUndefinedGlob(StringRef Arg) { + Expected Pat = GlobPattern::create(Arg); + if (!Pat) { + error("--undefined-glob: " + toString(Pat.takeError())); return; } - std::vector syms; - symtab->forEachSymbol([&](Symbol *sym) { + std::vector Syms; + Symtab->forEachSymbol([&](Symbol *Sym) { // Calling Sym->fetch() from here is not safe because it may // add new symbols to the symbol table, invalidating the // current iterator. So we just keep a note. - if (pat->match(sym->getName())) - syms.push_back(sym); + if (Pat->match(Sym->getName())) + Syms.push_back(Sym); }); - for (Symbol *sym : syms) - handleUndefined(sym); + for (Symbol *Sym : Syms) + handleUndefined(Sym); } -static void handleLibcall(StringRef name) { - Symbol *sym = symtab->find(name); - if (!sym || !sym->isLazy()) +static void handleLibcall(StringRef Name) { + Symbol *Sym = Symtab->find(Name); + if (!Sym || !Sym->isLazy()) return; - MemoryBufferRef mb; - if (auto *lo = dyn_cast(sym)) - mb = lo->file->mb; + MemoryBufferRef MB; + if (auto *LO = dyn_cast(Sym)) + MB = LO->File->MB; else - mb = cast(sym)->getMemberBuffer(); + MB = cast(Sym)->getMemberBuffer(); - if (isBitcode(mb)) - sym->fetch(); + if (isBitcode(MB)) + Sym->fetch(); } // Replaces common symbols with defined symbols reside in .bss sections. @@ -1386,17 +1373,17 @@ static void handleLibcall(StringRef name) { // result, the passes after the symbol resolution won't see any // symbols of type CommonSymbol. static void replaceCommonSymbols() { - symtab->forEachSymbol([](Symbol *sym) { - auto *s = dyn_cast(sym); - if (!s) + Symtab->forEachSymbol([](Symbol *Sym) { + auto *S = dyn_cast(Sym); + if (!S) return; - auto *bss = make("COMMON", s->size, s->alignment); - bss->file = s->file; - bss->markDead(); - inputSections.push_back(bss); - s->replace(Defined{s->file, s->getName(), s->binding, s->stOther, s->type, - /*value=*/0, s->size, bss}); + auto *Bss = make("COMMON", S->Size, S->Alignment); + Bss->File = S->File; + Bss->markDead(); + InputSections.push_back(Bss); + S->replace(Defined{S->File, S->getName(), S->Binding, S->StOther, S->Type, + /*Value=*/0, S->Size, Bss}); }); } @@ -1405,78 +1392,78 @@ static void replaceCommonSymbols() { // created from the DSO. Otherwise, they become dangling references // that point to a non-existent DSO. static void demoteSharedSymbols() { - symtab->forEachSymbol([](Symbol *sym) { - auto *s = dyn_cast(sym); - if (!s || s->getFile().isNeeded) + Symtab->forEachSymbol([](Symbol *Sym) { + auto *S = dyn_cast(Sym); + if (!S || S->getFile().IsNeeded) return; - bool used = s->used; - s->replace(Undefined{nullptr, s->getName(), STB_WEAK, s->stOther, s->type}); - s->used = used; + bool Used = S->Used; + S->replace(Undefined{nullptr, S->getName(), STB_WEAK, S->StOther, S->Type}); + S->Used = Used; }); } -// The section referred to by `s` is considered address-significant. Set the -// keepUnique flag on the section if appropriate. -static void markAddrsig(Symbol *s) { - if (auto *d = dyn_cast_or_null(s)) - if (d->section) +// The section referred to by S is considered address-significant. Set the +// KeepUnique flag on the section if appropriate. +static void markAddrsig(Symbol *S) { + if (auto *D = dyn_cast_or_null(S)) + if (D->Section) // We don't need to keep text sections unique under --icf=all even if they // are address-significant. - if (config->icf == ICFLevel::Safe || !(d->section->flags & SHF_EXECINSTR)) - d->section->keepUnique = true; + if (Config->ICF == ICFLevel::Safe || !(D->Section->Flags & SHF_EXECINSTR)) + D->Section->KeepUnique = true; } // Record sections that define symbols mentioned in --keep-unique // and symbols referred to by address-significance tables. These sections are // ineligible for ICF. template -static void findKeepUniqueSections(opt::InputArgList &args) { - for (auto *arg : args.filtered(OPT_keep_unique)) { - StringRef name = arg->getValue(); - auto *d = dyn_cast_or_null(symtab->find(name)); - if (!d || !d->section) { - warn("could not find symbol " + name + " to keep unique"); +static void findKeepUniqueSections(opt::InputArgList &Args) { + for (auto *Arg : Args.filtered(OPT_keep_unique)) { + StringRef Name = Arg->getValue(); + auto *D = dyn_cast_or_null(Symtab->find(Name)); + if (!D || !D->Section) { + warn("could not find symbol " + Name + " to keep unique"); continue; } - d->section->keepUnique = true; + D->Section->KeepUnique = true; } // --icf=all --ignore-data-address-equality means that we can ignore // the dynsym and address-significance tables entirely. - if (config->icf == ICFLevel::All && config->ignoreDataAddressEquality) + if (Config->ICF == ICFLevel::All && Config->IgnoreDataAddressEquality) return; // Symbols in the dynsym could be address-significant in other executables // or DSOs, so we conservatively mark them as address-significant. - symtab->forEachSymbol([&](Symbol *sym) { - if (sym->includeInDynsym()) - markAddrsig(sym); + Symtab->forEachSymbol([&](Symbol *Sym) { + if (Sym->includeInDynsym()) + markAddrsig(Sym); }); // Visit the address-significance table in each object file and mark each // referenced symbol as address-significant. - for (InputFile *f : objectFiles) { - auto *obj = cast>(f); - ArrayRef syms = obj->getSymbols(); - if (obj->addrsigSec) { - ArrayRef contents = - check(obj->getObj().getSectionContents(obj->addrsigSec)); - const uint8_t *cur = contents.begin(); - while (cur != contents.end()) { - unsigned size; - const char *err; - uint64_t symIndex = decodeULEB128(cur, &size, contents.end(), &err); - if (err) - fatal(toString(f) + ": could not decode addrsig section: " + err); - markAddrsig(syms[symIndex]); - cur += size; + for (InputFile *F : ObjectFiles) { + auto *Obj = cast>(F); + ArrayRef Syms = Obj->getSymbols(); + if (Obj->AddrsigSec) { + ArrayRef Contents = + check(Obj->getObj().getSectionContents(Obj->AddrsigSec)); + const uint8_t *Cur = Contents.begin(); + while (Cur != Contents.end()) { + unsigned Size; + const char *Err; + uint64_t SymIndex = decodeULEB128(Cur, &Size, Contents.end(), &Err); + if (Err) + fatal(toString(F) + ": could not decode addrsig section: " + Err); + markAddrsig(Syms[SymIndex]); + Cur += Size; } } else { // If an object file does not have an address-significance table, // conservatively mark all of its symbols as address-significant. - for (Symbol *s : syms) - markAddrsig(s); + for (Symbol *S : Syms) + markAddrsig(S); } } } @@ -1485,20 +1472,20 @@ static void findKeepUniqueSections(opt::InputArgList &args) { // are used to control which partition a symbol is allocated to. See // https://lld.llvm.org/Partitions.html for more details on partitions. template -static void readSymbolPartitionSection(InputSectionBase *s) { +static void readSymbolPartitionSection(InputSectionBase *S) { // Read the relocation that refers to the partition's entry point symbol. - Symbol *sym; - if (s->areRelocsRela) - sym = &s->getFile()->getRelocTargetSym(s->template relas()[0]); + Symbol *Sym; + if (S->AreRelocsRela) + Sym = &S->getFile()->getRelocTargetSym(S->template relas()[0]); else - sym = &s->getFile()->getRelocTargetSym(s->template rels()[0]); - if (!isa(sym) || !sym->includeInDynsym()) + Sym = &S->getFile()->getRelocTargetSym(S->template rels()[0]); + if (!isa(Sym) || !Sym->includeInDynsym()) return; - StringRef partName = reinterpret_cast(s->data().data()); - for (Partition &part : partitions) { - if (part.name == partName) { - sym->partition = part.getNumber(); + StringRef PartName = reinterpret_cast(S->data().data()); + for (Partition &Part : Partitions) { + if (Part.Name == PartName) { + Sym->Partition = Part.getNumber(); return; } } @@ -1506,33 +1493,33 @@ static void readSymbolPartitionSection(InputSectionBase *s) { // Forbid partitions from being used on incompatible targets, and forbid them // from being used together with various linker features that assume a single // set of output sections. - if (script->hasSectionsCommand) - error(toString(s->file) + + if (Script->HasSectionsCommand) + error(toString(S->File) + ": partitions cannot be used with the SECTIONS command"); - if (script->hasPhdrsCommands()) - error(toString(s->file) + + if (Script->hasPhdrsCommands()) + error(toString(S->File) + ": partitions cannot be used with the PHDRS command"); - if (!config->sectionStartMap.empty()) - error(toString(s->file) + ": partitions cannot be used with " + if (!Config->SectionStartMap.empty()) + error(toString(S->File) + ": partitions cannot be used with " "--section-start, -Ttext, -Tdata or -Tbss"); - if (config->emachine == EM_MIPS) - error(toString(s->file) + ": partitions cannot be used on this target"); + if (Config->EMachine == EM_MIPS) + error(toString(S->File) + ": partitions cannot be used on this target"); // Impose a limit of no more than 254 partitions. This limit comes from the // sizes of the Partition fields in InputSectionBase and Symbol, as well as // the amount of space devoted to the partition number in RankFlags. - if (partitions.size() == 254) + if (Partitions.size() == 254) fatal("may not have more than 254 partitions"); - partitions.emplace_back(); - Partition &newPart = partitions.back(); - newPart.name = partName; - sym->partition = newPart.getNumber(); + Partitions.emplace_back(); + Partition &NewPart = Partitions.back(); + NewPart.Name = PartName; + Sym->Partition = NewPart.getNumber(); } -static Symbol *addUndefined(StringRef name) { - return symtab->addSymbol( - Undefined{nullptr, name, STB_GLOBAL, STV_DEFAULT, 0}); +static Symbol *addUndefined(StringRef Name) { + return Symtab->addSymbol( + Undefined{nullptr, Name, STB_GLOBAL, STV_DEFAULT, 0}); } // This function is where all the optimizations of link-time @@ -1544,16 +1531,16 @@ static Symbol *addUndefined(StringRef name) { // the compiler at once, it can do a whole-program optimization. template void LinkerDriver::compileBitcodeFiles() { // Compile bitcode files and replace bitcode symbols. - lto.reset(new BitcodeCompiler); - for (BitcodeFile *file : bitcodeFiles) - lto->add(*file); - - for (InputFile *file : lto->compile()) { - auto *obj = cast>(file); - obj->parse(/*ignoreComdats=*/true); - for (Symbol *sym : obj->getGlobalSymbols()) - sym->parseSymbolVersion(); - objectFiles.push_back(file); + LTO.reset(new BitcodeCompiler); + for (BitcodeFile *File : BitcodeFiles) + LTO->add(*File); + + for (InputFile *File : LTO->compile()) { + auto *Obj = cast>(File); + Obj->parse(/*IgnoreComdats=*/true); + for (Symbol *Sym : Obj->getGlobalSymbols()) + Sym->parseSymbolVersion(); + ObjectFiles.push_back(File); } } @@ -1566,9 +1553,9 @@ template void LinkerDriver::compileBitcodeFiles() { // // This data structure is instantiated for each -wrap option. struct WrappedSymbol { - Symbol *sym; - Symbol *real; - Symbol *wrap; + Symbol *Sym; + Symbol *Real; + Symbol *Wrap; }; // Handles -wrap option. @@ -1576,33 +1563,33 @@ struct WrappedSymbol { // This function instantiates wrapper symbols. At this point, they seem // like they are not being used at all, so we explicitly set some flags so // that LTO won't eliminate them. -static std::vector addWrappedSymbols(opt::InputArgList &args) { - std::vector v; - DenseSet seen; +static std::vector addWrappedSymbols(opt::InputArgList &Args) { + std::vector V; + DenseSet Seen; - for (auto *arg : args.filtered(OPT_wrap)) { - StringRef name = arg->getValue(); - if (!seen.insert(name).second) + for (auto *Arg : Args.filtered(OPT_wrap)) { + StringRef Name = Arg->getValue(); + if (!Seen.insert(Name).second) continue; - Symbol *sym = symtab->find(name); - if (!sym) + Symbol *Sym = Symtab->find(Name); + if (!Sym) continue; - Symbol *real = addUndefined(saver.save("__real_" + name)); - Symbol *wrap = addUndefined(saver.save("__wrap_" + name)); - v.push_back({sym, real, wrap}); + Symbol *Real = addUndefined(Saver.save("__real_" + Name)); + Symbol *Wrap = addUndefined(Saver.save("__wrap_" + Name)); + V.push_back({Sym, Real, Wrap}); // We want to tell LTO not to inline symbols to be overwritten // because LTO doesn't know the final symbol contents after renaming. - real->canInline = false; - sym->canInline = false; + Real->CanInline = false; + Sym->CanInline = false; // Tell LTO not to eliminate these symbols. - sym->isUsedInRegularObj = true; - wrap->isUsedInRegularObj = true; + Sym->IsUsedInRegularObj = true; + Wrap->IsUsedInRegularObj = true; } - return v; + return V; } // Do renaming for -wrap by updating pointers to symbols. @@ -1610,24 +1597,24 @@ static std::vector addWrappedSymbols(opt::InputArgList &args) { // When this function is executed, only InputFiles and symbol table // contain pointers to symbol objects. We visit them to replace pointers, // so that wrapped symbols are swapped as instructed by the command line. -static void wrapSymbols(ArrayRef wrapped) { - DenseMap map; - for (const WrappedSymbol &w : wrapped) { - map[w.sym] = w.wrap; - map[w.real] = w.sym; +static void wrapSymbols(ArrayRef Wrapped) { + DenseMap Map; + for (const WrappedSymbol &W : Wrapped) { + Map[W.Sym] = W.Wrap; + Map[W.Real] = W.Sym; } // Update pointers in input files. - parallelForEach(objectFiles, [&](InputFile *file) { - MutableArrayRef syms = file->getMutableSymbols(); - for (size_t i = 0, e = syms.size(); i != e; ++i) - if (Symbol *s = map.lookup(syms[i])) - syms[i] = s; + parallelForEach(ObjectFiles, [&](InputFile *File) { + MutableArrayRef Syms = File->getMutableSymbols(); + for (size_t I = 0, E = Syms.size(); I != E; ++I) + if (Symbol *S = Map.lookup(Syms[I])) + Syms[I] = S; }); // Update pointers in the symbol table. - for (const WrappedSymbol &w : wrapped) - symtab->wrap(w.sym, w.real, w.wrap); + for (const WrappedSymbol &W : Wrapped) + Symtab->wrap(W.Sym, W.Real, W.Wrap); } // To enable CET (x86's hardware-assited control flow enforcement), each @@ -1643,30 +1630,30 @@ static void wrapSymbols(ArrayRef wrapped) { // Note that the CET-aware PLT is not implemented yet. We do error // check only. template static uint32_t getAndFeatures() { - if (config->emachine != EM_386 && config->emachine != EM_X86_64 && - config->emachine != EM_AARCH64) + if (Config->EMachine != EM_386 && Config->EMachine != EM_X86_64 && + Config->EMachine != EM_AARCH64) return 0; - uint32_t ret = -1; - for (InputFile *f : objectFiles) { - uint32_t features = cast>(f)->andFeatures; - if (config->forceBTI && !(features & GNU_PROPERTY_AARCH64_FEATURE_1_BTI)) { - warn(toString(f) + ": --force-bti: file does not have BTI property"); - features |= GNU_PROPERTY_AARCH64_FEATURE_1_BTI; - } else if (!features && config->requireCET) - error(toString(f) + ": --require-cet: file is not compatible with CET"); - ret &= features; + uint32_t Ret = -1; + for (InputFile *F : ObjectFiles) { + uint32_t Features = cast>(F)->AndFeatures; + if (Config->ForceBTI && !(Features & GNU_PROPERTY_AARCH64_FEATURE_1_BTI)) { + warn(toString(F) + ": --force-bti: file does not have BTI property"); + Features |= GNU_PROPERTY_AARCH64_FEATURE_1_BTI; + } else if (!Features && Config->RequireCET) + error(toString(F) + ": --require-cet: file is not compatible with CET"); + Ret &= Features; } // Force enable pointer authentication Plt, we don't warn in this case as // this does not require support in the object for correctness. - if (config->pacPlt) - ret |= GNU_PROPERTY_AARCH64_FEATURE_1_PAC; + if (Config->PacPlt) + Ret |= GNU_PROPERTY_AARCH64_FEATURE_1_PAC; - return ret; + return Ret; } -static const char *libcallRoutineNames[] = { +static const char *LibcallRoutineNames[] = { #define HANDLE_LIBCALL(code, name) name, #include "llvm/IR/RuntimeLibcalls.def" #undef HANDLE_LIBCALL @@ -1674,48 +1661,48 @@ static const char *libcallRoutineNames[] = { // Do actual linking. Note that when this function is called, // all linker scripts have already been parsed. -template void LinkerDriver::link(opt::InputArgList &args) { +template void LinkerDriver::link(opt::InputArgList &Args) { // If a -hash-style option was not given, set to a default value, // which varies depending on the target. - if (!args.hasArg(OPT_hash_style)) { - if (config->emachine == EM_MIPS) - config->sysvHash = true; + if (!Args.hasArg(OPT_hash_style)) { + if (Config->EMachine == EM_MIPS) + Config->SysvHash = true; else - config->sysvHash = config->gnuHash = true; + Config->SysvHash = Config->GnuHash = true; } // Default output filename is "a.out" by the Unix tradition. - if (config->outputFile.empty()) - config->outputFile = "a.out"; + if (Config->OutputFile.empty()) + Config->OutputFile = "a.out"; // Fail early if the output file or map file is not writable. If a user has a // long link, e.g. due to a large LTO link, they do not wish to run it and // find that it failed because there was a mistake in their command-line. - if (auto e = tryCreateFile(config->outputFile)) - error("cannot open output file " + config->outputFile + ": " + e.message()); - if (auto e = tryCreateFile(config->mapFile)) - error("cannot open map file " + config->mapFile + ": " + e.message()); + if (auto E = tryCreateFile(Config->OutputFile)) + error("cannot open output file " + Config->OutputFile + ": " + E.message()); + if (auto E = tryCreateFile(Config->MapFile)) + error("cannot open map file " + Config->MapFile + ": " + E.message()); if (errorCount()) return; // Use default entry point name if no name was given via the command // line nor linker scripts. For some reason, MIPS entry point name is // different from others. - config->warnMissingEntry = - (!config->entry.empty() || (!config->shared && !config->relocatable)); - if (config->entry.empty() && !config->relocatable) - config->entry = (config->emachine == EM_MIPS) ? "__start" : "_start"; + Config->WarnMissingEntry = + (!Config->Entry.empty() || (!Config->Shared && !Config->Relocatable)); + if (Config->Entry.empty() && !Config->Relocatable) + Config->Entry = (Config->EMachine == EM_MIPS) ? "__start" : "_start"; // Handle --trace-symbol. - for (auto *arg : args.filtered(OPT_trace_symbol)) - symtab->insert(arg->getValue())->traced = true; + for (auto *Arg : Args.filtered(OPT_trace_symbol)) + Symtab->insert(Arg->getValue())->Traced = true; // Add all files to the symbol table. This will add almost all // symbols that we need to the symbol table. This process might // add files to the link, via autolinking, these files are always // appended to the Files vector. - for (size_t i = 0; i < files.size(); ++i) - parseFile(files[i]); + for (size_t I = 0; I < Files.size(); ++I) + parseFile(Files[I]); // Now that we have every file, we can decide if we will need a // dynamic symbol table. @@ -1723,26 +1710,26 @@ template void LinkerDriver::link(opt::InputArgList &args) { // producing a shared library. // We also need one if any shared libraries are used and for pie executables // (probably because the dynamic linker needs it). - config->hasDynSymTab = - !sharedFiles.empty() || config->isPic || config->exportDynamic; + Config->HasDynSymTab = + !SharedFiles.empty() || Config->Pic || Config->ExportDynamic; // Some symbols (such as __ehdr_start) are defined lazily only when there // are undefined symbols for them, so we add these to trigger that logic. - for (StringRef name : script->referencedSymbols) - addUndefined(name); + for (StringRef Name : Script->ReferencedSymbols) + addUndefined(Name); // Handle the `--undefined ` options. - for (StringRef arg : config->undefined) - if (Symbol *sym = symtab->find(arg)) - handleUndefined(sym); + for (StringRef Arg : Config->Undefined) + if (Symbol *Sym = Symtab->find(Arg)) + handleUndefined(Sym); // If an entry symbol is in a static archive, pull out that file now. - if (Symbol *sym = symtab->find(config->entry)) - handleUndefined(sym); + if (Symbol *Sym = Symtab->find(Config->Entry)) + handleUndefined(Sym); // Handle the `--undefined-glob ` options. - for (StringRef pat : args::getStrings(args, OPT_undefined_glob)) - handleUndefinedGlob(pat); + for (StringRef Pat : args::getStrings(Args, OPT_undefined_glob)) + handleUndefinedGlob(Pat); // If any of our inputs are bitcode files, the LTO code generator may create // references to certain library functions that might not be explicit in the @@ -1761,9 +1748,9 @@ template void LinkerDriver::link(opt::InputArgList &args) { // to, i.e. if the symbol's definition is in bitcode. Any other required // libcall symbols will be added to the link after LTO when we add the LTO // object file to the link. - if (!bitcodeFiles.empty()) - for (const char *s : libcallRoutineNames) - handleLibcall(s); + if (!BitcodeFiles.empty()) + for (const char *S : LibcallRoutineNames) + handleLibcall(S); // Return if there were name resolution errors. if (errorCount()) @@ -1771,27 +1758,27 @@ template void LinkerDriver::link(opt::InputArgList &args) { // Now when we read all script files, we want to finalize order of linker // script commands, which can be not yet final because of INSERT commands. - script->processInsertCommands(); + Script->processInsertCommands(); // We want to declare linker script's symbols early, // so that we can version them. // They also might be exported if referenced by DSOs. - script->declareSymbols(); + Script->declareSymbols(); // Handle the -exclude-libs option. - if (args.hasArg(OPT_exclude_libs)) - excludeLibs(args); + if (Args.hasArg(OPT_exclude_libs)) + excludeLibs(Args); - // Create elfHeader early. We need a dummy section in + // Create ElfHeader early. We need a dummy section in // addReservedSymbols to mark the created symbols as not absolute. - Out::elfHeader = make("", 0, SHF_ALLOC); - Out::elfHeader->size = sizeof(typename ELFT::Ehdr); + Out::ElfHeader = make("", 0, SHF_ALLOC); + Out::ElfHeader->Size = sizeof(typename ELFT::Ehdr); // Create wrapped symbols for -wrap option. - std::vector wrapped = addWrappedSymbols(args); + std::vector Wrapped = addWrappedSymbols(Args); // We need to create some reserved symbols such as _end. Create them. - if (!config->relocatable) + if (!Config->Relocatable) addReservedSymbols(); // Apply version scripts. @@ -1799,8 +1786,8 @@ template void LinkerDriver::link(opt::InputArgList &args) { // For a relocatable output, version scripts don't make sense, and // parsing a symbol version string (e.g. dropping "@ver1" from a symbol // name "foo@ver1") rather do harm, so we don't call this if -r is given. - if (!config->relocatable) - symtab->scanVersionScript(); + if (!Config->Relocatable) + Symtab->scanVersionScript(); // Do link-time optimization if given files are LLVM bitcode files. // This compiles bitcode files into real object files. @@ -1814,83 +1801,83 @@ template void LinkerDriver::link(opt::InputArgList &args) { // If -thinlto-index-only is given, we should create only "index // files" and not object files. Index file creation is already done // in addCombinedLTOObject, so we are done if that's the case. - if (config->thinLTOIndexOnly) + if (Config->ThinLTOIndexOnly) return; // Likewise, --plugin-opt=emit-llvm is an option to make LTO create // an output file in bitcode and exit, so that you can just get a // combined bitcode file. - if (config->emitLLVM) + if (Config->EmitLLVM) return; // Apply symbol renames for -wrap. - if (!wrapped.empty()) - wrapSymbols(wrapped); + if (!Wrapped.empty()) + wrapSymbols(Wrapped); // Now that we have a complete list of input files. // Beyond this point, no new files are added. // Aggregate all input sections into one place. - for (InputFile *f : objectFiles) - for (InputSectionBase *s : f->getSections()) - if (s && s != &InputSection::discarded) - inputSections.push_back(s); - for (BinaryFile *f : binaryFiles) - for (InputSectionBase *s : f->getSections()) - inputSections.push_back(cast(s)); - - llvm::erase_if(inputSections, [](InputSectionBase *s) { - if (s->type == SHT_LLVM_SYMPART) { - readSymbolPartitionSection(s); + for (InputFile *F : ObjectFiles) + for (InputSectionBase *S : F->getSections()) + if (S && S != &InputSection::Discarded) + InputSections.push_back(S); + for (BinaryFile *F : BinaryFiles) + for (InputSectionBase *S : F->getSections()) + InputSections.push_back(cast(S)); + + llvm::erase_if(InputSections, [](InputSectionBase *S) { + if (S->Type == SHT_LLVM_SYMPART) { + readSymbolPartitionSection(S); return true; } // We do not want to emit debug sections if --strip-all // or -strip-debug are given. - return config->strip != StripPolicy::None && - (s->name.startswith(".debug") || s->name.startswith(".zdebug")); + return Config->Strip != StripPolicy::None && + (S->Name.startswith(".debug") || S->Name.startswith(".zdebug")); }); // Now that the number of partitions is fixed, save a pointer to the main // partition. - mainPart = &partitions[0]; + Main = &Partitions[0]; // Read .note.gnu.property sections from input object files which // contain a hint to tweak linker's and loader's behaviors. - config->andFeatures = getAndFeatures(); + Config->AndFeatures = getAndFeatures(); // The Target instance handles target-specific stuff, such as applying // relocations or writing a PLT section. It also contains target-dependent // values such as a default image base address. - target = getTarget(); + Target = getTarget(); - config->eflags = target->calcEFlags(); - // maxPageSize (sometimes called abi page size) is the maximum page size that + Config->EFlags = Target->calcEFlags(); + // MaxPageSize (sometimes called abi page size) is the maximum page size that // the output can be run on. For example if the OS can use 4k or 64k page - // sizes then maxPageSize must be 64k for the output to be useable on both. + // sizes then MaxPageSize must be 64 for the output to be useable on both. // All important alignment decisions must use this value. - config->maxPageSize = getMaxPageSize(args); - // commonPageSize is the most common page size that the output will be run on. + Config->MaxPageSize = getMaxPageSize(Args); + // CommonPageSize is the most common page size that the output will be run on. // For example if an OS can use 4k or 64k page sizes and 4k is more common - // than 64k then commonPageSize is set to 4k. commonPageSize can be used for + // than 64k then CommonPageSize is set to 4k. CommonPageSize can be used for // optimizations such as DATA_SEGMENT_ALIGN in linker scripts. LLD's use of it // is limited to writing trap instructions on the last executable segment. - config->commonPageSize = getCommonPageSize(args); + Config->CommonPageSize = getCommonPageSize(Args); - config->imageBase = getImageBase(args); + Config->ImageBase = getImageBase(Args); - if (config->emachine == EM_ARM) { + if (Config->EMachine == EM_ARM) { // FIXME: These warnings can be removed when lld only uses these features // when the input objects have been compiled with an architecture that // supports them. - if (config->armHasBlx == false) + if (Config->ARMHasBlx == false) warn("lld uses blx instruction, no object with architecture supporting " "feature detected"); } // This adds a .comment section containing a version string. We have to add it // before mergeSections because the .comment section is a mergeable section. - if (!config->relocatable) - inputSections.push_back(createCommentSection()); + if (!Config->Relocatable) + InputSections.push_back(createCommentSection()); // Replace common symbols with regular symbols. replaceCommonSymbols(); @@ -1901,36 +1888,16 @@ template void LinkerDriver::link(opt::InputArgList &args) { markLive(); demoteSharedSymbols(); mergeSections(); - - // Make copies of any input sections that need to be copied into each - // partition. - copySectionsIntoPartitions(); - - // Create synthesized sections such as .got and .plt. This is called before - // processSectionCommands() so that they can be placed by SECTIONS commands. - createSyntheticSections(); - - // Some input sections that are used for exception handling need to be moved - // into synthetic sections. Do that now so that they aren't assigned to - // output sections in the usual way. - if (!config->relocatable) - combineEhSections(); - - // Create output sections described by SECTIONS commands. - script->processSectionCommands(); - - // Two input sections with different output sections should not be folded. - // ICF runs after processSectionCommands() so that we know the output sections. - if (config->icf != ICFLevel::None) { - findKeepUniqueSections(args); + if (Config->ICF != ICFLevel::None) { + findKeepUniqueSections(Args); doIcf(); } // Read the callgraph now that we know what was gced or icfed - if (config->callGraphProfileSort) { - if (auto *arg = args.getLastArg(OPT_call_graph_ordering_file)) - if (Optional buffer = readFile(arg->getValue())) - readCallGraph(*buffer); + if (Config->CallGraphProfileSort) { + if (auto *Arg = Args.getLastArg(OPT_call_graph_ordering_file)) + if (Optional Buffer = readFile(Arg->getValue())) + readCallGraph(*Buffer); readCallGraphsFromObjectFiles(); } diff --git a/lld/ELF/Driver.h b/lld/ELF/Driver.h index 3115e28d16698b..76b91be2119515 100644 --- a/lld/ELF/Driver.h +++ b/lld/ELF/Driver.h @@ -22,37 +22,37 @@ namespace lld { namespace elf { -extern class LinkerDriver *driver; +extern class LinkerDriver *Driver; class LinkerDriver { public: - void main(ArrayRef args); - void addFile(StringRef path, bool withLOption); - void addLibrary(StringRef name); + void main(ArrayRef Args); + void addFile(StringRef Path, bool WithLOption); + void addLibrary(StringRef Name); private: - void createFiles(llvm::opt::InputArgList &args); + void createFiles(llvm::opt::InputArgList &Args); void inferMachineType(); - template void link(llvm::opt::InputArgList &args); + template void link(llvm::opt::InputArgList &Args); template void compileBitcodeFiles(); // True if we are in --whole-archive and --no-whole-archive. - bool inWholeArchive = false; + bool InWholeArchive = false; // True if we are in --start-lib and --end-lib. - bool inLib = false; + bool InLib = false; // For LTO. - std::unique_ptr lto; + std::unique_ptr LTO; - std::vector files; + std::vector Files; }; // Parses command line options. class ELFOptTable : public llvm::opt::OptTable { public: ELFOptTable(); - llvm::opt::InputArgList parse(ArrayRef argv); + llvm::opt::InputArgList parse(ArrayRef Argv); }; // Create enum with OPT_xxx values for each option in Options.td @@ -64,12 +64,12 @@ enum { }; void printHelp(); -std::string createResponseFile(const llvm::opt::InputArgList &args); +std::string createResponseFile(const llvm::opt::InputArgList &Args); -llvm::Optional findFromSearchPaths(StringRef path); -llvm::Optional searchScript(StringRef path); -llvm::Optional searchLibraryBaseName(StringRef path); -llvm::Optional searchLibrary(StringRef path); +llvm::Optional findFromSearchPaths(StringRef Path); +llvm::Optional searchScript(StringRef Path); +llvm::Optional searchLibraryBaseName(StringRef Path); +llvm::Optional searchLibrary(StringRef Path); } // namespace elf } // namespace lld diff --git a/lld/ELF/DriverUtils.cpp b/lld/ELF/DriverUtils.cpp index 5ed37e0171b87f..e6a482b4969ba3 100644 --- a/lld/ELF/DriverUtils.cpp +++ b/lld/ELF/DriverUtils.cpp @@ -41,7 +41,7 @@ using namespace lld::elf; #undef PREFIX // Create table mapping all options defined in Options.td -static const opt::OptTable::Info optInfo[] = { +static const opt::OptTable::Info OptInfo[] = { #define OPTION(X1, X2, ID, KIND, GROUP, ALIAS, X7, X8, X9, X10, X11, X12) \ {X1, X2, X10, X11, OPT_##ID, opt::Option::KIND##Class, \ X9, X8, OPT_##GROUP, OPT_##ALIAS, X7, X12}, @@ -49,36 +49,36 @@ static const opt::OptTable::Info optInfo[] = { #undef OPTION }; -ELFOptTable::ELFOptTable() : OptTable(optInfo) {} +ELFOptTable::ELFOptTable() : OptTable(OptInfo) {} // Set color diagnostics according to -color-diagnostics={auto,always,never} // or -no-color-diagnostics flags. -static void handleColorDiagnostics(opt::InputArgList &args) { - auto *arg = args.getLastArg(OPT_color_diagnostics, OPT_color_diagnostics_eq, +static void handleColorDiagnostics(opt::InputArgList &Args) { + auto *Arg = Args.getLastArg(OPT_color_diagnostics, OPT_color_diagnostics_eq, OPT_no_color_diagnostics); - if (!arg) + if (!Arg) return; - if (arg->getOption().getID() == OPT_color_diagnostics) { - enableColors(true); - } else if (arg->getOption().getID() == OPT_no_color_diagnostics) { - enableColors(false); + if (Arg->getOption().getID() == OPT_color_diagnostics) { + errorHandler().ColorDiagnostics = true; + } else if (Arg->getOption().getID() == OPT_no_color_diagnostics) { + errorHandler().ColorDiagnostics = false; } else { - StringRef s = arg->getValue(); - if (s == "always") - enableColors(true); - else if (s == "never") - enableColors(false); - else if (s != "auto") - error("unknown option: --color-diagnostics=" + s); + StringRef S = Arg->getValue(); + if (S == "always") + errorHandler().ColorDiagnostics = true; + else if (S == "never") + errorHandler().ColorDiagnostics = false; + else if (S != "auto") + error("unknown option: --color-diagnostics=" + S); } } -static cl::TokenizerCallback getQuotingStyle(opt::InputArgList &args) { - if (auto *arg = args.getLastArg(OPT_rsp_quoting)) { - StringRef s = arg->getValue(); - if (s != "windows" && s != "posix") - error("invalid response file quoting: " + s); - if (s == "windows") +static cl::TokenizerCallback getQuotingStyle(opt::InputArgList &Args) { + if (auto *Arg = Args.getLastArg(OPT_rsp_quoting)) { + StringRef S = Arg->getValue(); + if (S != "windows" && S != "posix") + error("invalid response file quoting: " + S); + if (S == "windows") return cl::TokenizeWindowsCommandLine; return cl::TokenizeGNUCommandLine; } @@ -96,56 +96,56 @@ static cl::TokenizerCallback getQuotingStyle(opt::InputArgList &args) { // `--plugin-opt ` is converted to `--plugin-opt=`. This is a // bit hacky, but looks like it is still better than handling --plugin-opt // options by hand. -static void concatLTOPluginOptions(SmallVectorImpl &args) { - SmallVector v; - for (size_t i = 0, e = args.size(); i != e; ++i) { - StringRef s = args[i]; - if ((s == "-plugin-opt" || s == "--plugin-opt") && i + 1 != e) { - v.push_back(saver.save(s + "=" + args[i + 1]).data()); - ++i; +static void concatLTOPluginOptions(SmallVectorImpl &Args) { + SmallVector V; + for (size_t I = 0, E = Args.size(); I != E; ++I) { + StringRef S = Args[I]; + if ((S == "-plugin-opt" || S == "--plugin-opt") && I + 1 != E) { + V.push_back(Saver.save(S + "=" + Args[I + 1]).data()); + ++I; } else { - v.push_back(args[i]); + V.push_back(Args[I]); } } - args = std::move(v); + Args = std::move(V); } // Parses a given list of options. -opt::InputArgList ELFOptTable::parse(ArrayRef argv) { +opt::InputArgList ELFOptTable::parse(ArrayRef Argv) { // Make InputArgList from string vectors. - unsigned missingIndex; - unsigned missingCount; - SmallVector vec(argv.data(), argv.data() + argv.size()); + unsigned MissingIndex; + unsigned MissingCount; + SmallVector Vec(Argv.data(), Argv.data() + Argv.size()); // We need to get the quoting style for response files before parsing all // options so we parse here before and ignore all the options but // --rsp-quoting. - opt::InputArgList args = this->ParseArgs(vec, missingIndex, missingCount); + opt::InputArgList Args = this->ParseArgs(Vec, MissingIndex, MissingCount); // Expand response files (arguments in the form of @) // and then parse the argument again. - cl::ExpandResponseFiles(saver, getQuotingStyle(args), vec); - concatLTOPluginOptions(vec); - args = this->ParseArgs(vec, missingIndex, missingCount); - - handleColorDiagnostics(args); - if (missingCount) - error(Twine(args.getArgString(missingIndex)) + ": missing argument"); - - for (auto *arg : args.filtered(OPT_UNKNOWN)) { - std::string nearest; - if (findNearest(arg->getAsString(args), nearest) > 1) - error("unknown argument '" + arg->getAsString(args) + "'"); + cl::ExpandResponseFiles(Saver, getQuotingStyle(Args), Vec); + concatLTOPluginOptions(Vec); + Args = this->ParseArgs(Vec, MissingIndex, MissingCount); + + handleColorDiagnostics(Args); + if (MissingCount) + error(Twine(Args.getArgString(MissingIndex)) + ": missing argument"); + + for (auto *Arg : Args.filtered(OPT_UNKNOWN)) { + std::string Nearest; + if (findNearest(Arg->getAsString(Args), Nearest) > 1) + error("unknown argument '" + Arg->getSpelling() + "'"); else - error("unknown argument '" + arg->getAsString(args) + - "', did you mean '" + nearest + "'"); + error("unknown argument '" + Arg->getSpelling() + "', did you mean '" + + Nearest + "'"); } - return args; + return Args; } void elf::printHelp() { ELFOptTable().PrintHelp( - outs(), (config->progName + " [options] file...").str().c_str(), "lld", + outs(), (Config->ProgName + " [options] file...").str().c_str(), "lld", false /*ShowHidden*/, true /*ShowAllAliases*/); outs() << "\n"; @@ -154,36 +154,36 @@ void elf::printHelp() { // in a message for the -help option. If it doesn't match, the scripts // assume that the linker doesn't support very basic features such as // shared libraries. Therefore, we need to print out at least "elf". - outs() << config->progName << ": supported targets: elf\n"; + outs() << Config->ProgName << ": supported targets: elf\n"; } -static std::string rewritePath(StringRef s) { - if (fs::exists(s)) - return relativeToRoot(s); - return s; +static std::string rewritePath(StringRef S) { + if (fs::exists(S)) + return relativeToRoot(S); + return S; } // Reconstructs command line arguments so that so that you can re-run // the same command with the same inputs. This is for --reproduce. -std::string elf::createResponseFile(const opt::InputArgList &args) { - SmallString<0> data; - raw_svector_ostream os(data); - os << "--chroot .\n"; +std::string elf::createResponseFile(const opt::InputArgList &Args) { + SmallString<0> Data; + raw_svector_ostream OS(Data); + OS << "--chroot .\n"; // Copy the command line to the output while rewriting paths. - for (auto *arg : args) { - switch (arg->getOption().getID()) { + for (auto *Arg : Args) { + switch (Arg->getOption().getUnaliasedOption().getID()) { case OPT_reproduce: break; case OPT_INPUT: - os << quote(rewritePath(arg->getValue())) << "\n"; + OS << quote(rewritePath(Arg->getValue())) << "\n"; break; case OPT_o: // If -o path contains directories, "lld @response.txt" will likely // fail because the archive we are creating doesn't contain empty // directories for the output path (-o doesn't create directories). // Strip directories to prevent the issue. - os << "-o " << quote(sys::path::filename(arg->getValue())) << "\n"; + OS << "-o " << quote(sys::path::filename(Arg->getValue())) << "\n"; break; case OPT_dynamic_list: case OPT_library_path: @@ -192,62 +192,62 @@ std::string elf::createResponseFile(const opt::InputArgList &args) { case OPT_symbol_ordering_file: case OPT_sysroot: case OPT_version_script: - os << arg->getSpelling() << " " << quote(rewritePath(arg->getValue())) + OS << Arg->getSpelling() << " " << quote(rewritePath(Arg->getValue())) << "\n"; break; default: - os << toString(*arg) << "\n"; + OS << toString(*Arg) << "\n"; } } - return data.str(); + return Data.str(); } // Find a file by concatenating given paths. If a resulting path // starts with "=", the character is replaced with a --sysroot value. -static Optional findFile(StringRef path1, const Twine &path2) { - SmallString<128> s; - if (path1.startswith("=")) - path::append(s, config->sysroot, path1.substr(1), path2); +static Optional findFile(StringRef Path1, const Twine &Path2) { + SmallString<128> S; + if (Path1.startswith("=")) + path::append(S, Config->Sysroot, Path1.substr(1), Path2); else - path::append(s, path1, path2); + path::append(S, Path1, Path2); - if (fs::exists(s)) - return s.str().str(); + if (fs::exists(S)) + return S.str().str(); return None; } -Optional elf::findFromSearchPaths(StringRef path) { - for (StringRef dir : config->searchPaths) - if (Optional s = findFile(dir, path)) - return s; +Optional elf::findFromSearchPaths(StringRef Path) { + for (StringRef Dir : Config->SearchPaths) + if (Optional S = findFile(Dir, Path)) + return S; return None; } // This is for -l. We'll look for lib.so or lib.a from // search paths. -Optional elf::searchLibraryBaseName(StringRef name) { - for (StringRef dir : config->searchPaths) { - if (!config->isStatic) - if (Optional s = findFile(dir, "lib" + name + ".so")) - return s; - if (Optional s = findFile(dir, "lib" + name + ".a")) - return s; +Optional elf::searchLibraryBaseName(StringRef Name) { + for (StringRef Dir : Config->SearchPaths) { + if (!Config->Static) + if (Optional S = findFile(Dir, "lib" + Name + ".so")) + return S; + if (Optional S = findFile(Dir, "lib" + Name + ".a")) + return S; } return None; } // This is for -l. -Optional elf::searchLibrary(StringRef name) { - if (name.startswith(":")) - return findFromSearchPaths(name.substr(1)); - return searchLibraryBaseName (name); +Optional elf::searchLibrary(StringRef Name) { + if (Name.startswith(":")) + return findFromSearchPaths(Name.substr(1)); + return searchLibraryBaseName (Name); } // If a linker/version script doesn't exist in the current directory, we also // look for the script in the '-L' search paths. This matches the behaviour of // '-T', --version-script=, and linker script INPUT() command in ld.bfd. -Optional elf::searchScript(StringRef name) { - if (fs::exists(name)) - return name.str(); - return findFromSearchPaths(name); +Optional elf::searchScript(StringRef Name) { + if (fs::exists(Name)) + return Name.str(); + return findFromSearchPaths(Name); } diff --git a/lld/ELF/EhFrame.cpp b/lld/ELF/EhFrame.cpp index b3245dd01669ef..236b895f61c165 100644 --- a/lld/ELF/EhFrame.cpp +++ b/lld/ELF/EhFrame.cpp @@ -36,72 +36,72 @@ using namespace lld::elf; namespace { class EhReader { public: - EhReader(InputSectionBase *s, ArrayRef d) : isec(s), d(d) {} + EhReader(InputSectionBase *S, ArrayRef D) : IS(S), D(D) {} size_t readEhRecordSize(); uint8_t getFdeEncoding(); private: - template void failOn(const P *loc, const Twine &msg) { - fatal("corrupted .eh_frame: " + msg + "\n>>> defined in " + - isec->getObjMsg((const uint8_t *)loc - isec->data().data())); + template void failOn(const P *Loc, const Twine &Msg) { + fatal("corrupted .eh_frame: " + Msg + "\n>>> defined in " + + IS->getObjMsg((const uint8_t *)Loc - IS->data().data())); } uint8_t readByte(); - void skipBytes(size_t count); + void skipBytes(size_t Count); StringRef readString(); void skipLeb128(); void skipAugP(); - InputSectionBase *isec; - ArrayRef d; + InputSectionBase *IS; + ArrayRef D; }; } -size_t elf::readEhRecordSize(InputSectionBase *s, size_t off) { - return EhReader(s, s->data().slice(off)).readEhRecordSize(); +size_t elf::readEhRecordSize(InputSectionBase *S, size_t Off) { + return EhReader(S, S->data().slice(Off)).readEhRecordSize(); } // .eh_frame section is a sequence of records. Each record starts with // a 4 byte length field. This function reads the length. size_t EhReader::readEhRecordSize() { - if (d.size() < 4) - failOn(d.data(), "CIE/FDE too small"); + if (D.size() < 4) + failOn(D.data(), "CIE/FDE too small"); // First 4 bytes of CIE/FDE is the size of the record. // If it is 0xFFFFFFFF, the next 8 bytes contain the size instead, // but we do not support that format yet. - uint64_t v = read32(d.data()); - if (v == UINT32_MAX) - failOn(d.data(), "CIE/FDE too large"); - uint64_t size = v + 4; - if (size > d.size()) - failOn(d.data(), "CIE/FDE ends past the end of the section"); - return size; + uint64_t V = read32(D.data()); + if (V == UINT32_MAX) + failOn(D.data(), "CIE/FDE too large"); + uint64_t Size = V + 4; + if (Size > D.size()) + failOn(D.data(), "CIE/FDE ends past the end of the section"); + return Size; } // Read a byte and advance D by one byte. uint8_t EhReader::readByte() { - if (d.empty()) - failOn(d.data(), "unexpected end of CIE"); - uint8_t b = d.front(); - d = d.slice(1); - return b; + if (D.empty()) + failOn(D.data(), "unexpected end of CIE"); + uint8_t B = D.front(); + D = D.slice(1); + return B; } -void EhReader::skipBytes(size_t count) { - if (d.size() < count) - failOn(d.data(), "CIE is too small"); - d = d.slice(count); +void EhReader::skipBytes(size_t Count) { + if (D.size() < Count) + failOn(D.data(), "CIE is too small"); + D = D.slice(Count); } // Read a null-terminated string. StringRef EhReader::readString() { - const uint8_t *end = llvm::find(d, '\0'); - if (end == d.end()) - failOn(d.data(), "corrupted CIE (failed to read string)"); - StringRef s = toStringRef(d.slice(0, end - d.begin())); - d = d.slice(s.size() + 1); - return s; + const uint8_t *End = llvm::find(D, '\0'); + if (End == D.end()) + failOn(D.data(), "corrupted CIE (failed to read string)"); + StringRef S = toStringRef(D.slice(0, End - D.begin())); + D = D.slice(S.size() + 1); + return S; } // Skip an integer encoded in the LEB128 format. @@ -109,21 +109,21 @@ StringRef EhReader::readString() { // But we need to be at least able to skip it so that we can read // the field that follows a LEB128 number. void EhReader::skipLeb128() { - const uint8_t *errPos = d.data(); - while (!d.empty()) { - uint8_t val = d.front(); - d = d.slice(1); - if ((val & 0x80) == 0) + const uint8_t *ErrPos = D.data(); + while (!D.empty()) { + uint8_t Val = D.front(); + D = D.slice(1); + if ((Val & 0x80) == 0) return; } - failOn(errPos, "corrupted CIE (failed to read LEB128)"); + failOn(ErrPos, "corrupted CIE (failed to read LEB128)"); } -static size_t getAugPSize(unsigned enc) { - switch (enc & 0x0f) { +static size_t getAugPSize(unsigned Enc) { + switch (Enc & 0x0f) { case DW_EH_PE_absptr: case DW_EH_PE_signed: - return config->wordsize; + return Config->Wordsize; case DW_EH_PE_udata2: case DW_EH_PE_sdata2: return 2; @@ -138,29 +138,29 @@ static size_t getAugPSize(unsigned enc) { } void EhReader::skipAugP() { - uint8_t enc = readByte(); - if ((enc & 0xf0) == DW_EH_PE_aligned) - failOn(d.data() - 1, "DW_EH_PE_aligned encoding is not supported"); - size_t size = getAugPSize(enc); - if (size == 0) - failOn(d.data() - 1, "unknown FDE encoding"); - if (size >= d.size()) - failOn(d.data() - 1, "corrupted CIE"); - d = d.slice(size); + uint8_t Enc = readByte(); + if ((Enc & 0xf0) == DW_EH_PE_aligned) + failOn(D.data() - 1, "DW_EH_PE_aligned encoding is not supported"); + size_t Size = getAugPSize(Enc); + if (Size == 0) + failOn(D.data() - 1, "unknown FDE encoding"); + if (Size >= D.size()) + failOn(D.data() - 1, "corrupted CIE"); + D = D.slice(Size); } -uint8_t elf::getFdeEncoding(EhSectionPiece *p) { - return EhReader(p->sec, p->data()).getFdeEncoding(); +uint8_t elf::getFdeEncoding(EhSectionPiece *P) { + return EhReader(P->Sec, P->data()).getFdeEncoding(); } uint8_t EhReader::getFdeEncoding() { skipBytes(8); - int version = readByte(); - if (version != 1 && version != 3) - failOn(d.data() - 1, - "FDE version 1 or 3 expected, but got " + Twine(version)); + int Version = readByte(); + if (Version != 1 && Version != 3) + failOn(D.data() - 1, + "FDE version 1 or 3 expected, but got " + Twine(Version)); - StringRef aug = readString(); + StringRef Aug = readString(); // Skip code and data alignment factors. skipLeb128(); @@ -168,7 +168,7 @@ uint8_t EhReader::getFdeEncoding() { // Skip the return address register. In CIE version 1 this is a single // byte. In CIE version 3 this is an unsigned LEB128. - if (version == 1) + if (Version == 1) readByte(); else skipLeb128(); @@ -176,22 +176,22 @@ uint8_t EhReader::getFdeEncoding() { // We only care about an 'R' value, but other records may precede an 'R' // record. Unfortunately records are not in TLV (type-length-value) format, // so we need to teach the linker how to skip records for each type. - for (char c : aug) { - if (c == 'R') + for (char C : Aug) { + if (C == 'R') return readByte(); - if (c == 'z') { + if (C == 'z') { skipLeb128(); continue; } - if (c == 'P') { + if (C == 'P') { skipAugP(); continue; } - if (c == 'L') { + if (C == 'L') { readByte(); continue; } - failOn(aug.data(), "unknown .eh_frame augmentation string: " + aug); + failOn(Aug.data(), "unknown .eh_frame augmentation string: " + Aug); } return DW_EH_PE_absptr; } diff --git a/lld/ELF/EhFrame.h b/lld/ELF/EhFrame.h index 20dd6126ec8e3e..165d72b79ce434 100644 --- a/lld/ELF/EhFrame.h +++ b/lld/ELF/EhFrame.h @@ -16,8 +16,8 @@ namespace elf { class InputSectionBase; struct EhSectionPiece; -size_t readEhRecordSize(InputSectionBase *s, size_t off); -uint8_t getFdeEncoding(EhSectionPiece *p); +size_t readEhRecordSize(InputSectionBase *S, size_t Off); +uint8_t getFdeEncoding(EhSectionPiece *P); } // namespace elf } // namespace lld diff --git a/lld/ELF/ICF.cpp b/lld/ELF/ICF.cpp index a780ee1244897e..08f7ad3cda424a 100644 --- a/lld/ELF/ICF.cpp +++ b/lld/ELF/ICF.cpp @@ -74,8 +74,6 @@ #include "ICF.h" #include "Config.h" -#include "LinkerScript.h" -#include "OutputSections.h" #include "SymbolTable.h" #include "Symbols.h" #include "SyntheticSections.h" @@ -100,33 +98,33 @@ template class ICF { void run(); private: - void segregate(size_t begin, size_t end, bool constant); + void segregate(size_t Begin, size_t End, bool Constant); template - bool constantEq(const InputSection *a, ArrayRef relsA, - const InputSection *b, ArrayRef relsB); + bool constantEq(const InputSection *A, ArrayRef RelsA, + const InputSection *B, ArrayRef RelsB); template - bool variableEq(const InputSection *a, ArrayRef relsA, - const InputSection *b, ArrayRef relsB); + bool variableEq(const InputSection *A, ArrayRef RelsA, + const InputSection *B, ArrayRef RelsB); - bool equalsConstant(const InputSection *a, const InputSection *b); - bool equalsVariable(const InputSection *a, const InputSection *b); + bool equalsConstant(const InputSection *A, const InputSection *B); + bool equalsVariable(const InputSection *A, const InputSection *B); - size_t findBoundary(size_t begin, size_t end); + size_t findBoundary(size_t Begin, size_t End); - void forEachClassRange(size_t begin, size_t end, - llvm::function_ref fn); + void forEachClassRange(size_t Begin, size_t End, + llvm::function_ref Fn); - void forEachClass(llvm::function_ref fn); + void forEachClass(llvm::function_ref Fn); - std::vector sections; + std::vector Sections; // We repeat the main loop while `Repeat` is true. - std::atomic repeat; + std::atomic Repeat; // The main loop counter. - int cnt = 0; + int Cnt = 0; // We have two locations for equivalence classes. On the first iteration // of the main loop, Class[0] has a valid value, and Class[1] contains @@ -152,42 +150,42 @@ template class ICF { // because we can safely read the next class without worrying about race // conditions. Using the same location makes this algorithm converge // faster because it uses results of the same iteration earlier. - int current = 0; - int next = 0; + int Current = 0; + int Next = 0; }; } // Returns true if section S is subject of ICF. -static bool isEligible(InputSection *s) { - if (!s->isLive() || s->keepUnique || !(s->flags & SHF_ALLOC)) +static bool isEligible(InputSection *S) { + if (!S->isLive() || S->KeepUnique || !(S->Flags & SHF_ALLOC)) return false; // Don't merge writable sections. .data.rel.ro sections are marked as writable // but are semantically read-only. - if ((s->flags & SHF_WRITE) && s->name != ".data.rel.ro" && - !s->name.startswith(".data.rel.ro.")) + if ((S->Flags & SHF_WRITE) && S->Name != ".data.rel.ro" && + !S->Name.startswith(".data.rel.ro.")) return false; // SHF_LINK_ORDER sections are ICF'd as a unit with their dependent sections, // so we don't consider them for ICF individually. - if (s->flags & SHF_LINK_ORDER) + if (S->Flags & SHF_LINK_ORDER) return false; // Don't merge synthetic sections as their Data member is not valid and empty. // The Data member needs to be valid for ICF as it is used by ICF to determine // the equality of section contents. - if (isa(s)) + if (isa(S)) return false; // .init and .fini contains instructions that must be executed to initialize // and finalize the process. They cannot and should not be merged. - if (s->name == ".init" || s->name == ".fini") + if (S->Name == ".init" || S->Name == ".fini") return false; // A user program may enumerate sections named with a C identifier using // __start_* and __stop_* symbols. We cannot ICF any such sections because // that could change program semantics. - if (isValidCIdentifier(s->name)) + if (isValidCIdentifier(S->Name)) return false; return true; @@ -195,7 +193,7 @@ static bool isEligible(InputSection *s) { // Split an equivalence class into smaller classes. template -void ICF::segregate(size_t begin, size_t end, bool constant) { +void ICF::segregate(size_t Begin, size_t End, bool Constant) { // This loop rearranges sections in [Begin, End) so that all sections // that are equal in terms of equals{Constant,Variable} are contiguous // in [Begin, End). @@ -204,93 +202,93 @@ void ICF::segregate(size_t begin, size_t end, bool constant) { // issue in practice because the number of the distinct sections in // each range is usually very small. - while (begin < end) { + while (Begin < End) { // Divide [Begin, End) into two. Let Mid be the start index of the // second group. - auto bound = - std::stable_partition(sections.begin() + begin + 1, - sections.begin() + end, [&](InputSection *s) { - if (constant) - return equalsConstant(sections[begin], s); - return equalsVariable(sections[begin], s); + auto Bound = + std::stable_partition(Sections.begin() + Begin + 1, + Sections.begin() + End, [&](InputSection *S) { + if (Constant) + return equalsConstant(Sections[Begin], S); + return equalsVariable(Sections[Begin], S); }); - size_t mid = bound - sections.begin(); + size_t Mid = Bound - Sections.begin(); // Now we split [Begin, End) into [Begin, Mid) and [Mid, End) by // updating the sections in [Begin, Mid). We use Mid as an equivalence // class ID because every group ends with a unique index. - for (size_t i = begin; i < mid; ++i) - sections[i]->eqClass[next] = mid; + for (size_t I = Begin; I < Mid; ++I) + Sections[I]->Class[Next] = Mid; // If we created a group, we need to iterate the main loop again. - if (mid != end) - repeat = true; + if (Mid != End) + Repeat = true; - begin = mid; + Begin = Mid; } } // Compare two lists of relocations. template template -bool ICF::constantEq(const InputSection *secA, ArrayRef ra, - const InputSection *secB, ArrayRef rb) { - for (size_t i = 0; i < ra.size(); ++i) { - if (ra[i].r_offset != rb[i].r_offset || - ra[i].getType(config->isMips64EL) != rb[i].getType(config->isMips64EL)) +bool ICF::constantEq(const InputSection *SecA, ArrayRef RA, + const InputSection *SecB, ArrayRef RB) { + for (size_t I = 0; I < RA.size(); ++I) { + if (RA[I].r_offset != RB[I].r_offset || + RA[I].getType(Config->IsMips64EL) != RB[I].getType(Config->IsMips64EL)) return false; - uint64_t addA = getAddend(ra[i]); - uint64_t addB = getAddend(rb[i]); + uint64_t AddA = getAddend(RA[I]); + uint64_t AddB = getAddend(RB[I]); - Symbol &sa = secA->template getFile()->getRelocTargetSym(ra[i]); - Symbol &sb = secB->template getFile()->getRelocTargetSym(rb[i]); - if (&sa == &sb) { - if (addA == addB) + Symbol &SA = SecA->template getFile()->getRelocTargetSym(RA[I]); + Symbol &SB = SecB->template getFile()->getRelocTargetSym(RB[I]); + if (&SA == &SB) { + if (AddA == AddB) continue; return false; } - auto *da = dyn_cast(&sa); - auto *db = dyn_cast(&sb); + auto *DA = dyn_cast(&SA); + auto *DB = dyn_cast(&SB); // Placeholder symbols generated by linker scripts look the same now but // may have different values later. - if (!da || !db || da->scriptDefined || db->scriptDefined) + if (!DA || !DB || DA->ScriptDefined || DB->ScriptDefined) return false; // Relocations referring to absolute symbols are constant-equal if their // values are equal. - if (!da->section && !db->section && da->value + addA == db->value + addB) + if (!DA->Section && !DB->Section && DA->Value + AddA == DB->Value + AddB) continue; - if (!da->section || !db->section) + if (!DA->Section || !DB->Section) return false; - if (da->section->kind() != db->section->kind()) + if (DA->Section->kind() != DB->Section->kind()) return false; // Relocations referring to InputSections are constant-equal if their // section offsets are equal. - if (isa(da->section)) { - if (da->value + addA == db->value + addB) + if (isa(DA->Section)) { + if (DA->Value + AddA == DB->Value + AddB) continue; return false; } // Relocations referring to MergeInputSections are constant-equal if their // offsets in the output section are equal. - auto *x = dyn_cast(da->section); - if (!x) + auto *X = dyn_cast(DA->Section); + if (!X) return false; - auto *y = cast(db->section); - if (x->getParent() != y->getParent()) + auto *Y = cast(DB->Section); + if (X->getParent() != Y->getParent()) return false; - uint64_t offsetA = - sa.isSection() ? x->getOffset(addA) : x->getOffset(da->value) + addA; - uint64_t offsetB = - sb.isSection() ? y->getOffset(addB) : y->getOffset(db->value) + addB; - if (offsetA != offsetB) + uint64_t OffsetA = + SA.isSection() ? X->getOffset(AddA) : X->getOffset(DA->Value) + AddA; + uint64_t OffsetB = + SB.isSection() ? Y->getOffset(AddB) : Y->getOffset(DB->Value) + AddB; + if (OffsetA != OffsetB) return false; } @@ -300,55 +298,57 @@ bool ICF::constantEq(const InputSection *secA, ArrayRef ra, // Compare "non-moving" part of two InputSections, namely everything // except relocation targets. template -bool ICF::equalsConstant(const InputSection *a, const InputSection *b) { - if (a->numRelocations != b->numRelocations || a->flags != b->flags || - a->getSize() != b->getSize() || a->data() != b->data()) +bool ICF::equalsConstant(const InputSection *A, const InputSection *B) { + if (A->NumRelocations != B->NumRelocations || A->Flags != B->Flags || + A->getSize() != B->getSize() || A->data() != B->data()) return false; // If two sections have different output sections, we cannot merge them. - if (getOutputSectionName(a) != getOutputSectionName(b) || - a->getParent() != b->getParent()) + // FIXME: This doesn't do the right thing in the case where there is a linker + // script. We probably need to move output section assignment before ICF to + // get the correct behaviour here. + if (getOutputSectionName(A) != getOutputSectionName(B)) return false; - if (a->areRelocsRela) - return constantEq(a, a->template relas(), b, - b->template relas()); - return constantEq(a, a->template rels(), b, b->template rels()); + if (A->AreRelocsRela) + return constantEq(A, A->template relas(), B, + B->template relas()); + return constantEq(A, A->template rels(), B, B->template rels()); } // Compare two lists of relocations. Returns true if all pairs of // relocations point to the same section in terms of ICF. template template -bool ICF::variableEq(const InputSection *secA, ArrayRef ra, - const InputSection *secB, ArrayRef rb) { - assert(ra.size() == rb.size()); +bool ICF::variableEq(const InputSection *SecA, ArrayRef RA, + const InputSection *SecB, ArrayRef RB) { + assert(RA.size() == RB.size()); - for (size_t i = 0; i < ra.size(); ++i) { + for (size_t I = 0; I < RA.size(); ++I) { // The two sections must be identical. - Symbol &sa = secA->template getFile()->getRelocTargetSym(ra[i]); - Symbol &sb = secB->template getFile()->getRelocTargetSym(rb[i]); - if (&sa == &sb) + Symbol &SA = SecA->template getFile()->getRelocTargetSym(RA[I]); + Symbol &SB = SecB->template getFile()->getRelocTargetSym(RB[I]); + if (&SA == &SB) continue; - auto *da = cast(&sa); - auto *db = cast(&sb); + auto *DA = cast(&SA); + auto *DB = cast(&SB); // We already dealt with absolute and non-InputSection symbols in // constantEq, and for InputSections we have already checked everything // except the equivalence class. - if (!da->section) + if (!DA->Section) continue; - auto *x = dyn_cast(da->section); - if (!x) + auto *X = dyn_cast(DA->Section); + if (!X) continue; - auto *y = cast(db->section); + auto *Y = cast(DB->Section); // Ineligible sections are in the special equivalence class 0. // They can never be the same in terms of the equivalence class. - if (x->eqClass[current] == 0) + if (X->Class[Current] == 0) return false; - if (x->eqClass[current] != y->eqClass[current]) + if (X->Class[Current] != Y->Class[Current]) return false; }; @@ -357,19 +357,19 @@ bool ICF::variableEq(const InputSection *secA, ArrayRef ra, // Compare "moving" part of two InputSections, namely relocation targets. template -bool ICF::equalsVariable(const InputSection *a, const InputSection *b) { - if (a->areRelocsRela) - return variableEq(a, a->template relas(), b, - b->template relas()); - return variableEq(a, a->template rels(), b, b->template rels()); +bool ICF::equalsVariable(const InputSection *A, const InputSection *B) { + if (A->AreRelocsRela) + return variableEq(A, A->template relas(), B, + B->template relas()); + return variableEq(A, A->template rels(), B, B->template rels()); } -template size_t ICF::findBoundary(size_t begin, size_t end) { - uint32_t eqClass = sections[begin]->eqClass[current]; - for (size_t i = begin + 1; i < end; ++i) - if (eqClass != sections[i]->eqClass[current]) - return i; - return end; +template size_t ICF::findBoundary(size_t Begin, size_t End) { + uint32_t Class = Sections[Begin]->Class[Current]; + for (size_t I = Begin + 1; I < End; ++I) + if (Class != Sections[I]->Class[Current]) + return I; + return End; } // Sections in the same equivalence class are contiguous in Sections @@ -378,136 +378,127 @@ template size_t ICF::findBoundary(size_t begin, size_t end) { // // This function calls Fn on every group within [Begin, End). template -void ICF::forEachClassRange(size_t begin, size_t end, - llvm::function_ref fn) { - while (begin < end) { - size_t mid = findBoundary(begin, end); - fn(begin, mid); - begin = mid; +void ICF::forEachClassRange(size_t Begin, size_t End, + llvm::function_ref Fn) { + while (Begin < End) { + size_t Mid = findBoundary(Begin, End); + Fn(Begin, Mid); + Begin = Mid; } } // Call Fn on each equivalence class. template -void ICF::forEachClass(llvm::function_ref fn) { +void ICF::forEachClass(llvm::function_ref Fn) { // If threading is disabled or the number of sections are // too small to use threading, call Fn sequentially. - if (!threadsEnabled || sections.size() < 1024) { - forEachClassRange(0, sections.size(), fn); - ++cnt; + if (!ThreadsEnabled || Sections.size() < 1024) { + forEachClassRange(0, Sections.size(), Fn); + ++Cnt; return; } - current = cnt % 2; - next = (cnt + 1) % 2; + Current = Cnt % 2; + Next = (Cnt + 1) % 2; // Shard into non-overlapping intervals, and call Fn in parallel. // The sharding must be completed before any calls to Fn are made // so that Fn can modify the Chunks in its shard without causing data // races. - const size_t numShards = 256; - size_t step = sections.size() / numShards; - size_t boundaries[numShards + 1]; - boundaries[0] = 0; - boundaries[numShards] = sections.size(); - - parallelForEachN(1, numShards, [&](size_t i) { - boundaries[i] = findBoundary((i - 1) * step, sections.size()); + const size_t NumShards = 256; + size_t Step = Sections.size() / NumShards; + size_t Boundaries[NumShards + 1]; + Boundaries[0] = 0; + Boundaries[NumShards] = Sections.size(); + + parallelForEachN(1, NumShards, [&](size_t I) { + Boundaries[I] = findBoundary((I - 1) * Step, Sections.size()); }); - parallelForEachN(1, numShards + 1, [&](size_t i) { - if (boundaries[i - 1] < boundaries[i]) - forEachClassRange(boundaries[i - 1], boundaries[i], fn); + parallelForEachN(1, NumShards + 1, [&](size_t I) { + if (Boundaries[I - 1] < Boundaries[I]) + forEachClassRange(Boundaries[I - 1], Boundaries[I], Fn); }); - ++cnt; + ++Cnt; } // Combine the hashes of the sections referenced by the given section into its // hash. template -static void combineRelocHashes(unsigned cnt, InputSection *isec, - ArrayRef rels) { - uint32_t hash = isec->eqClass[cnt % 2]; - for (RelTy rel : rels) { - Symbol &s = isec->template getFile()->getRelocTargetSym(rel); - if (auto *d = dyn_cast(&s)) - if (auto *relSec = dyn_cast_or_null(d->section)) - hash += relSec->eqClass[cnt % 2]; +static void combineRelocHashes(unsigned Cnt, InputSection *IS, + ArrayRef Rels) { + uint32_t Hash = IS->Class[Cnt % 2]; + for (RelTy Rel : Rels) { + Symbol &S = IS->template getFile()->getRelocTargetSym(Rel); + if (auto *D = dyn_cast(&S)) + if (auto *RelSec = dyn_cast_or_null(D->Section)) + Hash += RelSec->Class[Cnt % 2]; } // Set MSB to 1 to avoid collisions with non-hash IDs. - isec->eqClass[(cnt + 1) % 2] = hash | (1U << 31); + IS->Class[(Cnt + 1) % 2] = Hash | (1U << 31); } -static void print(const Twine &s) { - if (config->printIcfSections) - message(s); +static void print(const Twine &S) { + if (Config->PrintIcfSections) + message(S); } // The main function of ICF. template void ICF::run() { // Collect sections to merge. - for (InputSectionBase *sec : inputSections) - if (auto *s = dyn_cast(sec)) - if (isEligible(s)) - sections.push_back(s); + for (InputSectionBase *Sec : InputSections) + if (auto *S = dyn_cast(Sec)) + if (isEligible(S)) + Sections.push_back(S); // Initially, we use hash values to partition sections. - parallelForEach(sections, [&](InputSection *s) { - s->eqClass[0] = xxHash64(s->data()); + parallelForEach(Sections, [&](InputSection *S) { + S->Class[0] = xxHash64(S->data()); }); - for (unsigned cnt = 0; cnt != 2; ++cnt) { - parallelForEach(sections, [&](InputSection *s) { - if (s->areRelocsRela) - combineRelocHashes(cnt, s, s->template relas()); + for (unsigned Cnt = 0; Cnt != 2; ++Cnt) { + parallelForEach(Sections, [&](InputSection *S) { + if (S->AreRelocsRela) + combineRelocHashes(Cnt, S, S->template relas()); else - combineRelocHashes(cnt, s, s->template rels()); + combineRelocHashes(Cnt, S, S->template rels()); }); } // From now on, sections in Sections vector are ordered so that sections // in the same equivalence class are consecutive in the vector. - llvm::stable_sort(sections, [](const InputSection *a, const InputSection *b) { - return a->eqClass[0] < b->eqClass[0]; + llvm::stable_sort(Sections, [](const InputSection *A, const InputSection *B) { + return A->Class[0] < B->Class[0]; }); // Compare static contents and assign unique IDs for each static content. - forEachClass([&](size_t begin, size_t end) { segregate(begin, end, true); }); + forEachClass([&](size_t Begin, size_t End) { segregate(Begin, End, true); }); // Split groups by comparing relocations until convergence is obtained. do { - repeat = false; + Repeat = false; forEachClass( - [&](size_t begin, size_t end) { segregate(begin, end, false); }); - } while (repeat); + [&](size_t Begin, size_t End) { segregate(Begin, End, false); }); + } while (Repeat); - log("ICF needed " + Twine(cnt) + " iterations"); + log("ICF needed " + Twine(Cnt) + " iterations"); // Merge sections by the equivalence class. - forEachClassRange(0, sections.size(), [&](size_t begin, size_t end) { - if (end - begin == 1) + forEachClassRange(0, Sections.size(), [&](size_t Begin, size_t End) { + if (End - Begin == 1) return; - print("selected section " + toString(sections[begin])); - for (size_t i = begin + 1; i < end; ++i) { - print(" removing identical section " + toString(sections[i])); - sections[begin]->replace(sections[i]); + print("selected section " + toString(Sections[Begin])); + for (size_t I = Begin + 1; I < End; ++I) { + print(" removing identical section " + toString(Sections[I])); + Sections[Begin]->replace(Sections[I]); // At this point we know sections merged are fully identical and hence // we want to remove duplicate implicit dependencies such as link order // and relocation sections. - for (InputSection *isec : sections[i]->dependentSections) - isec->markDead(); + for (InputSection *IS : Sections[I]->DependentSections) + IS->markDead(); } }); - - // InputSectionDescription::sections is populated by processSectionCommands(). - // ICF may fold some input sections assigned to output sections. Remove them. - for (BaseCommand *base : script->sectionCommands) - if (auto *sec = dyn_cast(base)) - for (BaseCommand *sub_base : sec->sectionCommands) - if (auto *isd = dyn_cast(sub_base)) - llvm::erase_if(isd->sections, - [](InputSection *isec) { return !isec->isLive(); }); } // ICF entry point function. diff --git a/lld/ELF/InputFiles.cpp b/lld/ELF/InputFiles.cpp index 71f28f4a63cede..d1a72f0adc4c24 100644 --- a/lld/ELF/InputFiles.cpp +++ b/lld/ELF/InputFiles.cpp @@ -40,167 +40,167 @@ using namespace llvm::support::endian; using namespace lld; using namespace lld::elf; -bool InputFile::isInGroup; -uint32_t InputFile::nextGroupId; -std::vector elf::binaryFiles; -std::vector elf::bitcodeFiles; -std::vector elf::lazyObjFiles; -std::vector elf::objectFiles; -std::vector elf::sharedFiles; - -std::unique_ptr elf::tar; - -static ELFKind getELFKind(MemoryBufferRef mb, StringRef archiveName) { - unsigned char size; - unsigned char endian; - std::tie(size, endian) = getElfArchType(mb.getBuffer()); - - auto report = [&](StringRef msg) { - StringRef filename = mb.getBufferIdentifier(); - if (archiveName.empty()) - fatal(filename + ": " + msg); +bool InputFile::IsInGroup; +uint32_t InputFile::NextGroupId; +std::vector elf::BinaryFiles; +std::vector elf::BitcodeFiles; +std::vector elf::LazyObjFiles; +std::vector elf::ObjectFiles; +std::vector elf::SharedFiles; + +std::unique_ptr elf::Tar; + +static ELFKind getELFKind(MemoryBufferRef MB, StringRef ArchiveName) { + unsigned char Size; + unsigned char Endian; + std::tie(Size, Endian) = getElfArchType(MB.getBuffer()); + + auto Fatal = [&](StringRef Msg) { + StringRef Filename = MB.getBufferIdentifier(); + if (ArchiveName.empty()) + fatal(Filename + ": " + Msg); else - fatal(archiveName + "(" + filename + "): " + msg); + fatal(ArchiveName + "(" + Filename + "): " + Msg); }; - if (!mb.getBuffer().startswith(ElfMagic)) - report("not an ELF file"); - if (endian != ELFDATA2LSB && endian != ELFDATA2MSB) - report("corrupted ELF file: invalid data encoding"); - if (size != ELFCLASS32 && size != ELFCLASS64) - report("corrupted ELF file: invalid file class"); - - size_t bufSize = mb.getBuffer().size(); - if ((size == ELFCLASS32 && bufSize < sizeof(Elf32_Ehdr)) || - (size == ELFCLASS64 && bufSize < sizeof(Elf64_Ehdr))) - report("corrupted ELF file: file is too short"); - - if (size == ELFCLASS32) - return (endian == ELFDATA2LSB) ? ELF32LEKind : ELF32BEKind; - return (endian == ELFDATA2LSB) ? ELF64LEKind : ELF64BEKind; + if (!MB.getBuffer().startswith(ElfMagic)) + Fatal("not an ELF file"); + if (Endian != ELFDATA2LSB && Endian != ELFDATA2MSB) + Fatal("corrupted ELF file: invalid data encoding"); + if (Size != ELFCLASS32 && Size != ELFCLASS64) + Fatal("corrupted ELF file: invalid file class"); + + size_t BufSize = MB.getBuffer().size(); + if ((Size == ELFCLASS32 && BufSize < sizeof(Elf32_Ehdr)) || + (Size == ELFCLASS64 && BufSize < sizeof(Elf64_Ehdr))) + Fatal("corrupted ELF file: file is too short"); + + if (Size == ELFCLASS32) + return (Endian == ELFDATA2LSB) ? ELF32LEKind : ELF32BEKind; + return (Endian == ELFDATA2LSB) ? ELF64LEKind : ELF64BEKind; } -InputFile::InputFile(Kind k, MemoryBufferRef m) - : mb(m), groupId(nextGroupId), fileKind(k) { +InputFile::InputFile(Kind K, MemoryBufferRef M) + : MB(M), GroupId(NextGroupId), FileKind(K) { // All files within the same --{start,end}-group get the same group ID. // Otherwise, a new file will get a new group ID. - if (!isInGroup) - ++nextGroupId; + if (!IsInGroup) + ++NextGroupId; } -Optional elf::readFile(StringRef path) { +Optional elf::readFile(StringRef Path) { // The --chroot option changes our virtual root directory. // This is useful when you are dealing with files created by --reproduce. - if (!config->chroot.empty() && path.startswith("/")) - path = saver.save(config->chroot + path); + if (!Config->Chroot.empty() && Path.startswith("/")) + Path = Saver.save(Config->Chroot + Path); - log(path); + log(Path); - auto mbOrErr = MemoryBuffer::getFile(path, -1, false); - if (auto ec = mbOrErr.getError()) { - error("cannot open " + path + ": " + ec.message()); + auto MBOrErr = MemoryBuffer::getFile(Path, -1, false); + if (auto EC = MBOrErr.getError()) { + error("cannot open " + Path + ": " + EC.message()); return None; } - std::unique_ptr &mb = *mbOrErr; - MemoryBufferRef mbref = mb->getMemBufferRef(); - make>(std::move(mb)); // take MB ownership + std::unique_ptr &MB = *MBOrErr; + MemoryBufferRef MBRef = MB->getMemBufferRef(); + make>(std::move(MB)); // take MB ownership - if (tar) - tar->append(relativeToRoot(path), mbref.getBuffer()); - return mbref; + if (Tar) + Tar->append(relativeToRoot(Path), MBRef.getBuffer()); + return MBRef; } // All input object files must be for the same architecture // (e.g. it does not make sense to link x86 object files with // MIPS object files.) This function checks for that error. -static bool isCompatible(InputFile *file) { - if (!file->isElf() && !isa(file)) +static bool isCompatible(InputFile *File) { + if (!File->isElf() && !isa(File)) return true; - if (file->ekind == config->ekind && file->emachine == config->emachine) { - if (config->emachine != EM_MIPS) + if (File->EKind == Config->EKind && File->EMachine == Config->EMachine) { + if (Config->EMachine != EM_MIPS) return true; - if (isMipsN32Abi(file) == config->mipsN32Abi) + if (isMipsN32Abi(File) == Config->MipsN32Abi) return true; } - if (!config->emulation.empty()) { - error(toString(file) + " is incompatible with " + config->emulation); - return false; - } + if (!Config->Emulation.empty()) { + error(toString(File) + " is incompatible with " + Config->Emulation); + } else { + InputFile *Existing; + if (!ObjectFiles.empty()) + Existing = ObjectFiles[0]; + else if (!SharedFiles.empty()) + Existing = SharedFiles[0]; + else + Existing = BitcodeFiles[0]; - InputFile *existing; - if (!objectFiles.empty()) - existing = objectFiles[0]; - else if (!sharedFiles.empty()) - existing = sharedFiles[0]; - else - existing = bitcodeFiles[0]; + error(toString(File) + " is incompatible with " + toString(Existing)); + } - error(toString(file) + " is incompatible with " + toString(existing)); return false; } -template static void doParseFile(InputFile *file) { - if (!isCompatible(file)) +template static void doParseFile(InputFile *File) { + if (!isCompatible(File)) return; // Binary file - if (auto *f = dyn_cast(file)) { - binaryFiles.push_back(f); - f->parse(); + if (auto *F = dyn_cast(File)) { + BinaryFiles.push_back(F); + F->parse(); return; } // .a file - if (auto *f = dyn_cast(file)) { - f->parse(); + if (auto *F = dyn_cast(File)) { + F->parse(); return; } // Lazy object file - if (auto *f = dyn_cast(file)) { - lazyObjFiles.push_back(f); - f->parse(); + if (auto *F = dyn_cast(File)) { + LazyObjFiles.push_back(F); + F->parse(); return; } - if (config->trace) - message(toString(file)); + if (Config->Trace) + message(toString(File)); // .so file - if (auto *f = dyn_cast(file)) { - f->parse(); + if (auto *F = dyn_cast(File)) { + F->parse(); return; } // LLVM bitcode file - if (auto *f = dyn_cast(file)) { - bitcodeFiles.push_back(f); - f->parse(); + if (auto *F = dyn_cast(File)) { + BitcodeFiles.push_back(F); + F->parse(); return; } // Regular object file - objectFiles.push_back(file); - cast>(file)->parse(); + ObjectFiles.push_back(File); + cast>(File)->parse(); } // Add symbols in File to the symbol table. -void elf::parseFile(InputFile *file) { - switch (config->ekind) { +void elf::parseFile(InputFile *File) { + switch (Config->EKind) { case ELF32LEKind: - doParseFile(file); + doParseFile(File); return; case ELF32BEKind: - doParseFile(file); + doParseFile(File); return; case ELF64LEKind: - doParseFile(file); + doParseFile(File); return; case ELF64BEKind: - doParseFile(file); + doParseFile(File); return; default: llvm_unreachable("unknown ELFT"); @@ -208,99 +208,99 @@ void elf::parseFile(InputFile *file) { } // Concatenates arguments to construct a string representing an error location. -static std::string createFileLineMsg(StringRef path, unsigned line) { - std::string filename = path::filename(path); - std::string lineno = ":" + std::to_string(line); - if (filename == path) - return filename + lineno; - return filename + lineno + " (" + path.str() + lineno + ")"; +static std::string createFileLineMsg(StringRef Path, unsigned Line) { + std::string Filename = path::filename(Path); + std::string Lineno = ":" + std::to_string(Line); + if (Filename == Path) + return Filename + Lineno; + return Filename + Lineno + " (" + Path.str() + Lineno + ")"; } template -static std::string getSrcMsgAux(ObjFile &file, const Symbol &sym, - InputSectionBase &sec, uint64_t offset) { +static std::string getSrcMsgAux(ObjFile &File, const Symbol &Sym, + InputSectionBase &Sec, uint64_t Offset) { // In DWARF, functions and variables are stored to different places. // First, lookup a function for a given offset. - if (Optional info = file.getDILineInfo(&sec, offset)) - return createFileLineMsg(info->FileName, info->Line); + if (Optional Info = File.getDILineInfo(&Sec, Offset)) + return createFileLineMsg(Info->FileName, Info->Line); // If it failed, lookup again as a variable. - if (Optional> fileLine = - file.getVariableLoc(sym.getName())) - return createFileLineMsg(fileLine->first, fileLine->second); + if (Optional> FileLine = + File.getVariableLoc(Sym.getName())) + return createFileLineMsg(FileLine->first, FileLine->second); - // File.sourceFile contains STT_FILE symbol, and that is a last resort. - return file.sourceFile; + // File.SourceFile contains STT_FILE symbol, and that is a last resort. + return File.SourceFile; } -std::string InputFile::getSrcMsg(const Symbol &sym, InputSectionBase &sec, - uint64_t offset) { +std::string InputFile::getSrcMsg(const Symbol &Sym, InputSectionBase &Sec, + uint64_t Offset) { if (kind() != ObjKind) return ""; - switch (config->ekind) { + switch (Config->EKind) { default: llvm_unreachable("Invalid kind"); case ELF32LEKind: - return getSrcMsgAux(cast>(*this), sym, sec, offset); + return getSrcMsgAux(cast>(*this), Sym, Sec, Offset); case ELF32BEKind: - return getSrcMsgAux(cast>(*this), sym, sec, offset); + return getSrcMsgAux(cast>(*this), Sym, Sec, Offset); case ELF64LEKind: - return getSrcMsgAux(cast>(*this), sym, sec, offset); + return getSrcMsgAux(cast>(*this), Sym, Sec, Offset); case ELF64BEKind: - return getSrcMsgAux(cast>(*this), sym, sec, offset); + return getSrcMsgAux(cast>(*this), Sym, Sec, Offset); } } template void ObjFile::initializeDwarf() { - dwarf = std::make_unique(std::make_unique>(this)); - for (std::unique_ptr &cu : dwarf->compile_units()) { - auto report = [](Error err) { - handleAllErrors(std::move(err), - [](ErrorInfoBase &info) { warn(info.message()); }); + Dwarf = llvm::make_unique(make_unique>(this)); + for (std::unique_ptr &CU : Dwarf->compile_units()) { + auto Report = [](Error Err) { + handleAllErrors(std::move(Err), + [](ErrorInfoBase &Info) { warn(Info.message()); }); }; - Expected expectedLT = - dwarf->getLineTableForUnit(cu.get(), report); - const DWARFDebugLine::LineTable *lt = nullptr; - if (expectedLT) - lt = *expectedLT; + Expected ExpectedLT = + Dwarf->getLineTableForUnit(CU.get(), Report); + const DWARFDebugLine::LineTable *LT = nullptr; + if (ExpectedLT) + LT = *ExpectedLT; else - report(expectedLT.takeError()); - if (!lt) + Report(ExpectedLT.takeError()); + if (!LT) continue; - lineTables.push_back(lt); + LineTables.push_back(LT); - // Loop over variable records and insert them to variableLoc. - for (const auto &entry : cu->dies()) { - DWARFDie die(cu.get(), &entry); + // Loop over variable records and insert them to VariableLoc. + for (const auto &Entry : CU->dies()) { + DWARFDie Die(CU.get(), &Entry); // Skip all tags that are not variables. - if (die.getTag() != dwarf::DW_TAG_variable) + if (Die.getTag() != dwarf::DW_TAG_variable) continue; // Skip if a local variable because we don't need them for generating // error messages. In general, only non-local symbols can fail to be // linked. - if (!dwarf::toUnsigned(die.find(dwarf::DW_AT_external), 0)) + if (!dwarf::toUnsigned(Die.find(dwarf::DW_AT_external), 0)) continue; // Get the source filename index for the variable. - unsigned file = dwarf::toUnsigned(die.find(dwarf::DW_AT_decl_file), 0); - if (!lt->hasFileAtIndex(file)) + unsigned File = dwarf::toUnsigned(Die.find(dwarf::DW_AT_decl_file), 0); + if (!LT->hasFileAtIndex(File)) continue; // Get the line number on which the variable is declared. - unsigned line = dwarf::toUnsigned(die.find(dwarf::DW_AT_decl_line), 0); + unsigned Line = dwarf::toUnsigned(Die.find(dwarf::DW_AT_decl_line), 0); - // Here we want to take the variable name to add it into variableLoc. + // Here we want to take the variable name to add it into VariableLoc. // Variable can have regular and linkage name associated. At first, we try // to get linkage name as it can be different, for example when we have // two variables in different namespaces of the same object. Use common // name otherwise, but handle the case when it also absent in case if the // input object file lacks some debug info. - StringRef name = - dwarf::toString(die.find(dwarf::DW_AT_linkage_name), - dwarf::toString(die.find(dwarf::DW_AT_name), "")); - if (!name.empty()) - variableLoc.insert({name, {lt, file, line}}); + StringRef Name = + dwarf::toString(Die.find(dwarf::DW_AT_linkage_name), + dwarf::toString(Die.find(dwarf::DW_AT_name), "")); + if (!Name.empty()) + VariableLoc.insert({Name, {LT, File, Line}}); } } } @@ -309,71 +309,71 @@ template void ObjFile::initializeDwarf() { // object (variable, array, etc) definition. template Optional> -ObjFile::getVariableLoc(StringRef name) { - llvm::call_once(initDwarfLine, [this]() { initializeDwarf(); }); +ObjFile::getVariableLoc(StringRef Name) { + llvm::call_once(InitDwarfLine, [this]() { initializeDwarf(); }); // Return if we have no debug information about data object. - auto it = variableLoc.find(name); - if (it == variableLoc.end()) + auto It = VariableLoc.find(Name); + if (It == VariableLoc.end()) return None; // Take file name string from line table. - std::string fileName; - if (!it->second.lt->getFileNameByIndex( - it->second.file, {}, - DILineInfoSpecifier::FileLineInfoKind::AbsoluteFilePath, fileName)) + std::string FileName; + if (!It->second.LT->getFileNameByIndex( + It->second.File, nullptr, + DILineInfoSpecifier::FileLineInfoKind::AbsoluteFilePath, FileName)) return None; - return std::make_pair(fileName, it->second.line); + return std::make_pair(FileName, It->second.Line); } // Returns source line information for a given offset // using DWARF debug info. template -Optional ObjFile::getDILineInfo(InputSectionBase *s, - uint64_t offset) { - llvm::call_once(initDwarfLine, [this]() { initializeDwarf(); }); +Optional ObjFile::getDILineInfo(InputSectionBase *S, + uint64_t Offset) { + llvm::call_once(InitDwarfLine, [this]() { initializeDwarf(); }); // Detect SectionIndex for specified section. - uint64_t sectionIndex = object::SectionedAddress::UndefSection; - ArrayRef sections = s->file->getSections(); - for (uint64_t curIndex = 0; curIndex < sections.size(); ++curIndex) { - if (s == sections[curIndex]) { - sectionIndex = curIndex; + uint64_t SectionIndex = object::SectionedAddress::UndefSection; + ArrayRef Sections = S->File->getSections(); + for (uint64_t CurIndex = 0; CurIndex < Sections.size(); ++CurIndex) { + if (S == Sections[CurIndex]) { + SectionIndex = CurIndex; break; } } // Use fake address calcuated by adding section file offset and offset in // section. See comments for ObjectInfo class. - DILineInfo info; - for (const llvm::DWARFDebugLine::LineTable *lt : lineTables) { - if (lt->getFileLineInfoForAddress( - {s->getOffsetInFile() + offset, sectionIndex}, nullptr, - DILineInfoSpecifier::FileLineInfoKind::AbsoluteFilePath, info)) - return info; + DILineInfo Info; + for (const llvm::DWARFDebugLine::LineTable *LT : LineTables) { + if (LT->getFileLineInfoForAddress( + {S->getOffsetInFile() + Offset, SectionIndex}, nullptr, + DILineInfoSpecifier::FileLineInfoKind::AbsoluteFilePath, Info)) + return Info; } return None; } // Returns "", "foo.a(bar.o)" or "baz.o". -std::string lld::toString(const InputFile *f) { - if (!f) +std::string lld::toString(const InputFile *F) { + if (!F) return ""; - if (f->toStringCache.empty()) { - if (f->archiveName.empty()) - f->toStringCache = f->getName(); + if (F->ToStringCache.empty()) { + if (F->ArchiveName.empty()) + F->ToStringCache = F->getName(); else - f->toStringCache = (f->archiveName + "(" + f->getName() + ")").str(); + F->ToStringCache = (F->ArchiveName + "(" + F->getName() + ")").str(); } - return f->toStringCache; + return F->ToStringCache; } -ELFFileBase::ELFFileBase(Kind k, MemoryBufferRef mb) : InputFile(k, mb) { - ekind = getELFKind(mb, ""); +ELFFileBase::ELFFileBase(Kind K, MemoryBufferRef MB) : InputFile(K, MB) { + EKind = getELFKind(MB, ""); - switch (ekind) { + switch (EKind) { case ELF32LEKind: init(); break; @@ -392,10 +392,10 @@ ELFFileBase::ELFFileBase(Kind k, MemoryBufferRef mb) : InputFile(k, mb) { } template -static const Elf_Shdr *findSection(ArrayRef sections, uint32_t type) { - for (const Elf_Shdr &sec : sections) - if (sec.sh_type == type) - return &sec; +static const Elf_Shdr *findSection(ArrayRef Sections, uint32_t Type) { + for (const Elf_Shdr &Sec : Sections) + if (Sec.sh_type == Type) + return &Sec; return nullptr; } @@ -404,57 +404,57 @@ template void ELFFileBase::init() { using Elf_Sym = typename ELFT::Sym; // Initialize trivial attributes. - const ELFFile &obj = getObj(); - emachine = obj.getHeader()->e_machine; - osabi = obj.getHeader()->e_ident[llvm::ELF::EI_OSABI]; - abiVersion = obj.getHeader()->e_ident[llvm::ELF::EI_ABIVERSION]; + const ELFFile &Obj = getObj(); + EMachine = Obj.getHeader()->e_machine; + OSABI = Obj.getHeader()->e_ident[llvm::ELF::EI_OSABI]; + ABIVersion = Obj.getHeader()->e_ident[llvm::ELF::EI_ABIVERSION]; - ArrayRef sections = CHECK(obj.sections(), this); + ArrayRef Sections = CHECK(Obj.sections(), this); // Find a symbol table. - bool isDSO = - (identify_magic(mb.getBuffer()) == file_magic::elf_shared_object); - const Elf_Shdr *symtabSec = - findSection(sections, isDSO ? SHT_DYNSYM : SHT_SYMTAB); + bool IsDSO = + (identify_magic(MB.getBuffer()) == file_magic::elf_shared_object); + const Elf_Shdr *SymtabSec = + findSection(Sections, IsDSO ? SHT_DYNSYM : SHT_SYMTAB); - if (!symtabSec) + if (!SymtabSec) return; // Initialize members corresponding to a symbol table. - firstGlobal = symtabSec->sh_info; + FirstGlobal = SymtabSec->sh_info; - ArrayRef eSyms = CHECK(obj.symbols(symtabSec), this); - if (firstGlobal == 0 || firstGlobal > eSyms.size()) + ArrayRef ESyms = CHECK(Obj.symbols(SymtabSec), this); + if (FirstGlobal == 0 || FirstGlobal > ESyms.size()) fatal(toString(this) + ": invalid sh_info in symbol table"); - elfSyms = reinterpret_cast(eSyms.data()); - numELFSyms = eSyms.size(); - stringTable = CHECK(obj.getStringTableForSymtab(*symtabSec, sections), this); + ELFSyms = reinterpret_cast(ESyms.data()); + NumELFSyms = ESyms.size(); + StringTable = CHECK(Obj.getStringTableForSymtab(*SymtabSec, Sections), this); } template -uint32_t ObjFile::getSectionIndex(const Elf_Sym &sym) const { +uint32_t ObjFile::getSectionIndex(const Elf_Sym &Sym) const { return CHECK( - this->getObj().getSectionIndex(&sym, getELFSyms(), shndxTable), + this->getObj().getSectionIndex(&Sym, getELFSyms(), ShndxTable), this); } template ArrayRef ObjFile::getLocalSymbols() { - if (this->symbols.empty()) + if (this->Symbols.empty()) return {}; - return makeArrayRef(this->symbols).slice(1, this->firstGlobal - 1); + return makeArrayRef(this->Symbols).slice(1, this->FirstGlobal - 1); } template ArrayRef ObjFile::getGlobalSymbols() { - return makeArrayRef(this->symbols).slice(this->firstGlobal); + return makeArrayRef(this->Symbols).slice(this->FirstGlobal); } -template void ObjFile::parse(bool ignoreComdats) { - // Read a section table. justSymbols is usually false. - if (this->justSymbols) +template void ObjFile::parse(bool IgnoreComdats) { + // Read a section table. JustSymbols is usually false. + if (this->JustSymbols) initializeJustSymbols(); else - initializeSections(ignoreComdats); + initializeSections(IgnoreComdats); // Read a symbol table. initializeSymbols(); @@ -464,13 +464,11 @@ template void ObjFile::parse(bool ignoreComdats) { // They are identified and deduplicated by group name. This function // returns a group name. template -StringRef ObjFile::getShtGroupSignature(ArrayRef sections, - const Elf_Shdr &sec) { - typename ELFT::SymRange symbols = this->getELFSyms(); - if (sec.sh_info >= symbols.size()) - fatal(toString(this) + ": invalid symbol index"); - const typename ELFT::Sym &sym = symbols[sec.sh_info]; - StringRef signature = CHECK(sym.getName(this->stringTable), this); +StringRef ObjFile::getShtGroupSignature(ArrayRef Sections, + const Elf_Shdr &Sec) { + const Elf_Sym *Sym = + CHECK(object::getSymbol(this->getELFSyms(), Sec.sh_info), this); + StringRef Signature = CHECK(Sym->getName(this->StringTable), this); // As a special case, if a symbol is a section symbol and has no name, // we use a section name as a signature. @@ -479,12 +477,12 @@ StringRef ObjFile::getShtGroupSignature(ArrayRef sections, // standard, but GNU gold 1.14 (the newest version as of July 2017) or // older produce such sections as outputs for the -r option, so we need // a bug-compatibility. - if (signature.empty() && sym.getType() == STT_SECTION) - return getSectionName(sec); - return signature; + if (Signature.empty() && Sym->getType() == STT_SECTION) + return getSectionName(Sec); + return Signature; } -template bool ObjFile::shouldMerge(const Elf_Shdr &sec) { +template bool ObjFile::shouldMerge(const Elf_Shdr &Sec) { // On a regular link we don't merge sections if -O0 (default is -O1). This // sometimes makes the linker significantly faster, although the output will // be bigger. @@ -497,14 +495,14 @@ template bool ObjFile::shouldMerge(const Elf_Shdr &sec) { // SHF_MERGE sections based both on their name and sh_entsize, but that seems // to be more trouble than it is worth. Instead, we just use the regular (-O1) // logic for -r. - if (config->optimize == 0 && !config->relocatable) + if (Config->Optimize == 0 && !Config->Relocatable) return false; // A mergeable section with size 0 is useless because they don't have // any data to merge. A mergeable string section with size 0 can be // argued as invalid because it doesn't end with a null character. // We'll avoid a mess by handling them as if they were non-mergeable. - if (sec.sh_size == 0) + if (Sec.sh_size == 0) return false; // Check for sh_entsize. The ELF spec is not clear about the zero @@ -512,17 +510,17 @@ template bool ObjFile::shouldMerge(const Elf_Shdr &sec) { // the section does not hold a table of fixed-size entries". We know // that Rust 1.13 produces a string mergeable section with a zero // sh_entsize. Here we just accept it rather than being picky about it. - uint64_t entSize = sec.sh_entsize; - if (entSize == 0) + uint64_t EntSize = Sec.sh_entsize; + if (EntSize == 0) return false; - if (sec.sh_size % entSize) + if (Sec.sh_size % EntSize) fatal(toString(this) + ": SHF_MERGE section size must be a multiple of sh_entsize"); - uint64_t flags = sec.sh_flags; - if (!(flags & SHF_MERGE)) + uint64_t Flags = Sec.sh_flags; + if (!(Flags & SHF_MERGE)) return false; - if (flags & SHF_WRITE) + if (Flags & SHF_WRITE) fatal(toString(this) + ": writable SHF_MERGE section is not supported"); return true; @@ -538,8 +536,8 @@ template bool ObjFile::shouldMerge(const Elf_Shdr &sec) { // When the option is given, we link "just symbols". The section table is // initialized with null pointers. template void ObjFile::initializeJustSymbols() { - ArrayRef sections = CHECK(this->getObj().sections(), this); - this->sections.resize(sections.size()); + ArrayRef Sections = CHECK(this->getObj().sections(), this); + this->Sections.resize(Sections.size()); } // An ELF object file may contain a `.deplibs` section. If it exists, the @@ -548,142 +546,138 @@ template void ObjFile::initializeJustSymbols() { // the various ways that a library can be specified to LLD. This ELF extension // is a form of autolinking and is called `dependent libraries`. It is currently // unique to LLVM and lld. -static void addDependentLibrary(StringRef specifier, const InputFile *f) { - if (!config->dependentLibraries) +static void addDependentLibrary(StringRef Specifier, const InputFile *F) { + if (!Config->DependentLibraries) return; - if (fs::exists(specifier)) - driver->addFile(specifier, /*withLOption=*/false); - else if (Optional s = findFromSearchPaths(specifier)) - driver->addFile(*s, /*withLOption=*/true); - else if (Optional s = searchLibraryBaseName(specifier)) - driver->addFile(*s, /*withLOption=*/true); + if (fs::exists(Specifier)) + Driver->addFile(Specifier, /*WithLOption=*/false); + else if (Optional S = findFromSearchPaths(Specifier)) + Driver->addFile(*S, /*WithLOption=*/true); + else if (Optional S = searchLibraryBaseName(Specifier)) + Driver->addFile(*S, /*WithLOption=*/true); else - error(toString(f) + + error(toString(F) + ": unable to find library from dependent library specifier: " + - specifier); + Specifier); } template -void ObjFile::initializeSections(bool ignoreComdats) { - const ELFFile &obj = this->getObj(); +void ObjFile::initializeSections(bool IgnoreComdats) { + const ELFFile &Obj = this->getObj(); - ArrayRef objSections = CHECK(obj.sections(), this); - uint64_t size = objSections.size(); - this->sections.resize(size); - this->sectionStringTable = - CHECK(obj.getSectionStringTable(objSections), this); + ArrayRef ObjSections = CHECK(Obj.sections(), this); + uint64_t Size = ObjSections.size(); + this->Sections.resize(Size); + this->SectionStringTable = + CHECK(Obj.getSectionStringTable(ObjSections), this); - for (size_t i = 0, e = objSections.size(); i < e; ++i) { - if (this->sections[i] == &InputSection::discarded) + for (size_t I = 0, E = ObjSections.size(); I < E; I++) { + if (this->Sections[I] == &InputSection::Discarded) continue; - const Elf_Shdr &sec = objSections[i]; + const Elf_Shdr &Sec = ObjSections[I]; - if (sec.sh_type == ELF::SHT_LLVM_CALL_GRAPH_PROFILE) - cgProfile = - check(obj.template getSectionContentsAsArray(&sec)); + if (Sec.sh_type == ELF::SHT_LLVM_CALL_GRAPH_PROFILE) + CGProfile = + check(Obj.template getSectionContentsAsArray(&Sec)); // SHF_EXCLUDE'ed sections are discarded by the linker. However, // if -r is given, we'll let the final link discard such sections. // This is compatible with GNU. - if ((sec.sh_flags & SHF_EXCLUDE) && !config->relocatable) { - if (sec.sh_type == SHT_LLVM_ADDRSIG) { + if ((Sec.sh_flags & SHF_EXCLUDE) && !Config->Relocatable) { + if (Sec.sh_type == SHT_LLVM_ADDRSIG) { // We ignore the address-significance table if we know that the object // file was created by objcopy or ld -r. This is because these tools // will reorder the symbols in the symbol table, invalidating the data // in the address-significance table, which refers to symbols by index. - if (sec.sh_link != 0) - this->addrsigSec = &sec; - else if (config->icf == ICFLevel::Safe) + if (Sec.sh_link != 0) + this->AddrsigSec = &Sec; + else if (Config->ICF == ICFLevel::Safe) warn(toString(this) + ": --icf=safe is incompatible with object " "files created using objcopy or ld -r"); } - this->sections[i] = &InputSection::discarded; + this->Sections[I] = &InputSection::Discarded; continue; } - switch (sec.sh_type) { + switch (Sec.sh_type) { case SHT_GROUP: { // De-duplicate section groups by their signatures. - StringRef signature = getShtGroupSignature(objSections, sec); - this->sections[i] = &InputSection::discarded; + StringRef Signature = getShtGroupSignature(ObjSections, Sec); + this->Sections[I] = &InputSection::Discarded; - ArrayRef entries = - CHECK(obj.template getSectionContentsAsArray(&sec), this); - if (entries.empty()) + ArrayRef Entries = + CHECK(Obj.template getSectionContentsAsArray(&Sec), this); + if (Entries.empty()) fatal(toString(this) + ": empty SHT_GROUP"); // The first word of a SHT_GROUP section contains flags. Currently, // the standard defines only "GRP_COMDAT" flag for the COMDAT group. // An group with the empty flag doesn't define anything; such sections // are just skipped. - if (entries[0] == 0) + if (Entries[0] == 0) continue; - if (entries[0] != GRP_COMDAT) + if (Entries[0] != GRP_COMDAT) fatal(toString(this) + ": unsupported SHT_GROUP format"); - bool isNew = - ignoreComdats || - symtab->comdatGroups.try_emplace(CachedHashStringRef(signature), this) + bool IsNew = + IgnoreComdats || + Symtab->ComdatGroups.try_emplace(CachedHashStringRef(Signature), this) .second; - if (isNew) { - if (config->relocatable) - this->sections[i] = createInputSection(sec); + if (IsNew) { + if (Config->Relocatable) + this->Sections[I] = createInputSection(Sec); continue; } // Otherwise, discard group members. - for (uint32_t secIndex : entries.slice(1)) { - if (secIndex >= size) + for (uint32_t SecIndex : Entries.slice(1)) { + if (SecIndex >= Size) fatal(toString(this) + - ": invalid section index in group: " + Twine(secIndex)); - this->sections[secIndex] = &InputSection::discarded; + ": invalid section index in group: " + Twine(SecIndex)); + this->Sections[SecIndex] = &InputSection::Discarded; } break; } case SHT_SYMTAB_SHNDX: - shndxTable = CHECK(obj.getSHNDXTable(sec, objSections), this); + ShndxTable = CHECK(Obj.getSHNDXTable(Sec, ObjSections), this); break; case SHT_SYMTAB: case SHT_STRTAB: case SHT_NULL: break; default: - this->sections[i] = createInputSection(sec); + this->Sections[I] = createInputSection(Sec); } - } - - for (size_t i = 0, e = objSections.size(); i < e; ++i) { - if (this->sections[i] == &InputSection::discarded) - continue; - const Elf_Shdr &sec = objSections[i]; - if (!(sec.sh_flags & SHF_LINK_ORDER)) - continue; // .ARM.exidx sections have a reverse dependency on the InputSection they // have a SHF_LINK_ORDER dependency, this is identified by the sh_link. - InputSectionBase *linkSec = nullptr; - if (sec.sh_link < this->sections.size()) - linkSec = this->sections[sec.sh_link]; - if (!linkSec) - fatal(toString(this) + ": invalid sh_link index: " + Twine(sec.sh_link)); - - InputSection *isec = cast(this->sections[i]); - linkSec->dependentSections.push_back(isec); - if (!isa(linkSec)) - error("a section " + isec->name + - " with SHF_LINK_ORDER should not refer a non-regular section: " + - toString(linkSec)); + if (Sec.sh_flags & SHF_LINK_ORDER) { + InputSectionBase *LinkSec = nullptr; + if (Sec.sh_link < this->Sections.size()) + LinkSec = this->Sections[Sec.sh_link]; + if (!LinkSec) + fatal(toString(this) + + ": invalid sh_link index: " + Twine(Sec.sh_link)); + + InputSection *IS = cast(this->Sections[I]); + LinkSec->DependentSections.push_back(IS); + if (!isa(LinkSec)) + error("a section " + IS->Name + + " with SHF_LINK_ORDER should not refer a non-regular " + "section: " + + toString(LinkSec)); + } } } // For ARM only, to set the EF_ARM_ABI_FLOAT_SOFT or EF_ARM_ABI_FLOAT_HARD // flag in the ELF Header we need to look at Tag_ABI_VFP_args to find out how // the input objects have been compiled. -static void updateARMVFPArgs(const ARMAttributeParser &attributes, - const InputFile *f) { - if (!attributes.hasAttribute(ARMBuildAttrs::ABI_VFP_args)) +static void updateARMVFPArgs(const ARMAttributeParser &Attributes, + const InputFile *F) { + if (!Attributes.hasAttribute(ARMBuildAttrs::ABI_VFP_args)) // If an ABI tag isn't present then it is implicitly given the value of 0 // which maps to ARMBuildAttrs::BaseAAPCS. However many assembler files, // including some in glibc that don't use FP args (and should have value 3) @@ -691,31 +685,31 @@ static void updateARMVFPArgs(const ARMAttributeParser &attributes, // as a clash. return; - unsigned vfpArgs = attributes.getAttributeValue(ARMBuildAttrs::ABI_VFP_args); - ARMVFPArgKind arg; - switch (vfpArgs) { + unsigned VFPArgs = Attributes.getAttributeValue(ARMBuildAttrs::ABI_VFP_args); + ARMVFPArgKind Arg; + switch (VFPArgs) { case ARMBuildAttrs::BaseAAPCS: - arg = ARMVFPArgKind::Base; + Arg = ARMVFPArgKind::Base; break; case ARMBuildAttrs::HardFPAAPCS: - arg = ARMVFPArgKind::VFP; + Arg = ARMVFPArgKind::VFP; break; case ARMBuildAttrs::ToolChainFPPCS: // Tool chain specific convention that conforms to neither AAPCS variant. - arg = ARMVFPArgKind::ToolChain; + Arg = ARMVFPArgKind::ToolChain; break; case ARMBuildAttrs::CompatibleFPAAPCS: // Object compatible with all conventions. return; default: - error(toString(f) + ": unknown Tag_ABI_VFP_args value: " + Twine(vfpArgs)); + error(toString(F) + ": unknown Tag_ABI_VFP_args value: " + Twine(VFPArgs)); return; } // Follow ld.bfd and error if there is a mix of calling conventions. - if (config->armVFPArgs != arg && config->armVFPArgs != ARMVFPArgKind::Default) - error(toString(f) + ": incompatible Tag_ABI_VFP_args"); + if (Config->ARMVFPArgs != Arg && Config->ARMVFPArgs != ARMVFPArgKind::Default) + error(toString(F) + ": incompatible Tag_ABI_VFP_args"); else - config->armVFPArgs = arg; + Config->ARMVFPArgs = Arg; } // The ARM support in lld makes some use of instructions that are not available @@ -727,11 +721,11 @@ static void updateARMVFPArgs(const ARMAttributeParser &attributes, // at compile time. We follow the convention that if at least one input object // is compiled with an architecture that supports these features then lld is // permitted to use them. -static void updateSupportedARMFeatures(const ARMAttributeParser &attributes) { - if (!attributes.hasAttribute(ARMBuildAttrs::CPU_arch)) +static void updateSupportedARMFeatures(const ARMAttributeParser &Attributes) { + if (!Attributes.hasAttribute(ARMBuildAttrs::CPU_arch)) return; - auto arch = attributes.getAttributeValue(ARMBuildAttrs::CPU_arch); - switch (arch) { + auto Arch = Attributes.getAttributeValue(ARMBuildAttrs::CPU_arch); + switch (Arch) { case ARMBuildAttrs::Pre_v4: case ARMBuildAttrs::v4: case ARMBuildAttrs::v4T: @@ -743,19 +737,19 @@ static void updateSupportedARMFeatures(const ARMAttributeParser &attributes) { case ARMBuildAttrs::v6: case ARMBuildAttrs::v6KZ: case ARMBuildAttrs::v6K: - config->armHasBlx = true; + Config->ARMHasBlx = true; // Architectures used in pre-Cortex processors do not support // The J1 = 1 J2 = 1 Thumb branch range extension, with the exception // of Architecture v6T2 (arm1156t2-s and arm1156t2f-s) that do. break; default: // All other Architectures have BLX and extended branch encoding - config->armHasBlx = true; - config->armJ1J2BranchEncoding = true; - if (arch != ARMBuildAttrs::v6_M && arch != ARMBuildAttrs::v6S_M) + Config->ARMHasBlx = true; + Config->ARMJ1J2BranchEncoding = true; + if (Arch != ARMBuildAttrs::v6_M && Arch != ARMBuildAttrs::v6S_M) // All Architectures used in Cortex processors with the exception // of v6-M and v6S-M have the MOVT and MOVW instructions. - config->armHasMovtMovw = true; + Config->ARMHasMovtMovw = true; break; } } @@ -773,126 +767,126 @@ static void updateSupportedARMFeatures(const ARMAttributeParser &attributes) { // certain type. It seems a bit too much to just store a 32-bit value, perhaps // the ABI is unnecessarily complicated. template -static uint32_t readAndFeatures(ObjFile *obj, ArrayRef data) { +static uint32_t readAndFeatures(ObjFile *Obj, ArrayRef Data) { using Elf_Nhdr = typename ELFT::Nhdr; using Elf_Note = typename ELFT::Note; - uint32_t featuresSet = 0; - while (!data.empty()) { + uint32_t FeaturesSet = 0; + while (!Data.empty()) { // Read one NOTE record. - if (data.size() < sizeof(Elf_Nhdr)) - fatal(toString(obj) + ": .note.gnu.property: section too short"); + if (Data.size() < sizeof(Elf_Nhdr)) + fatal(toString(Obj) + ": .note.gnu.property: section too short"); - auto *nhdr = reinterpret_cast(data.data()); - if (data.size() < nhdr->getSize()) - fatal(toString(obj) + ": .note.gnu.property: section too short"); + auto *Nhdr = reinterpret_cast(Data.data()); + if (Data.size() < Nhdr->getSize()) + fatal(toString(Obj) + ": .note.gnu.property: section too short"); - Elf_Note note(*nhdr); - if (nhdr->n_type != NT_GNU_PROPERTY_TYPE_0 || note.getName() != "GNU") { - data = data.slice(nhdr->getSize()); + Elf_Note Note(*Nhdr); + if (Nhdr->n_type != NT_GNU_PROPERTY_TYPE_0 || Note.getName() != "GNU") { + Data = Data.slice(Nhdr->getSize()); continue; } - uint32_t featureAndType = config->emachine == EM_AARCH64 + uint32_t FeatureAndType = Config->EMachine == EM_AARCH64 ? GNU_PROPERTY_AARCH64_FEATURE_1_AND : GNU_PROPERTY_X86_FEATURE_1_AND; // Read a body of a NOTE record, which consists of type-length-value fields. - ArrayRef desc = note.getDesc(); - while (!desc.empty()) { - if (desc.size() < 8) - fatal(toString(obj) + ": .note.gnu.property: section too short"); + ArrayRef Desc = Note.getDesc(); + while (!Desc.empty()) { + if (Desc.size() < 8) + fatal(toString(Obj) + ": .note.gnu.property: section too short"); - uint32_t type = read32le(desc.data()); - uint32_t size = read32le(desc.data() + 4); + uint32_t Type = read32le(Desc.data()); + uint32_t Size = read32le(Desc.data() + 4); - if (type == featureAndType) { + if (Type == FeatureAndType) { // We found a FEATURE_1_AND field. There may be more than one of these // in a .note.gnu.propery section, for a relocatable object we // accumulate the bits set. - featuresSet |= read32le(desc.data() + 8); + FeaturesSet |= read32le(Desc.data() + 8); } // On 64-bit, a payload may be followed by a 4-byte padding to make its // size a multiple of 8. if (ELFT::Is64Bits) - size = alignTo(size, 8); + Size = alignTo(Size, 8); - desc = desc.slice(size + 8); // +8 for Type and Size + Desc = Desc.slice(Size + 8); // +8 for Type and Size } // Go to next NOTE record to look for more FEATURE_1_AND descriptions. - data = data.slice(nhdr->getSize()); + Data = Data.slice(Nhdr->getSize()); } - return featuresSet; + return FeaturesSet; } template -InputSectionBase *ObjFile::getRelocTarget(const Elf_Shdr &sec) { - uint32_t idx = sec.sh_info; - if (idx >= this->sections.size()) - fatal(toString(this) + ": invalid relocated section index: " + Twine(idx)); - InputSectionBase *target = this->sections[idx]; +InputSectionBase *ObjFile::getRelocTarget(const Elf_Shdr &Sec) { + uint32_t Idx = Sec.sh_info; + if (Idx >= this->Sections.size()) + fatal(toString(this) + ": invalid relocated section index: " + Twine(Idx)); + InputSectionBase *Target = this->Sections[Idx]; // Strictly speaking, a relocation section must be included in the // group of the section it relocates. However, LLVM 3.3 and earlier // would fail to do so, so we gracefully handle that case. - if (target == &InputSection::discarded) + if (Target == &InputSection::Discarded) return nullptr; - if (!target) + if (!Target) fatal(toString(this) + ": unsupported relocation reference"); - return target; + return Target; } // Create a regular InputSection class that has the same contents // as a given section. -static InputSection *toRegularSection(MergeInputSection *sec) { - return make(sec->file, sec->flags, sec->type, sec->alignment, - sec->data(), sec->name); +static InputSection *toRegularSection(MergeInputSection *Sec) { + return make(Sec->File, Sec->Flags, Sec->Type, Sec->Alignment, + Sec->data(), Sec->Name); } template -InputSectionBase *ObjFile::createInputSection(const Elf_Shdr &sec) { - StringRef name = getSectionName(sec); +InputSectionBase *ObjFile::createInputSection(const Elf_Shdr &Sec) { + StringRef Name = getSectionName(Sec); - switch (sec.sh_type) { + switch (Sec.sh_type) { case SHT_ARM_ATTRIBUTES: { - if (config->emachine != EM_ARM) + if (Config->EMachine != EM_ARM) break; - ARMAttributeParser attributes; - ArrayRef contents = check(this->getObj().getSectionContents(&sec)); - attributes.Parse(contents, /*isLittle*/ config->ekind == ELF32LEKind); - updateSupportedARMFeatures(attributes); - updateARMVFPArgs(attributes, this); + ARMAttributeParser Attributes; + ArrayRef Contents = check(this->getObj().getSectionContents(&Sec)); + Attributes.Parse(Contents, /*isLittle*/ Config->EKind == ELF32LEKind); + updateSupportedARMFeatures(Attributes); + updateARMVFPArgs(Attributes, this); // FIXME: Retain the first attribute section we see. The eglibc ARM // dynamic loaders require the presence of an attribute section for dlopen // to work. In a full implementation we would merge all attribute sections. - if (in.armAttributes == nullptr) { - in.armAttributes = make(*this, sec, name); - return in.armAttributes; + if (In.ARMAttributes == nullptr) { + In.ARMAttributes = make(*this, Sec, Name); + return In.ARMAttributes; } - return &InputSection::discarded; + return &InputSection::Discarded; } case SHT_LLVM_DEPENDENT_LIBRARIES: { - if (config->relocatable) + if (Config->Relocatable) break; - ArrayRef data = - CHECK(this->getObj().template getSectionContentsAsArray(&sec), this); - if (!data.empty() && data.back() != '\0') { + ArrayRef Data = + CHECK(this->getObj().template getSectionContentsAsArray(&Sec), this); + if (!Data.empty() && Data.back() != '\0') { error(toString(this) + ": corrupted dependent libraries section (unterminated string): " + - name); - return &InputSection::discarded; + Name); + return &InputSection::Discarded; } - for (const char *d = data.begin(), *e = data.end(); d < e;) { - StringRef s(d); - addDependentLibrary(s, this); - d += s.size() + 1; + for (const char *D = Data.begin(), *E = Data.end(); D < E;) { + StringRef S(D); + addDependentLibrary(S, this); + D += S.size() + 1; } - return &InputSection::discarded; + return &InputSection::Discarded; } case SHT_RELA: case SHT_REL: { @@ -901,25 +895,25 @@ InputSectionBase *ObjFile::createInputSection(const Elf_Shdr &sec) { // and the group is discarded, even though it's a violation of the // spec. We handle that situation gracefully by discarding dangling // relocation sections. - InputSectionBase *target = getRelocTarget(sec); - if (!target) + InputSectionBase *Target = getRelocTarget(Sec); + if (!Target) return nullptr; // This section contains relocation information. // If -r is given, we do not interpret or apply relocation // but just copy relocation sections to output. - if (config->relocatable) { - InputSection *relocSec = make(*this, sec, name); + if (Config->Relocatable) { + InputSection *RelocSec = make(*this, Sec, Name); // We want to add a dependency to target, similar like we do for // -emit-relocs below. This is useful for the case when linker script // contains the "/DISCARD/". It is perhaps uncommon to use a script with // -r, but we faced it in the Linux kernel and have to handle such case // and not to crash. - target->dependentSections.push_back(relocSec); - return relocSec; + Target->DependentSections.push_back(RelocSec); + return RelocSec; } - if (target->firstRelocation) + if (Target->FirstRelocation) fatal(toString(this) + ": multiple relocation sections to one section are not supported"); @@ -928,33 +922,33 @@ InputSectionBase *ObjFile::createInputSection(const Elf_Shdr &sec) { // because applying relocations at end of linking changes section // contents. So, we simply handle such sections as non-mergeable ones. // Degrading like this is acceptable because section merging is optional. - if (auto *ms = dyn_cast(target)) { - target = toRegularSection(ms); - this->sections[sec.sh_info] = target; + if (auto *MS = dyn_cast(Target)) { + Target = toRegularSection(MS); + this->Sections[Sec.sh_info] = Target; } - if (sec.sh_type == SHT_RELA) { - ArrayRef rels = CHECK(getObj().relas(&sec), this); - target->firstRelocation = rels.begin(); - target->numRelocations = rels.size(); - target->areRelocsRela = true; + if (Sec.sh_type == SHT_RELA) { + ArrayRef Rels = CHECK(getObj().relas(&Sec), this); + Target->FirstRelocation = Rels.begin(); + Target->NumRelocations = Rels.size(); + Target->AreRelocsRela = true; } else { - ArrayRef rels = CHECK(getObj().rels(&sec), this); - target->firstRelocation = rels.begin(); - target->numRelocations = rels.size(); - target->areRelocsRela = false; + ArrayRef Rels = CHECK(getObj().rels(&Sec), this); + Target->FirstRelocation = Rels.begin(); + Target->NumRelocations = Rels.size(); + Target->AreRelocsRela = false; } - assert(isUInt<31>(target->numRelocations)); + assert(isUInt<31>(Target->NumRelocations)); // Relocation sections processed by the linker are usually removed // from the output, so returning `nullptr` for the normal case. // However, if -emit-relocs is given, we need to leave them in the output. // (Some post link analysis tools need this information.) - if (config->emitRelocs) { - InputSection *relocSec = make(*this, sec, name); + if (Config->EmitRelocs) { + InputSection *RelocSec = make(*this, Sec, Name); // We will not emit relocation section if target was discarded. - target->dependentSections.push_back(relocSec); - return relocSec; + Target->DependentSections.push_back(RelocSec); + return RelocSec; } return nullptr; } @@ -973,8 +967,8 @@ InputSectionBase *ObjFile::createInputSection(const Elf_Shdr &sec) { // explicitly told to do otherwise (by -z execstack). Because the stack // executable-ness is controlled solely by command line options, // .note.GNU-stack sections are simply ignored. - if (name == ".note.GNU-stack") - return &InputSection::discarded; + if (Name == ".note.GNU-stack") + return &InputSection::Discarded; // Object files that use processor features such as Intel Control-Flow // Enforcement (CET) or AArch64 Branch Target Identification BTI, use a @@ -984,31 +978,31 @@ InputSectionBase *ObjFile::createInputSection(const Elf_Shdr &sec) { // Since we merge bitmaps from multiple object files to create a new // .note.gnu.property containing a single AND'ed bitmap, we discard an input // file's .note.gnu.property section. - if (name == ".note.gnu.property") { - ArrayRef contents = check(this->getObj().getSectionContents(&sec)); - this->andFeatures = readAndFeatures(this, contents); - return &InputSection::discarded; + if (Name == ".note.gnu.property") { + ArrayRef Contents = check(this->getObj().getSectionContents(&Sec)); + this->AndFeatures = readAndFeatures(this, Contents); + return &InputSection::Discarded; } // Split stacks is a feature to support a discontiguous stack, // commonly used in the programming language Go. For the details, // see https://gcc.gnu.org/wiki/SplitStacks. An object file compiled // for split stack will include a .note.GNU-split-stack section. - if (name == ".note.GNU-split-stack") { - if (config->relocatable) { + if (Name == ".note.GNU-split-stack") { + if (Config->Relocatable) { error("cannot mix split-stack and non-split-stack in a relocatable link"); - return &InputSection::discarded; + return &InputSection::Discarded; } - this->splitStack = true; - return &InputSection::discarded; + this->SplitStack = true; + return &InputSection::Discarded; } // An object file cmpiled for split stack, but where some of the // functions were compiled with the no_split_stack_attribute will // include a .note.GNU-no-split-stack section. - if (name == ".note.GNU-no-split-stack") { - this->someNoSplitStack = true; - return &InputSection::discarded; + if (Name == ".note.GNU-no-split-stack") { + this->SomeNoSplitStack = true; + return &InputSection::Discarded; } // The linkonce feature is a sort of proto-comdat. Some glibc i386 object @@ -1016,99 +1010,98 @@ InputSectionBase *ObjFile::createInputSection(const Elf_Shdr &sec) { // sections. Drop those sections to avoid duplicate symbol errors. // FIXME: This is glibc PR20543, we should remove this hack once that has been // fixed for a while. - if (name == ".gnu.linkonce.t.__x86.get_pc_thunk.bx" || - name == ".gnu.linkonce.t.__i686.get_pc_thunk.bx") - return &InputSection::discarded; + if (Name == ".gnu.linkonce.t.__x86.get_pc_thunk.bx" || + Name == ".gnu.linkonce.t.__i686.get_pc_thunk.bx") + return &InputSection::Discarded; // If we are creating a new .build-id section, strip existing .build-id // sections so that the output won't have more than one .build-id. // This is not usually a problem because input object files normally don't // have .build-id sections, but you can create such files by // "ld.{bfd,gold,lld} -r --build-id", and we want to guard against it. - if (name == ".note.gnu.build-id" && config->buildId != BuildIdKind::None) - return &InputSection::discarded; + if (Name == ".note.gnu.build-id" && Config->BuildId != BuildIdKind::None) + return &InputSection::Discarded; // The linker merges EH (exception handling) frames and creates a // .eh_frame_hdr section for runtime. So we handle them with a special // class. For relocatable outputs, they are just passed through. - if (name == ".eh_frame" && !config->relocatable) - return make(*this, sec, name); + if (Name == ".eh_frame" && !Config->Relocatable) + return make(*this, Sec, Name); - if (shouldMerge(sec)) - return make(*this, sec, name); - return make(*this, sec, name); + if (shouldMerge(Sec)) + return make(*this, Sec, Name); + return make(*this, Sec, Name); } template -StringRef ObjFile::getSectionName(const Elf_Shdr &sec) { - return CHECK(getObj().getSectionName(&sec, sectionStringTable), this); +StringRef ObjFile::getSectionName(const Elf_Shdr &Sec) { + return CHECK(getObj().getSectionName(&Sec, SectionStringTable), this); } // Initialize this->Symbols. this->Symbols is a parallel array as // its corresponding ELF symbol table. template void ObjFile::initializeSymbols() { - ArrayRef eSyms = this->getELFSyms(); - this->symbols.resize(eSyms.size()); + ArrayRef ESyms = this->getELFSyms(); + this->Symbols.resize(ESyms.size()); // Our symbol table may have already been partially initialized // because of LazyObjFile. - for (size_t i = 0, end = eSyms.size(); i != end; ++i) - if (!this->symbols[i] && eSyms[i].getBinding() != STB_LOCAL) - this->symbols[i] = - symtab->insert(CHECK(eSyms[i].getName(this->stringTable), this)); + for (size_t I = 0, End = ESyms.size(); I != End; ++I) + if (!this->Symbols[I] && ESyms[I].getBinding() != STB_LOCAL) + this->Symbols[I] = + Symtab->insert(CHECK(ESyms[I].getName(this->StringTable), this)); // Fill this->Symbols. A symbol is either local or global. - for (size_t i = 0, end = eSyms.size(); i != end; ++i) { - const Elf_Sym &eSym = eSyms[i]; + for (size_t I = 0, End = ESyms.size(); I != End; ++I) { + const Elf_Sym &ESym = ESyms[I]; // Read symbol attributes. - uint32_t secIdx = getSectionIndex(eSym); - if (secIdx >= this->sections.size()) - fatal(toString(this) + ": invalid section index: " + Twine(secIdx)); - - InputSectionBase *sec = this->sections[secIdx]; - uint8_t binding = eSym.getBinding(); - uint8_t stOther = eSym.st_other; - uint8_t type = eSym.getType(); - uint64_t value = eSym.st_value; - uint64_t size = eSym.st_size; - StringRefZ name = this->stringTable.data() + eSym.st_name; + uint32_t SecIdx = getSectionIndex(ESym); + if (SecIdx >= this->Sections.size()) + fatal(toString(this) + ": invalid section index: " + Twine(SecIdx)); + + InputSectionBase *Sec = this->Sections[SecIdx]; + uint8_t Binding = ESym.getBinding(); + uint8_t StOther = ESym.st_other; + uint8_t Type = ESym.getType(); + uint64_t Value = ESym.st_value; + uint64_t Size = ESym.st_size; + StringRefZ Name = this->StringTable.data() + ESym.st_name; // Handle local symbols. Local symbols are not added to the symbol // table because they are not visible from other object files. We // allocate symbol instances and add their pointers to Symbols. - if (binding == STB_LOCAL) { - if (eSym.getType() == STT_FILE) - sourceFile = CHECK(eSym.getName(this->stringTable), this); + if (Binding == STB_LOCAL) { + if (ESym.getType() == STT_FILE) + SourceFile = CHECK(ESym.getName(this->StringTable), this); - if (this->stringTable.size() <= eSym.st_name) + if (this->StringTable.size() <= ESym.st_name) fatal(toString(this) + ": invalid symbol name offset"); - if (eSym.st_shndx == SHN_UNDEF) - this->symbols[i] = make(this, name, binding, stOther, type); - else if (sec == &InputSection::discarded) - this->symbols[i] = make(this, name, binding, stOther, type, - /*DiscardedSecIdx=*/secIdx); + if (ESym.st_shndx == SHN_UNDEF) + this->Symbols[I] = make(this, Name, Binding, StOther, Type); + else if (Sec == &InputSection::Discarded) + this->Symbols[I] = make(this, Name, Binding, StOther, Type, + /*DiscardedSecIdx=*/SecIdx); else - this->symbols[i] = - make(this, name, binding, stOther, type, value, size, sec); + this->Symbols[I] = + make(this, Name, Binding, StOther, Type, Value, Size, Sec); continue; } // Handle global undefined symbols. - if (eSym.st_shndx == SHN_UNDEF) { - this->symbols[i]->resolve(Undefined{this, name, binding, stOther, type}); - this->symbols[i]->referenced = true; + if (ESym.st_shndx == SHN_UNDEF) { + this->Symbols[I]->resolve(Undefined{this, Name, Binding, StOther, Type}); continue; } // Handle global common symbols. - if (eSym.st_shndx == SHN_COMMON) { - if (value == 0 || value >= UINT32_MAX) - fatal(toString(this) + ": common symbol '" + StringRef(name.data) + - "' has invalid alignment: " + Twine(value)); - this->symbols[i]->resolve( - CommonSymbol{this, name, binding, stOther, type, value, size}); + if (ESym.st_shndx == SHN_COMMON) { + if (Value == 0 || Value >= UINT32_MAX) + fatal(toString(this) + ": common symbol '" + StringRef(Name.Data) + + "' has invalid alignment: " + Twine(Value)); + this->Symbols[I]->resolve( + CommonSymbol{this, Name, Binding, StOther, Type, Value, Size}); continue; } @@ -1117,87 +1110,87 @@ template void ObjFile::initializeSymbols() { // standard, but in practice, a .eh_frame often directly refer // COMDAT member sections, and if a comdat group is discarded, some // defined symbol in a .eh_frame becomes dangling symbols. - if (sec == &InputSection::discarded) { - this->symbols[i]->resolve( - Undefined{this, name, binding, stOther, type, secIdx}); + if (Sec == &InputSection::Discarded) { + this->Symbols[I]->resolve( + Undefined{this, Name, Binding, StOther, Type, SecIdx}); continue; } // Handle global defined symbols. - if (binding == STB_GLOBAL || binding == STB_WEAK || - binding == STB_GNU_UNIQUE) { - this->symbols[i]->resolve( - Defined{this, name, binding, stOther, type, value, size, sec}); + if (Binding == STB_GLOBAL || Binding == STB_WEAK || + Binding == STB_GNU_UNIQUE) { + this->Symbols[I]->resolve( + Defined{this, Name, Binding, StOther, Type, Value, Size, Sec}); continue; } - fatal(toString(this) + ": unexpected binding: " + Twine((int)binding)); + fatal(toString(this) + ": unexpected binding: " + Twine((int)Binding)); } } -ArchiveFile::ArchiveFile(std::unique_ptr &&file) - : InputFile(ArchiveKind, file->getMemoryBufferRef()), - file(std::move(file)) {} +ArchiveFile::ArchiveFile(std::unique_ptr &&File) + : InputFile(ArchiveKind, File->getMemoryBufferRef()), + File(std::move(File)) {} void ArchiveFile::parse() { - for (const Archive::Symbol &sym : file->symbols()) - symtab->addSymbol(LazyArchive{*this, sym}); + for (const Archive::Symbol &Sym : File->symbols()) + Symtab->addSymbol(LazyArchive{*this, Sym}); } // Returns a buffer pointing to a member file containing a given symbol. -void ArchiveFile::fetch(const Archive::Symbol &sym) { - Archive::Child c = - CHECK(sym.getMember(), toString(this) + +void ArchiveFile::fetch(const Archive::Symbol &Sym) { + Archive::Child C = + CHECK(Sym.getMember(), toString(this) + ": could not get the member for symbol " + - toELFString(sym)); + Sym.getName()); - if (!seen.insert(c.getChildOffset()).second) + if (!Seen.insert(C.getChildOffset()).second) return; - MemoryBufferRef mb = - CHECK(c.getMemoryBufferRef(), + MemoryBufferRef MB = + CHECK(C.getMemoryBufferRef(), toString(this) + ": could not get the buffer for the member defining symbol " + - toELFString(sym)); + Sym.getName()); - if (tar && c.getParent()->isThin()) - tar->append(relativeToRoot(CHECK(c.getFullName(), this)), mb.getBuffer()); + if (Tar && C.getParent()->isThin()) + Tar->append(relativeToRoot(CHECK(C.getFullName(), this)), MB.getBuffer()); - InputFile *file = createObjectFile( - mb, getName(), c.getParent()->isThin() ? 0 : c.getChildOffset()); - file->groupId = groupId; - parseFile(file); + InputFile *File = createObjectFile( + MB, getName(), C.getParent()->isThin() ? 0 : C.getChildOffset()); + File->GroupId = GroupId; + parseFile(File); } -unsigned SharedFile::vernauxNum; +unsigned SharedFile::VernauxNum; // Parse the version definitions in the object file if present, and return a // vector whose nth element contains a pointer to the Elf_Verdef for version // identifier n. Version identifiers that are not definitions map to nullptr. template -static std::vector parseVerdefs(const uint8_t *base, - const typename ELFT::Shdr *sec) { - if (!sec) +static std::vector parseVerdefs(const uint8_t *Base, + const typename ELFT::Shdr *Sec) { + if (!Sec) return {}; // We cannot determine the largest verdef identifier without inspecting // every Elf_Verdef, but both bfd and gold assign verdef identifiers // sequentially starting from 1, so we predict that the largest identifier - // will be verdefCount. - unsigned verdefCount = sec->sh_info; - std::vector verdefs(verdefCount + 1); + // will be VerdefCount. + unsigned VerdefCount = Sec->sh_info; + std::vector Verdefs(VerdefCount + 1); // Build the Verdefs array by following the chain of Elf_Verdef objects // from the start of the .gnu.version_d section. - const uint8_t *verdef = base + sec->sh_offset; - for (unsigned i = 0; i != verdefCount; ++i) { - auto *curVerdef = reinterpret_cast(verdef); - verdef += curVerdef->vd_next; - unsigned verdefIndex = curVerdef->vd_ndx; - verdefs.resize(verdefIndex + 1); - verdefs[verdefIndex] = curVerdef; + const uint8_t *Verdef = Base + Sec->sh_offset; + for (unsigned I = 0; I != VerdefCount; ++I) { + auto *CurVerdef = reinterpret_cast(Verdef); + Verdef += CurVerdef->vd_next; + unsigned VerdefIndex = CurVerdef->vd_ndx; + Verdefs.resize(VerdefIndex + 1); + Verdefs[VerdefIndex] = CurVerdef; } - return verdefs; + return Verdefs; } // We do not usually care about alignments of data in shared object @@ -1205,14 +1198,14 @@ static std::vector parseVerdefs(const uint8_t *base, // DSO symbol to point to .bss due to copy relocation, we need to keep // the original alignment requirements. We infer it in this function. template -static uint64_t getAlignment(ArrayRef sections, - const typename ELFT::Sym &sym) { - uint64_t ret = UINT64_MAX; - if (sym.st_value) - ret = 1ULL << countTrailingZeros((uint64_t)sym.st_value); - if (0 < sym.st_shndx && sym.st_shndx < sections.size()) - ret = std::min(ret, sections[sym.st_shndx].sh_addralign); - return (ret > UINT32_MAX) ? 0 : ret; +static uint64_t getAlignment(ArrayRef Sections, + const typename ELFT::Sym &Sym) { + uint64_t Ret = UINT64_MAX; + if (Sym.st_value) + Ret = 1ULL << countTrailingZeros((uint64_t)Sym.st_value); + if (0 < Sym.st_shndx && Sym.st_shndx < Sections.size()) + Ret = std::min(Ret, Sections[Sym.st_shndx].sh_addralign); + return (Ret > UINT32_MAX) ? 0 : Ret; } // Fully parse the shared object file. @@ -1237,156 +1230,156 @@ template void SharedFile::parse() { using Elf_Verdef = typename ELFT::Verdef; using Elf_Versym = typename ELFT::Versym; - ArrayRef dynamicTags; - const ELFFile obj = this->getObj(); - ArrayRef sections = CHECK(obj.sections(), this); + ArrayRef DynamicTags; + const ELFFile Obj = this->getObj(); + ArrayRef Sections = CHECK(Obj.sections(), this); - const Elf_Shdr *versymSec = nullptr; - const Elf_Shdr *verdefSec = nullptr; + const Elf_Shdr *VersymSec = nullptr; + const Elf_Shdr *VerdefSec = nullptr; // Search for .dynsym, .dynamic, .symtab, .gnu.version and .gnu.version_d. - for (const Elf_Shdr &sec : sections) { - switch (sec.sh_type) { + for (const Elf_Shdr &Sec : Sections) { + switch (Sec.sh_type) { default: continue; case SHT_DYNAMIC: - dynamicTags = - CHECK(obj.template getSectionContentsAsArray(&sec), this); + DynamicTags = + CHECK(Obj.template getSectionContentsAsArray(&Sec), this); break; case SHT_GNU_versym: - versymSec = &sec; + VersymSec = &Sec; break; case SHT_GNU_verdef: - verdefSec = &sec; + VerdefSec = &Sec; break; } } - if (versymSec && numELFSyms == 0) { + if (VersymSec && NumELFSyms == 0) { error("SHT_GNU_versym should be associated with symbol table"); return; } - // Search for a DT_SONAME tag to initialize this->soName. - for (const Elf_Dyn &dyn : dynamicTags) { - if (dyn.d_tag == DT_NEEDED) { - uint64_t val = dyn.getVal(); - if (val >= this->stringTable.size()) + // Search for a DT_SONAME tag to initialize this->SoName. + for (const Elf_Dyn &Dyn : DynamicTags) { + if (Dyn.d_tag == DT_NEEDED) { + uint64_t Val = Dyn.getVal(); + if (Val >= this->StringTable.size()) fatal(toString(this) + ": invalid DT_NEEDED entry"); - dtNeeded.push_back(this->stringTable.data() + val); - } else if (dyn.d_tag == DT_SONAME) { - uint64_t val = dyn.getVal(); - if (val >= this->stringTable.size()) + DtNeeded.push_back(this->StringTable.data() + Val); + } else if (Dyn.d_tag == DT_SONAME) { + uint64_t Val = Dyn.getVal(); + if (Val >= this->StringTable.size()) fatal(toString(this) + ": invalid DT_SONAME entry"); - soName = this->stringTable.data() + val; + SoName = this->StringTable.data() + Val; } } // DSOs are uniquified not by filename but by soname. - DenseMap::iterator it; - bool wasInserted; - std::tie(it, wasInserted) = symtab->soNames.try_emplace(soName, this); + DenseMap::iterator It; + bool WasInserted; + std::tie(It, WasInserted) = Symtab->SoNames.try_emplace(SoName, this); // If a DSO appears more than once on the command line with and without // --as-needed, --no-as-needed takes precedence over --as-needed because a // user can add an extra DSO with --no-as-needed to force it to be added to // the dependency list. - it->second->isNeeded |= isNeeded; - if (!wasInserted) + It->second->IsNeeded |= IsNeeded; + if (!WasInserted) return; - sharedFiles.push_back(this); + SharedFiles.push_back(this); - verdefs = parseVerdefs(obj.base(), verdefSec); + Verdefs = parseVerdefs(Obj.base(), VerdefSec); // Parse ".gnu.version" section which is a parallel array for the symbol // table. If a given file doesn't have a ".gnu.version" section, we use // VER_NDX_GLOBAL. - size_t size = numELFSyms - firstGlobal; - std::vector versyms(size, VER_NDX_GLOBAL); - if (versymSec) { - ArrayRef versym = - CHECK(obj.template getSectionContentsAsArray(versymSec), + size_t Size = NumELFSyms - FirstGlobal; + std::vector Versyms(Size, VER_NDX_GLOBAL); + if (VersymSec) { + ArrayRef Versym = + CHECK(Obj.template getSectionContentsAsArray(VersymSec), this) - .slice(firstGlobal); - for (size_t i = 0; i < size; ++i) - versyms[i] = versym[i].vs_index; + .slice(FirstGlobal); + for (size_t I = 0; I < Size; ++I) + Versyms[I] = Versym[I].vs_index; } // System libraries can have a lot of symbols with versions. Using a // fixed buffer for computing the versions name (foo@ver) can save a // lot of allocations. - SmallString<0> versionedNameBuffer; + SmallString<0> VersionedNameBuffer; // Add symbols to the symbol table. - ArrayRef syms = this->getGlobalELFSyms(); - for (size_t i = 0; i < syms.size(); ++i) { - const Elf_Sym &sym = syms[i]; + ArrayRef Syms = this->getGlobalELFSyms(); + for (size_t I = 0; I < Syms.size(); ++I) { + const Elf_Sym &Sym = Syms[I]; // ELF spec requires that all local symbols precede weak or global // symbols in each symbol table, and the index of first non-local symbol // is stored to sh_info. If a local symbol appears after some non-local // symbol, that's a violation of the spec. - StringRef name = CHECK(sym.getName(this->stringTable), this); - if (sym.getBinding() == STB_LOCAL) { - warn("found local symbol '" + name + + StringRef Name = CHECK(Sym.getName(this->StringTable), this); + if (Sym.getBinding() == STB_LOCAL) { + warn("found local symbol '" + Name + "' in global part of symbol table in file " + toString(this)); continue; } - if (sym.isUndefined()) { - Symbol *s = symtab->addSymbol( - Undefined{this, name, sym.getBinding(), sym.st_other, sym.getType()}); - s->exportDynamic = true; + if (Sym.isUndefined()) { + Symbol *S = Symtab->addSymbol( + Undefined{this, Name, Sym.getBinding(), Sym.st_other, Sym.getType()}); + S->ExportDynamic = true; continue; } // MIPS BFD linker puts _gp_disp symbol into DSO files and incorrectly // assigns VER_NDX_LOCAL to this section global symbol. Here is a // workaround for this bug. - uint32_t idx = versyms[i] & ~VERSYM_HIDDEN; - if (config->emachine == EM_MIPS && idx == VER_NDX_LOCAL && - name == "_gp_disp") + uint32_t Idx = Versyms[I] & ~VERSYM_HIDDEN; + if (Config->EMachine == EM_MIPS && Idx == VER_NDX_LOCAL && + Name == "_gp_disp") continue; - uint32_t alignment = getAlignment(sections, sym); - if (!(versyms[i] & VERSYM_HIDDEN)) { - symtab->addSymbol(SharedSymbol{*this, name, sym.getBinding(), - sym.st_other, sym.getType(), sym.st_value, - sym.st_size, alignment, idx}); + uint32_t Alignment = getAlignment(Sections, Sym); + if (!(Versyms[I] & VERSYM_HIDDEN)) { + Symtab->addSymbol(SharedSymbol{*this, Name, Sym.getBinding(), + Sym.st_other, Sym.getType(), Sym.st_value, + Sym.st_size, Alignment, Idx}); } // Also add the symbol with the versioned name to handle undefined symbols // with explicit versions. - if (idx == VER_NDX_GLOBAL) + if (Idx == VER_NDX_GLOBAL) continue; - if (idx >= verdefs.size() || idx == VER_NDX_LOCAL) { - error("corrupt input file: version definition index " + Twine(idx) + - " for symbol " + name + " is out of bounds\n>>> defined in " + + if (Idx >= Verdefs.size() || Idx == VER_NDX_LOCAL) { + error("corrupt input file: version definition index " + Twine(Idx) + + " for symbol " + Name + " is out of bounds\n>>> defined in " + toString(this)); continue; } - StringRef verName = - this->stringTable.data() + - reinterpret_cast(verdefs[idx])->getAux()->vda_name; - versionedNameBuffer.clear(); - name = (name + "@" + verName).toStringRef(versionedNameBuffer); - symtab->addSymbol(SharedSymbol{*this, saver.save(name), sym.getBinding(), - sym.st_other, sym.getType(), sym.st_value, - sym.st_size, alignment, idx}); + StringRef VerName = + this->StringTable.data() + + reinterpret_cast(Verdefs[Idx])->getAux()->vda_name; + VersionedNameBuffer.clear(); + Name = (Name + "@" + VerName).toStringRef(VersionedNameBuffer); + Symtab->addSymbol(SharedSymbol{*this, Saver.save(Name), Sym.getBinding(), + Sym.st_other, Sym.getType(), Sym.st_value, + Sym.st_size, Alignment, Idx}); } } -static ELFKind getBitcodeELFKind(const Triple &t) { - if (t.isLittleEndian()) - return t.isArch64Bit() ? ELF64LEKind : ELF32LEKind; - return t.isArch64Bit() ? ELF64BEKind : ELF32BEKind; +static ELFKind getBitcodeELFKind(const Triple &T) { + if (T.isLittleEndian()) + return T.isArch64Bit() ? ELF64LEKind : ELF32LEKind; + return T.isArch64Bit() ? ELF64BEKind : ELF32BEKind; } -static uint8_t getBitcodeMachineKind(StringRef path, const Triple &t) { - switch (t.getArch()) { +static uint8_t getBitcodeMachineKind(StringRef Path, const Triple &T) { + switch (T.getArch()) { case Triple::aarch64: return EM_AARCH64; case Triple::amdgcn: @@ -1409,28 +1402,25 @@ static uint8_t getBitcodeMachineKind(StringRef path, const Triple &t) { case Triple::ppc64: case Triple::ppc64le: return EM_PPC64; - case Triple::riscv32: - case Triple::riscv64: - return EM_RISCV; case Triple::x86: - return t.isOSIAMCU() ? EM_IAMCU : EM_386; + return T.isOSIAMCU() ? EM_IAMCU : EM_386; case Triple::x86_64: return EM_X86_64; default: - error(path + ": could not infer e_machine from bitcode target triple " + - t.str()); + error(Path + ": could not infer e_machine from bitcode target triple " + + T.str()); return EM_NONE; } } -BitcodeFile::BitcodeFile(MemoryBufferRef mb, StringRef archiveName, - uint64_t offsetInArchive) - : InputFile(BitcodeKind, mb) { - this->archiveName = archiveName; +BitcodeFile::BitcodeFile(MemoryBufferRef MB, StringRef ArchiveName, + uint64_t OffsetInArchive) + : InputFile(BitcodeKind, MB) { + this->ArchiveName = ArchiveName; - std::string path = mb.getBufferIdentifier().str(); - if (config->thinLTOIndexOnly) - path = replaceThinLTOSuffix(mb.getBufferIdentifier()); + std::string Path = MB.getBufferIdentifier().str(); + if (Config->ThinLTOIndexOnly) + Path = replaceThinLTOSuffix(MB.getBufferIdentifier()); // ThinLTO assumes that all MemoryBufferRefs given to it have a unique // name. If two archives define two members with the same name, this @@ -1438,21 +1428,21 @@ BitcodeFile::BitcodeFile(MemoryBufferRef mb, StringRef archiveName, // into consideration at LTO time (which very likely causes undefined // symbols later in the link stage). So we append file offset to make // filename unique. - StringRef name = archiveName.empty() - ? saver.save(path) - : saver.save(archiveName + "(" + path + " at " + - utostr(offsetInArchive) + ")"); - MemoryBufferRef mbref(mb.getBuffer(), name); + StringRef Name = ArchiveName.empty() + ? Saver.save(Path) + : Saver.save(ArchiveName + "(" + Path + " at " + + utostr(OffsetInArchive) + ")"); + MemoryBufferRef MBRef(MB.getBuffer(), Name); - obj = CHECK(lto::InputFile::create(mbref), this); + Obj = CHECK(lto::InputFile::create(MBRef), this); - Triple t(obj->getTargetTriple()); - ekind = getBitcodeELFKind(t); - emachine = getBitcodeMachineKind(mb.getBufferIdentifier(), t); + Triple T(Obj->getTargetTriple()); + EKind = getBitcodeELFKind(T); + EMachine = getBitcodeMachineKind(MB.getBufferIdentifier(), T); } -static uint8_t mapVisibility(GlobalValue::VisibilityTypes gvVisibility) { - switch (gvVisibility) { +static uint8_t mapVisibility(GlobalValue::VisibilityTypes GvVisibility) { + switch (GvVisibility) { case GlobalValue::DefaultVisibility: return STV_DEFAULT; case GlobalValue::HiddenVisibility: @@ -1464,171 +1454,169 @@ static uint8_t mapVisibility(GlobalValue::VisibilityTypes gvVisibility) { } template -static Symbol *createBitcodeSymbol(const std::vector &keptComdats, - const lto::InputFile::Symbol &objSym, - BitcodeFile &f) { - StringRef name = saver.save(objSym.getName()); - uint8_t binding = objSym.isWeak() ? STB_WEAK : STB_GLOBAL; - uint8_t type = objSym.isTLS() ? STT_TLS : STT_NOTYPE; - uint8_t visibility = mapVisibility(objSym.getVisibility()); - bool canOmitFromDynSym = objSym.canBeOmittedFromSymbolTable(); - - int c = objSym.getComdatIndex(); - if (objSym.isUndefined() || (c != -1 && !keptComdats[c])) { - Undefined newSym(&f, name, binding, visibility, type); - if (canOmitFromDynSym) - newSym.exportDynamic = false; - Symbol *ret = symtab->addSymbol(newSym); - ret->referenced = true; - return ret; +static Symbol *createBitcodeSymbol(const std::vector &KeptComdats, + const lto::InputFile::Symbol &ObjSym, + BitcodeFile &F) { + StringRef Name = Saver.save(ObjSym.getName()); + uint8_t Binding = ObjSym.isWeak() ? STB_WEAK : STB_GLOBAL; + uint8_t Type = ObjSym.isTLS() ? STT_TLS : STT_NOTYPE; + uint8_t Visibility = mapVisibility(ObjSym.getVisibility()); + bool CanOmitFromDynSym = ObjSym.canBeOmittedFromSymbolTable(); + + int C = ObjSym.getComdatIndex(); + if (ObjSym.isUndefined() || (C != -1 && !KeptComdats[C])) { + Undefined New(&F, Name, Binding, Visibility, Type); + if (CanOmitFromDynSym) + New.ExportDynamic = false; + return Symtab->addSymbol(New); } - if (objSym.isCommon()) - return symtab->addSymbol( - CommonSymbol{&f, name, binding, visibility, STT_OBJECT, - objSym.getCommonAlignment(), objSym.getCommonSize()}); + if (ObjSym.isCommon()) + return Symtab->addSymbol( + CommonSymbol{&F, Name, Binding, Visibility, STT_OBJECT, + ObjSym.getCommonAlignment(), ObjSym.getCommonSize()}); - Defined newSym(&f, name, binding, visibility, type, 0, 0, nullptr); - if (canOmitFromDynSym) - newSym.exportDynamic = false; - return symtab->addSymbol(newSym); + Defined New(&F, Name, Binding, Visibility, Type, 0, 0, nullptr); + if (CanOmitFromDynSym) + New.ExportDynamic = false; + return Symtab->addSymbol(New); } template void BitcodeFile::parse() { - std::vector keptComdats; - for (StringRef s : obj->getComdatTable()) - keptComdats.push_back( - symtab->comdatGroups.try_emplace(CachedHashStringRef(s), this).second); + std::vector KeptComdats; + for (StringRef S : Obj->getComdatTable()) + KeptComdats.push_back( + Symtab->ComdatGroups.try_emplace(CachedHashStringRef(S), this).second); - for (const lto::InputFile::Symbol &objSym : obj->symbols()) - symbols.push_back(createBitcodeSymbol(keptComdats, objSym, *this)); + for (const lto::InputFile::Symbol &ObjSym : Obj->symbols()) + Symbols.push_back(createBitcodeSymbol(KeptComdats, ObjSym, *this)); - for (auto l : obj->getDependentLibraries()) - addDependentLibrary(l, this); + for (auto L : Obj->getDependentLibraries()) + addDependentLibrary(L, this); } void BinaryFile::parse() { - ArrayRef data = arrayRefFromStringRef(mb.getBuffer()); - auto *section = make(this, SHF_ALLOC | SHF_WRITE, SHT_PROGBITS, - 8, data, ".data"); - sections.push_back(section); + ArrayRef Data = arrayRefFromStringRef(MB.getBuffer()); + auto *Section = make(this, SHF_ALLOC | SHF_WRITE, SHT_PROGBITS, + 8, Data, ".data"); + Sections.push_back(Section); // For each input file foo that is embedded to a result as a binary // blob, we define _binary_foo_{start,end,size} symbols, so that // user programs can access blobs by name. Non-alphanumeric // characters in a filename are replaced with underscore. - std::string s = "_binary_" + mb.getBufferIdentifier().str(); - for (size_t i = 0; i < s.size(); ++i) - if (!isAlnum(s[i])) - s[i] = '_'; - - symtab->addSymbol(Defined{nullptr, saver.save(s + "_start"), STB_GLOBAL, - STV_DEFAULT, STT_OBJECT, 0, 0, section}); - symtab->addSymbol(Defined{nullptr, saver.save(s + "_end"), STB_GLOBAL, - STV_DEFAULT, STT_OBJECT, data.size(), 0, section}); - symtab->addSymbol(Defined{nullptr, saver.save(s + "_size"), STB_GLOBAL, - STV_DEFAULT, STT_OBJECT, data.size(), 0, nullptr}); + std::string S = "_binary_" + MB.getBufferIdentifier().str(); + for (size_t I = 0; I < S.size(); ++I) + if (!isAlnum(S[I])) + S[I] = '_'; + + Symtab->addSymbol(Defined{nullptr, Saver.save(S + "_start"), STB_GLOBAL, + STV_DEFAULT, STT_OBJECT, 0, 0, Section}); + Symtab->addSymbol(Defined{nullptr, Saver.save(S + "_end"), STB_GLOBAL, + STV_DEFAULT, STT_OBJECT, Data.size(), 0, Section}); + Symtab->addSymbol(Defined{nullptr, Saver.save(S + "_size"), STB_GLOBAL, + STV_DEFAULT, STT_OBJECT, Data.size(), 0, nullptr}); } -InputFile *elf::createObjectFile(MemoryBufferRef mb, StringRef archiveName, - uint64_t offsetInArchive) { - if (isBitcode(mb)) - return make(mb, archiveName, offsetInArchive); +InputFile *elf::createObjectFile(MemoryBufferRef MB, StringRef ArchiveName, + uint64_t OffsetInArchive) { + if (isBitcode(MB)) + return make(MB, ArchiveName, OffsetInArchive); - switch (getELFKind(mb, archiveName)) { + switch (getELFKind(MB, ArchiveName)) { case ELF32LEKind: - return make>(mb, archiveName); + return make>(MB, ArchiveName); case ELF32BEKind: - return make>(mb, archiveName); + return make>(MB, ArchiveName); case ELF64LEKind: - return make>(mb, archiveName); + return make>(MB, ArchiveName); case ELF64BEKind: - return make>(mb, archiveName); + return make>(MB, ArchiveName); default: llvm_unreachable("getELFKind"); } } void LazyObjFile::fetch() { - if (mb.getBuffer().empty()) + if (MB.getBuffer().empty()) return; - InputFile *file = createObjectFile(mb, archiveName, offsetInArchive); - file->groupId = groupId; + InputFile *File = createObjectFile(MB, ArchiveName, OffsetInArchive); + File->GroupId = GroupId; - mb = {}; + MB = {}; // Copy symbol vector so that the new InputFile doesn't have to // insert the same defined symbols to the symbol table again. - file->symbols = std::move(symbols); + File->Symbols = std::move(Symbols); - parseFile(file); + parseFile(File); } template void LazyObjFile::parse() { using Elf_Sym = typename ELFT::Sym; // A lazy object file wraps either a bitcode file or an ELF file. - if (isBitcode(this->mb)) { - std::unique_ptr obj = - CHECK(lto::InputFile::create(this->mb), this); - for (const lto::InputFile::Symbol &sym : obj->symbols()) { - if (sym.isUndefined()) + if (isBitcode(this->MB)) { + std::unique_ptr Obj = + CHECK(lto::InputFile::create(this->MB), this); + for (const lto::InputFile::Symbol &Sym : Obj->symbols()) { + if (Sym.isUndefined()) continue; - symtab->addSymbol(LazyObject{*this, saver.save(sym.getName())}); + Symtab->addSymbol(LazyObject{*this, Saver.save(Sym.getName())}); } return; } - if (getELFKind(this->mb, archiveName) != config->ekind) { - error("incompatible file: " + this->mb.getBufferIdentifier()); + if (getELFKind(this->MB, ArchiveName) != Config->EKind) { + error("incompatible file: " + this->MB.getBufferIdentifier()); return; } // Find a symbol table. - ELFFile obj = check(ELFFile::create(mb.getBuffer())); - ArrayRef sections = CHECK(obj.sections(), this); + ELFFile Obj = check(ELFFile::create(MB.getBuffer())); + ArrayRef Sections = CHECK(Obj.sections(), this); - for (const typename ELFT::Shdr &sec : sections) { - if (sec.sh_type != SHT_SYMTAB) + for (const typename ELFT::Shdr &Sec : Sections) { + if (Sec.sh_type != SHT_SYMTAB) continue; // A symbol table is found. - ArrayRef eSyms = CHECK(obj.symbols(&sec), this); - uint32_t firstGlobal = sec.sh_info; - StringRef strtab = CHECK(obj.getStringTableForSymtab(sec, sections), this); - this->symbols.resize(eSyms.size()); + ArrayRef ESyms = CHECK(Obj.symbols(&Sec), this); + uint32_t FirstGlobal = Sec.sh_info; + StringRef Strtab = CHECK(Obj.getStringTableForSymtab(Sec, Sections), this); + this->Symbols.resize(ESyms.size()); // Get existing symbols or insert placeholder symbols. - for (size_t i = firstGlobal, end = eSyms.size(); i != end; ++i) - if (eSyms[i].st_shndx != SHN_UNDEF) - this->symbols[i] = symtab->insert(CHECK(eSyms[i].getName(strtab), this)); + for (size_t I = FirstGlobal, End = ESyms.size(); I != End; ++I) + if (ESyms[I].st_shndx != SHN_UNDEF) + this->Symbols[I] = Symtab->insert(CHECK(ESyms[I].getName(Strtab), this)); // Replace existing symbols with LazyObject symbols. // // resolve() may trigger this->fetch() if an existing symbol is an // undefined symbol. If that happens, this LazyObjFile has served // its purpose, and we can exit from the loop early. - for (Symbol *sym : this->symbols) { - if (!sym) + for (Symbol *Sym : this->Symbols) { + if (!Sym) continue; - sym->resolve(LazyObject{*this, sym->getName()}); + Sym->resolve(LazyObject{*this, Sym->getName()}); // MemoryBuffer is emptied if this file is instantiated as ObjFile. - if (mb.getBuffer().empty()) + if (MB.getBuffer().empty()) return; } return; } } -std::string elf::replaceThinLTOSuffix(StringRef path) { - StringRef suffix = config->thinLTOObjectSuffixReplace.first; - StringRef repl = config->thinLTOObjectSuffixReplace.second; +std::string elf::replaceThinLTOSuffix(StringRef Path) { + StringRef Suffix = Config->ThinLTOObjectSuffixReplace.first; + StringRef Repl = Config->ThinLTOObjectSuffixReplace.second; - if (path.consume_back(suffix)) - return (path + repl).str(); - return path; + if (Path.consume_back(Suffix)) + return (Path + Repl).str(); + return Path; } template void BitcodeFile::parse(); diff --git a/lld/ELF/InputFiles.h b/lld/ELF/InputFiles.h index 5ccc3d402b3761..588d59ab2351a1 100644 --- a/lld/ELF/InputFiles.h +++ b/lld/ELF/InputFiles.h @@ -39,7 +39,7 @@ class InputSectionBase; } // Returns "", "foo.a(bar.o)" or "baz.o". -std::string toString(const elf::InputFile *f); +std::string toString(const elf::InputFile *F); namespace elf { @@ -49,13 +49,13 @@ class Symbol; // If -reproduce option is given, all input files are written // to this tar archive. -extern std::unique_ptr tar; +extern std::unique_ptr Tar; // Opens a given file. -llvm::Optional readFile(StringRef path); +llvm::Optional readFile(StringRef Path); // Add symbols in File to the symbol table. -void parseFile(InputFile *file); +void parseFile(InputFile *File); // The root class of input files. class InputFile { @@ -69,21 +69,21 @@ class InputFile { BinaryKind, }; - Kind kind() const { return fileKind; } + Kind kind() const { return FileKind; } bool isElf() const { - Kind k = kind(); - return k == ObjKind || k == SharedKind; + Kind K = kind(); + return K == ObjKind || K == SharedKind; } - StringRef getName() const { return mb.getBufferIdentifier(); } - MemoryBufferRef mb; + StringRef getName() const { return MB.getBufferIdentifier(); } + MemoryBufferRef MB; // Returns sections. It is a runtime error to call this function // on files that don't have the notion of sections. ArrayRef getSections() const { - assert(fileKind == ObjKind || fileKind == BinaryKind); - return sections; + assert(FileKind == ObjKind || FileKind == BinaryKind); + return Sections; } // Returns object file symbols. It is a runtime error to call this @@ -91,35 +91,35 @@ class InputFile { ArrayRef getSymbols() { return getMutableSymbols(); } MutableArrayRef getMutableSymbols() { - assert(fileKind == BinaryKind || fileKind == ObjKind || - fileKind == BitcodeKind); - return symbols; + assert(FileKind == BinaryKind || FileKind == ObjKind || + FileKind == BitcodeKind); + return Symbols; } // Filename of .a which contained this file. If this file was // not in an archive file, it is the empty string. We use this // string for creating error messages. - std::string archiveName; + std::string ArchiveName; // If this is an architecture-specific file, the following members // have ELF type (i.e. ELF{32,64}{LE,BE}) and target machine type. - ELFKind ekind = ELFNoneKind; - uint16_t emachine = llvm::ELF::EM_NONE; - uint8_t osabi = 0; - uint8_t abiVersion = 0; + ELFKind EKind = ELFNoneKind; + uint16_t EMachine = llvm::ELF::EM_NONE; + uint8_t OSABI = 0; + uint8_t ABIVersion = 0; // Cache for toString(). Only toString() should use this member. - mutable std::string toStringCache; + mutable std::string ToStringCache; - std::string getSrcMsg(const Symbol &sym, InputSectionBase &sec, - uint64_t offset); + std::string getSrcMsg(const Symbol &Sym, InputSectionBase &Sec, + uint64_t Offset); // True if this is an argument for --just-symbols. Usually false. - bool justSymbols = false; + bool JustSymbols = false; - // outSecOff of .got2 in the current file. This is used by PPC32 -fPIC/-fPIE + // OutSecOff of .got2 in the current file. This is used by PPC32 -fPIC/-fPIE // to compute offsets in PLT call stubs. - uint32_t ppc32Got2OutSecOff = 0; + uint32_t PPC32Got2OutSecOff = 0; // On PPC64 we need to keep track of which files contain small code model // relocations that access the .toc section. To minimize the chance of a @@ -130,56 +130,56 @@ class InputFile { // code model relocations support immediates in the range [-0x8000, 0x7FFC], // making the addressable range relative to the toc pointer // [.got, .got + 0xFFFC]. - bool ppc64SmallCodeModelTocRelocs = false; + bool PPC64SmallCodeModelTocRelocs = false; - // groupId is used for --warn-backrefs which is an optional error + // GroupId is used for --warn-backrefs which is an optional error // checking feature. All files within the same --{start,end}-group or // --{start,end}-lib get the same group ID. Otherwise, each file gets a new // group ID. For more info, see checkDependency() in SymbolTable.cpp. - uint32_t groupId; - static bool isInGroup; - static uint32_t nextGroupId; + uint32_t GroupId; + static bool IsInGroup; + static uint32_t NextGroupId; // Index of MIPS GOT built for this file. - llvm::Optional mipsGotIndex; + llvm::Optional MipsGotIndex; - std::vector symbols; + std::vector Symbols; protected: - InputFile(Kind k, MemoryBufferRef m); - std::vector sections; + InputFile(Kind K, MemoryBufferRef M); + std::vector Sections; private: - const Kind fileKind; + const Kind FileKind; }; class ELFFileBase : public InputFile { public: - ELFFileBase(Kind k, MemoryBufferRef m); - static bool classof(const InputFile *f) { return f->isElf(); } + ELFFileBase(Kind K, MemoryBufferRef M); + static bool classof(const InputFile *F) { return F->isElf(); } template llvm::object::ELFFile getObj() const { - return check(llvm::object::ELFFile::create(mb.getBuffer())); + return check(llvm::object::ELFFile::create(MB.getBuffer())); } - StringRef getStringTable() const { return stringTable; } + StringRef getStringTable() const { return StringTable; } template typename ELFT::SymRange getELFSyms() const { return typename ELFT::SymRange( - reinterpret_cast(elfSyms), numELFSyms); + reinterpret_cast(ELFSyms), NumELFSyms); } template typename ELFT::SymRange getGlobalELFSyms() const { - return getELFSyms().slice(firstGlobal); + return getELFSyms().slice(FirstGlobal); } protected: // Initializes this class's member variables. template void init(); - const void *elfSyms = nullptr; - size_t numELFSyms = 0; - uint32_t firstGlobal = 0; - StringRef stringTable; + const void *ELFSyms = nullptr; + size_t NumELFSyms = 0; + uint32_t FirstGlobal = 0; + StringRef StringTable; }; // .o file. @@ -192,7 +192,7 @@ template class ObjFile : public ELFFileBase { using Elf_CGProfile = typename ELFT::CGProfile; public: - static bool classof(const InputFile *f) { return f->kind() == ObjKind; } + static bool classof(const InputFile *F) { return F->kind() == ObjKind; } llvm::object::ELFFile getObj() const { return this->ELFFileBase::getObj(); @@ -201,67 +201,67 @@ template class ObjFile : public ELFFileBase { ArrayRef getLocalSymbols(); ArrayRef getGlobalSymbols(); - ObjFile(MemoryBufferRef m, StringRef archiveName) : ELFFileBase(ObjKind, m) { - this->archiveName = archiveName; + ObjFile(MemoryBufferRef M, StringRef ArchiveName) : ELFFileBase(ObjKind, M) { + this->ArchiveName = ArchiveName; } - void parse(bool ignoreComdats = false); + void parse(bool IgnoreComdats = false); - StringRef getShtGroupSignature(ArrayRef sections, - const Elf_Shdr &sec); + StringRef getShtGroupSignature(ArrayRef Sections, + const Elf_Shdr &Sec); - Symbol &getSymbol(uint32_t symbolIndex) const { - if (symbolIndex >= this->symbols.size()) + Symbol &getSymbol(uint32_t SymbolIndex) const { + if (SymbolIndex >= this->Symbols.size()) fatal(toString(this) + ": invalid symbol index"); - return *this->symbols[symbolIndex]; + return *this->Symbols[SymbolIndex]; } - uint32_t getSectionIndex(const Elf_Sym &sym) const; + uint32_t getSectionIndex(const Elf_Sym &Sym) const; - template Symbol &getRelocTargetSym(const RelT &rel) const { - uint32_t symIndex = rel.getSymbol(config->isMips64EL); - return getSymbol(symIndex); + template Symbol &getRelocTargetSym(const RelT &Rel) const { + uint32_t SymIndex = Rel.getSymbol(Config->IsMips64EL); + return getSymbol(SymIndex); } llvm::Optional getDILineInfo(InputSectionBase *, uint64_t); - llvm::Optional> getVariableLoc(StringRef name); + llvm::Optional> getVariableLoc(StringRef Name); // MIPS GP0 value defined by this file. This value represents the gp value // used to create the relocatable object and required to support // R_MIPS_GPREL16 / R_MIPS_GPREL32 relocations. - uint32_t mipsGp0 = 0; + uint32_t MipsGp0 = 0; - uint32_t andFeatures = 0; + uint32_t AndFeatures = 0; // Name of source file obtained from STT_FILE symbol value, // or empty string if there is no such symbol in object file // symbol table. - StringRef sourceFile; + StringRef SourceFile; // True if the file defines functions compiled with // -fsplit-stack. Usually false. - bool splitStack = false; + bool SplitStack = false; // True if the file defines functions compiled with -fsplit-stack, // but had one or more functions with the no_split_stack attribute. - bool someNoSplitStack = false; + bool SomeNoSplitStack = false; // Pointer to this input file's .llvm_addrsig section, if it has one. - const Elf_Shdr *addrsigSec = nullptr; + const Elf_Shdr *AddrsigSec = nullptr; // SHT_LLVM_CALL_GRAPH_PROFILE table - ArrayRef cgProfile; + ArrayRef CGProfile; private: - void initializeSections(bool ignoreComdats); + void initializeSections(bool IgnoreComdats); void initializeSymbols(); void initializeJustSymbols(); void initializeDwarf(); - InputSectionBase *getRelocTarget(const Elf_Shdr &sec); - InputSectionBase *createInputSection(const Elf_Shdr &sec); - StringRef getSectionName(const Elf_Shdr &sec); + InputSectionBase *getRelocTarget(const Elf_Shdr &Sec); + InputSectionBase *createInputSection(const Elf_Shdr &Sec); + StringRef getSectionName(const Elf_Shdr &Sec); - bool shouldMerge(const Elf_Shdr &sec); + bool shouldMerge(const Elf_Shdr &Sec); // Each ELF symbol contains a section index which the symbol belongs to. // However, because the number of bits dedicated for that is limited, a @@ -275,24 +275,24 @@ template class ObjFile : public ELFFileBase { // // The following variable contains the contents of .symtab_shndx. // If the section does not exist (which is common), the array is empty. - ArrayRef shndxTable; + ArrayRef ShndxTable; // .shstrtab contents. - StringRef sectionStringTable; + StringRef SectionStringTable; // Debugging information to retrieve source file and line for error // reporting. Linker may find reasonable number of errors in a // single object file, so we cache debugging information in order to // parse it only once for each object file we link. - std::unique_ptr dwarf; - std::vector lineTables; + std::unique_ptr Dwarf; + std::vector LineTables; struct VarLoc { - const llvm::DWARFDebugLine::LineTable *lt; - unsigned file; - unsigned line; + const llvm::DWARFDebugLine::LineTable *LT; + unsigned File; + unsigned Line; }; - llvm::DenseMap variableLoc; - llvm::once_flag initDwarfLine; + llvm::DenseMap VariableLoc; + llvm::once_flag InitDwarfLine; }; // LazyObjFile is analogous to ArchiveFile in the sense that @@ -304,100 +304,100 @@ template class ObjFile : public ELFFileBase { // archive file semantics. class LazyObjFile : public InputFile { public: - LazyObjFile(MemoryBufferRef m, StringRef archiveName, - uint64_t offsetInArchive) - : InputFile(LazyObjKind, m), offsetInArchive(offsetInArchive) { - this->archiveName = archiveName; + LazyObjFile(MemoryBufferRef M, StringRef ArchiveName, + uint64_t OffsetInArchive) + : InputFile(LazyObjKind, M), OffsetInArchive(OffsetInArchive) { + this->ArchiveName = ArchiveName; } - static bool classof(const InputFile *f) { return f->kind() == LazyObjKind; } + static bool classof(const InputFile *F) { return F->kind() == LazyObjKind; } template void parse(); void fetch(); private: - uint64_t offsetInArchive; + uint64_t OffsetInArchive; }; // An ArchiveFile object represents a .a file. class ArchiveFile : public InputFile { public: - explicit ArchiveFile(std::unique_ptr &&file); - static bool classof(const InputFile *f) { return f->kind() == ArchiveKind; } + explicit ArchiveFile(std::unique_ptr &&File); + static bool classof(const InputFile *F) { return F->kind() == ArchiveKind; } void parse(); // Pulls out an object file that contains a definition for Sym and // returns it. If the same file was instantiated before, this // function does nothing (so we don't instantiate the same file // more than once.) - void fetch(const Archive::Symbol &sym); + void fetch(const Archive::Symbol &Sym); private: - std::unique_ptr file; - llvm::DenseSet seen; + std::unique_ptr File; + llvm::DenseSet Seen; }; class BitcodeFile : public InputFile { public: - BitcodeFile(MemoryBufferRef m, StringRef archiveName, - uint64_t offsetInArchive); - static bool classof(const InputFile *f) { return f->kind() == BitcodeKind; } + BitcodeFile(MemoryBufferRef M, StringRef ArchiveName, + uint64_t OffsetInArchive); + static bool classof(const InputFile *F) { return F->kind() == BitcodeKind; } template void parse(); - std::unique_ptr obj; + std::unique_ptr Obj; }; // .so file. class SharedFile : public ELFFileBase { public: - SharedFile(MemoryBufferRef m, StringRef defaultSoName) - : ELFFileBase(SharedKind, m), soName(defaultSoName), - isNeeded(!config->asNeeded) {} + SharedFile(MemoryBufferRef M, StringRef DefaultSoName) + : ELFFileBase(SharedKind, M), SoName(DefaultSoName), + IsNeeded(!Config->AsNeeded) {} // This is actually a vector of Elf_Verdef pointers. - std::vector verdefs; + std::vector Verdefs; // If the output file needs Elf_Verneed data structures for this file, this is // a vector of Elf_Vernaux version identifiers that map onto the entries in // Verdefs, otherwise it is empty. - std::vector vernauxs; + std::vector Vernauxs; - static unsigned vernauxNum; + static unsigned VernauxNum; - std::vector dtNeeded; - std::string soName; + std::vector DtNeeded; + std::string SoName; - static bool classof(const InputFile *f) { return f->kind() == SharedKind; } + static bool classof(const InputFile *F) { return F->kind() == SharedKind; } template void parse(); // Used for --no-allow-shlib-undefined. - bool allNeededIsKnown; + bool AllNeededIsKnown; // Used for --as-needed - bool isNeeded; + bool IsNeeded; }; class BinaryFile : public InputFile { public: - explicit BinaryFile(MemoryBufferRef m) : InputFile(BinaryKind, m) {} - static bool classof(const InputFile *f) { return f->kind() == BinaryKind; } + explicit BinaryFile(MemoryBufferRef M) : InputFile(BinaryKind, M) {} + static bool classof(const InputFile *F) { return F->kind() == BinaryKind; } void parse(); }; -InputFile *createObjectFile(MemoryBufferRef mb, StringRef archiveName = "", - uint64_t offsetInArchive = 0); +InputFile *createObjectFile(MemoryBufferRef MB, StringRef ArchiveName = "", + uint64_t OffsetInArchive = 0); -inline bool isBitcode(MemoryBufferRef mb) { - return identify_magic(mb.getBuffer()) == llvm::file_magic::bitcode; +inline bool isBitcode(MemoryBufferRef MB) { + return identify_magic(MB.getBuffer()) == llvm::file_magic::bitcode; } -std::string replaceThinLTOSuffix(StringRef path); +std::string replaceThinLTOSuffix(StringRef Path); -extern std::vector binaryFiles; -extern std::vector bitcodeFiles; -extern std::vector lazyObjFiles; -extern std::vector objectFiles; -extern std::vector sharedFiles; +extern std::vector BinaryFiles; +extern std::vector BitcodeFiles; +extern std::vector LazyObjFiles; +extern std::vector ObjectFiles; +extern std::vector SharedFiles; } // namespace elf } // namespace lld diff --git a/lld/ELF/InputSection.cpp b/lld/ELF/InputSection.cpp index 813423bb5e74fb..d077c017ca7183 100644 --- a/lld/ELF/InputSection.cpp +++ b/lld/ELF/InputSection.cpp @@ -40,52 +40,52 @@ using namespace llvm::sys; using namespace lld; using namespace lld::elf; -std::vector elf::inputSections; +std::vector elf::InputSections; // Returns a string to construct an error message. -std::string lld::toString(const InputSectionBase *sec) { - return (toString(sec->file) + ":(" + sec->name + ")").str(); +std::string lld::toString(const InputSectionBase *Sec) { + return (toString(Sec->File) + ":(" + Sec->Name + ")").str(); } template -static ArrayRef getSectionContents(ObjFile &file, - const typename ELFT::Shdr &hdr) { - if (hdr.sh_type == SHT_NOBITS) - return makeArrayRef(nullptr, hdr.sh_size); - return check(file.getObj().getSectionContents(&hdr)); +static ArrayRef getSectionContents(ObjFile &File, + const typename ELFT::Shdr &Hdr) { + if (Hdr.sh_type == SHT_NOBITS) + return makeArrayRef(nullptr, Hdr.sh_size); + return check(File.getObj().getSectionContents(&Hdr)); } -InputSectionBase::InputSectionBase(InputFile *file, uint64_t flags, - uint32_t type, uint64_t entsize, - uint32_t link, uint32_t info, - uint32_t alignment, ArrayRef data, - StringRef name, Kind sectionKind) - : SectionBase(sectionKind, name, flags, entsize, alignment, type, info, - link), - file(file), rawData(data) { +InputSectionBase::InputSectionBase(InputFile *File, uint64_t Flags, + uint32_t Type, uint64_t Entsize, + uint32_t Link, uint32_t Info, + uint32_t Alignment, ArrayRef Data, + StringRef Name, Kind SectionKind) + : SectionBase(SectionKind, Name, Flags, Entsize, Alignment, Type, Info, + Link), + File(File), RawData(Data) { // In order to reduce memory allocation, we assume that mergeable // sections are smaller than 4 GiB, which is not an unreasonable // assumption as of 2017. - if (sectionKind == SectionBase::Merge && rawData.size() > UINT32_MAX) + if (SectionKind == SectionBase::Merge && RawData.size() > UINT32_MAX) error(toString(this) + ": section too large"); - numRelocations = 0; - areRelocsRela = false; + NumRelocations = 0; + AreRelocsRela = false; // The ELF spec states that a value of 0 means the section has // no alignment constraits. - uint32_t v = std::max(alignment, 1); - if (!isPowerOf2_64(v)) + uint32_t V = std::max(Alignment, 1); + if (!isPowerOf2_64(V)) fatal(toString(this) + ": sh_addralign is not a power of 2"); - this->alignment = v; + this->Alignment = V; // In ELF, each section can be compressed by zlib, and if compressed, // section name may be mangled by appending "z" (e.g. ".zdebug_info"). // If that's the case, demangle section name so that we can handle a // section as if it weren't compressed. - if ((flags & SHF_COMPRESSED) || name.startswith(".zdebug")) { + if ((Flags & SHF_COMPRESSED) || Name.startswith(".zdebug")) { if (!zlib::isAvailable()) - error(toString(file) + ": contains a compressed section, " + + error(toString(File) + ": contains a compressed section, " + "but zlib is not available"); parseCompressedHeader(); } @@ -94,11 +94,11 @@ InputSectionBase::InputSectionBase(InputFile *file, uint64_t flags, // Drop SHF_GROUP bit unless we are producing a re-linkable object file. // SHF_GROUP is a marker that a section belongs to some comdat group. // That flag doesn't make sense in an executable. -static uint64_t getFlags(uint64_t flags) { - flags &= ~(uint64_t)SHF_INFO_LINK; - if (!config->relocatable) - flags &= ~(uint64_t)SHF_GROUP; - return flags; +static uint64_t getFlags(uint64_t Flags) { + Flags &= ~(uint64_t)SHF_INFO_LINK; + if (!Config->Relocatable) + Flags &= ~(uint64_t)SHF_GROUP; + return Flags; } // GNU assembler 2.24 and LLVM 4.0.0's MC (the newest release as of @@ -111,212 +111,212 @@ static uint64_t getFlags(uint64_t flags) { // // This function forces SHT_{INIT,FINI}_ARRAY so that we can handle // incorrect inputs as if they were correct from the beginning. -static uint64_t getType(uint64_t type, StringRef name) { - if (type == SHT_PROGBITS && name.startswith(".init_array.")) +static uint64_t getType(uint64_t Type, StringRef Name) { + if (Type == SHT_PROGBITS && Name.startswith(".init_array.")) return SHT_INIT_ARRAY; - if (type == SHT_PROGBITS && name.startswith(".fini_array.")) + if (Type == SHT_PROGBITS && Name.startswith(".fini_array.")) return SHT_FINI_ARRAY; - return type; + return Type; } template -InputSectionBase::InputSectionBase(ObjFile &file, - const typename ELFT::Shdr &hdr, - StringRef name, Kind sectionKind) - : InputSectionBase(&file, getFlags(hdr.sh_flags), - getType(hdr.sh_type, name), hdr.sh_entsize, hdr.sh_link, - hdr.sh_info, hdr.sh_addralign, - getSectionContents(file, hdr), name, sectionKind) { +InputSectionBase::InputSectionBase(ObjFile &File, + const typename ELFT::Shdr &Hdr, + StringRef Name, Kind SectionKind) + : InputSectionBase(&File, getFlags(Hdr.sh_flags), + getType(Hdr.sh_type, Name), Hdr.sh_entsize, Hdr.sh_link, + Hdr.sh_info, Hdr.sh_addralign, + getSectionContents(File, Hdr), Name, SectionKind) { // We reject object files having insanely large alignments even though // they are allowed by the spec. I think 4GB is a reasonable limitation. // We might want to relax this in the future. - if (hdr.sh_addralign > UINT32_MAX) - fatal(toString(&file) + ": section sh_addralign is too large"); + if (Hdr.sh_addralign > UINT32_MAX) + fatal(toString(&File) + ": section sh_addralign is too large"); } size_t InputSectionBase::getSize() const { - if (auto *s = dyn_cast(this)) - return s->getSize(); - if (uncompressedSize >= 0) - return uncompressedSize; - return rawData.size(); + if (auto *S = dyn_cast(this)) + return S->getSize(); + if (UncompressedSize >= 0) + return UncompressedSize; + return RawData.size(); } void InputSectionBase::uncompress() const { - size_t size = uncompressedSize; - char *uncompressedBuf; + size_t Size = UncompressedSize; + char *UncompressedBuf; { - static std::mutex mu; - std::lock_guard lock(mu); - uncompressedBuf = bAlloc.Allocate(size); + static std::mutex Mu; + std::lock_guard Lock(Mu); + UncompressedBuf = BAlloc.Allocate(Size); } - if (Error e = zlib::uncompress(toStringRef(rawData), uncompressedBuf, size)) + if (Error E = zlib::uncompress(toStringRef(RawData), UncompressedBuf, Size)) fatal(toString(this) + - ": uncompress failed: " + llvm::toString(std::move(e))); - rawData = makeArrayRef((uint8_t *)uncompressedBuf, size); - uncompressedSize = -1; + ": uncompress failed: " + llvm::toString(std::move(E))); + RawData = makeArrayRef((uint8_t *)UncompressedBuf, Size); + UncompressedSize = -1; } uint64_t InputSectionBase::getOffsetInFile() const { - const uint8_t *fileStart = (const uint8_t *)file->mb.getBufferStart(); - const uint8_t *secStart = data().begin(); - return secStart - fileStart; + const uint8_t *FileStart = (const uint8_t *)File->MB.getBufferStart(); + const uint8_t *SecStart = data().begin(); + return SecStart - FileStart; } -uint64_t SectionBase::getOffset(uint64_t offset) const { +uint64_t SectionBase::getOffset(uint64_t Offset) const { switch (kind()) { case Output: { - auto *os = cast(this); + auto *OS = cast(this); // For output sections we treat offset -1 as the end of the section. - return offset == uint64_t(-1) ? os->size : offset; + return Offset == uint64_t(-1) ? OS->Size : Offset; } case Regular: case Synthetic: - return cast(this)->getOffset(offset); + return cast(this)->getOffset(Offset); case EHFrame: // The file crtbeginT.o has relocations pointing to the start of an empty // .eh_frame that is known to be the first in the link. It does that to // identify the start of the output .eh_frame. - return offset; + return Offset; case Merge: - const MergeInputSection *ms = cast(this); - if (InputSection *isec = ms->getParent()) - return isec->getOffset(ms->getParentOffset(offset)); - return ms->getParentOffset(offset); + const MergeInputSection *MS = cast(this); + if (InputSection *IS = MS->getParent()) + return IS->getOffset(MS->getParentOffset(Offset)); + return MS->getParentOffset(Offset); } llvm_unreachable("invalid section kind"); } -uint64_t SectionBase::getVA(uint64_t offset) const { - const OutputSection *out = getOutputSection(); - return (out ? out->addr : 0) + getOffset(offset); +uint64_t SectionBase::getVA(uint64_t Offset) const { + const OutputSection *Out = getOutputSection(); + return (Out ? Out->Addr : 0) + getOffset(Offset); } OutputSection *SectionBase::getOutputSection() { - InputSection *sec; - if (auto *isec = dyn_cast(this)) - sec = isec; - else if (auto *ms = dyn_cast(this)) - sec = ms->getParent(); - else if (auto *eh = dyn_cast(this)) - sec = eh->getParent(); + InputSection *Sec; + if (auto *IS = dyn_cast(this)) + Sec = IS; + else if (auto *MS = dyn_cast(this)) + Sec = MS->getParent(); + else if (auto *EH = dyn_cast(this)) + Sec = EH->getParent(); else return cast(this); - return sec ? sec->getParent() : nullptr; + return Sec ? Sec->getParent() : nullptr; } -// When a section is compressed, `rawData` consists with a header followed +// When a section is compressed, `RawData` consists with a header followed // by zlib-compressed data. This function parses a header to initialize -// `uncompressedSize` member and remove the header from `rawData`. +// `UncompressedSize` member and remove the header from `RawData`. void InputSectionBase::parseCompressedHeader() { using Chdr64 = typename ELF64LE::Chdr; using Chdr32 = typename ELF32LE::Chdr; // Old-style header - if (name.startswith(".zdebug")) { - if (!toStringRef(rawData).startswith("ZLIB")) { + if (Name.startswith(".zdebug")) { + if (!toStringRef(RawData).startswith("ZLIB")) { error(toString(this) + ": corrupted compressed section header"); return; } - rawData = rawData.slice(4); + RawData = RawData.slice(4); - if (rawData.size() < 8) { + if (RawData.size() < 8) { error(toString(this) + ": corrupted compressed section header"); return; } - uncompressedSize = read64be(rawData.data()); - rawData = rawData.slice(8); + UncompressedSize = read64be(RawData.data()); + RawData = RawData.slice(8); // Restore the original section name. // (e.g. ".zdebug_info" -> ".debug_info") - name = saver.save("." + name.substr(2)); + Name = Saver.save("." + Name.substr(2)); return; } - assert(flags & SHF_COMPRESSED); - flags &= ~(uint64_t)SHF_COMPRESSED; + assert(Flags & SHF_COMPRESSED); + Flags &= ~(uint64_t)SHF_COMPRESSED; // New-style 64-bit header - if (config->is64) { - if (rawData.size() < sizeof(Chdr64)) { + if (Config->Is64) { + if (RawData.size() < sizeof(Chdr64)) { error(toString(this) + ": corrupted compressed section"); return; } - auto *hdr = reinterpret_cast(rawData.data()); - if (hdr->ch_type != ELFCOMPRESS_ZLIB) { + auto *Hdr = reinterpret_cast(RawData.data()); + if (Hdr->ch_type != ELFCOMPRESS_ZLIB) { error(toString(this) + ": unsupported compression type"); return; } - uncompressedSize = hdr->ch_size; - alignment = std::max(hdr->ch_addralign, 1); - rawData = rawData.slice(sizeof(*hdr)); + UncompressedSize = Hdr->ch_size; + Alignment = std::max(Hdr->ch_addralign, 1); + RawData = RawData.slice(sizeof(*Hdr)); return; } // New-style 32-bit header - if (rawData.size() < sizeof(Chdr32)) { + if (RawData.size() < sizeof(Chdr32)) { error(toString(this) + ": corrupted compressed section"); return; } - auto *hdr = reinterpret_cast(rawData.data()); - if (hdr->ch_type != ELFCOMPRESS_ZLIB) { + auto *Hdr = reinterpret_cast(RawData.data()); + if (Hdr->ch_type != ELFCOMPRESS_ZLIB) { error(toString(this) + ": unsupported compression type"); return; } - uncompressedSize = hdr->ch_size; - alignment = std::max(hdr->ch_addralign, 1); - rawData = rawData.slice(sizeof(*hdr)); + UncompressedSize = Hdr->ch_size; + Alignment = std::max(Hdr->ch_addralign, 1); + RawData = RawData.slice(sizeof(*Hdr)); } InputSection *InputSectionBase::getLinkOrderDep() const { - assert(link); - assert(flags & SHF_LINK_ORDER); - return cast(file->getSections()[link]); + assert(Link); + assert(Flags & SHF_LINK_ORDER); + return cast(File->getSections()[Link]); } // Find a function symbol that encloses a given location. template -Defined *InputSectionBase::getEnclosingFunction(uint64_t offset) { - for (Symbol *b : file->getSymbols()) - if (Defined *d = dyn_cast(b)) - if (d->section == this && d->type == STT_FUNC && d->value <= offset && - offset < d->value + d->size) - return d; +Defined *InputSectionBase::getEnclosingFunction(uint64_t Offset) { + for (Symbol *B : File->getSymbols()) + if (Defined *D = dyn_cast(B)) + if (D->Section == this && D->Type == STT_FUNC && D->Value <= Offset && + Offset < D->Value + D->Size) + return D; return nullptr; } // Returns a source location string. Used to construct an error message. template -std::string InputSectionBase::getLocation(uint64_t offset) { - std::string secAndOffset = (name + "+0x" + utohexstr(offset)).str(); +std::string InputSectionBase::getLocation(uint64_t Offset) { + std::string SecAndOffset = (Name + "+0x" + utohexstr(Offset)).str(); // We don't have file for synthetic sections. if (getFile() == nullptr) - return (config->outputFile + ":(" + secAndOffset + ")") + return (Config->OutputFile + ":(" + SecAndOffset + ")") .str(); // First check if we can get desired values from debugging information. - if (Optional info = getFile()->getDILineInfo(this, offset)) - return info->FileName + ":" + std::to_string(info->Line) + ":(" + - secAndOffset + ")"; + if (Optional Info = getFile()->getDILineInfo(this, Offset)) + return Info->FileName + ":" + std::to_string(Info->Line) + ":(" + + SecAndOffset + ")"; - // File->sourceFile contains STT_FILE symbol that contains a + // File->SourceFile contains STT_FILE symbol that contains a // source file name. If it's missing, we use an object file name. - std::string srcFile = getFile()->sourceFile; - if (srcFile.empty()) - srcFile = toString(file); + std::string SrcFile = getFile()->SourceFile; + if (SrcFile.empty()) + SrcFile = toString(File); - if (Defined *d = getEnclosingFunction(offset)) - return srcFile + ":(function " + toString(*d) + ": " + secAndOffset + ")"; + if (Defined *D = getEnclosingFunction(Offset)) + return SrcFile + ":(function " + toString(*D) + ": " + SecAndOffset + ")"; // If there's no symbol, print out the offset in the section. - return (srcFile + ":(" + secAndOffset + ")"); + return (SrcFile + ":(" + SecAndOffset + ")"); } // This function is intended to be used for constructing an error message. @@ -325,8 +325,8 @@ std::string InputSectionBase::getLocation(uint64_t offset) { // foo.c:42 (/home/alice/possibly/very/long/path/foo.c:42) // // Returns an empty string if there's no way to get line info. -std::string InputSectionBase::getSrcMsg(const Symbol &sym, uint64_t offset) { - return file->getSrcMsg(sym, *this, offset); +std::string InputSectionBase::getSrcMsg(const Symbol &Sym, uint64_t Offset) { + return File->getSrcMsg(Sym, *this, Offset); } // Returns a filename string along with an optional section name. This @@ -338,96 +338,96 @@ std::string InputSectionBase::getSrcMsg(const Symbol &sym, uint64_t offset) { // or // // path/to/foo.o:(function bar) in archive path/to/bar.a -std::string InputSectionBase::getObjMsg(uint64_t off) { - std::string filename = file->getName(); +std::string InputSectionBase::getObjMsg(uint64_t Off) { + std::string Filename = File->getName(); - std::string archive; - if (!file->archiveName.empty()) - archive = " in archive " + file->archiveName; + std::string Archive; + if (!File->ArchiveName.empty()) + Archive = " in archive " + File->ArchiveName; // Find a symbol that encloses a given location. - for (Symbol *b : file->getSymbols()) - if (auto *d = dyn_cast(b)) - if (d->section == this && d->value <= off && off < d->value + d->size) - return filename + ":(" + toString(*d) + ")" + archive; + for (Symbol *B : File->getSymbols()) + if (auto *D = dyn_cast(B)) + if (D->Section == this && D->Value <= Off && Off < D->Value + D->Size) + return Filename + ":(" + toString(*D) + ")" + Archive; // If there's no symbol, print out the offset in the section. - return (filename + ":(" + name + "+0x" + utohexstr(off) + ")" + archive) + return (Filename + ":(" + Name + "+0x" + utohexstr(Off) + ")" + Archive) .str(); } -InputSection InputSection::discarded(nullptr, 0, 0, 0, ArrayRef(), ""); +InputSection InputSection::Discarded(nullptr, 0, 0, 0, ArrayRef(), ""); -InputSection::InputSection(InputFile *f, uint64_t flags, uint32_t type, - uint32_t alignment, ArrayRef data, - StringRef name, Kind k) - : InputSectionBase(f, flags, type, - /*Entsize*/ 0, /*Link*/ 0, /*Info*/ 0, alignment, data, - name, k) {} +InputSection::InputSection(InputFile *F, uint64_t Flags, uint32_t Type, + uint32_t Alignment, ArrayRef Data, + StringRef Name, Kind K) + : InputSectionBase(F, Flags, Type, + /*Entsize*/ 0, /*Link*/ 0, /*Info*/ 0, Alignment, Data, + Name, K) {} template -InputSection::InputSection(ObjFile &f, const typename ELFT::Shdr &header, - StringRef name) - : InputSectionBase(f, header, name, InputSectionBase::Regular) {} +InputSection::InputSection(ObjFile &F, const typename ELFT::Shdr &Header, + StringRef Name) + : InputSectionBase(F, Header, Name, InputSectionBase::Regular) {} -bool InputSection::classof(const SectionBase *s) { - return s->kind() == SectionBase::Regular || - s->kind() == SectionBase::Synthetic; +bool InputSection::classof(const SectionBase *S) { + return S->kind() == SectionBase::Regular || + S->kind() == SectionBase::Synthetic; } OutputSection *InputSection::getParent() const { - return cast_or_null(parent); + return cast_or_null(Parent); } // Copy SHT_GROUP section contents. Used only for the -r option. -template void InputSection::copyShtGroup(uint8_t *buf) { +template void InputSection::copyShtGroup(uint8_t *Buf) { // ELFT::Word is the 32-bit integral type in the target endianness. using u32 = typename ELFT::Word; - ArrayRef from = getDataAs(); - auto *to = reinterpret_cast(buf); + ArrayRef From = getDataAs(); + auto *To = reinterpret_cast(Buf); // The first entry is not a section number but a flag. - *to++ = from[0]; + *To++ = From[0]; // Adjust section numbers because section numbers in an input object // files are different in the output. - ArrayRef sections = file->getSections(); - for (uint32_t idx : from.slice(1)) - *to++ = sections[idx]->getOutputSection()->sectionIndex; + ArrayRef Sections = File->getSections(); + for (uint32_t Idx : From.slice(1)) + *To++ = Sections[Idx]->getOutputSection()->SectionIndex; } InputSectionBase *InputSection::getRelocatedSection() const { - if (!file || (type != SHT_RELA && type != SHT_REL)) + if (!File || (Type != SHT_RELA && Type != SHT_REL)) return nullptr; - ArrayRef sections = file->getSections(); - return sections[info]; + ArrayRef Sections = File->getSections(); + return Sections[Info]; } // This is used for -r and --emit-relocs. We can't use memcpy to copy // relocations because we need to update symbol table offset and section index // for each relocation. So we copy relocations one by one. template -void InputSection::copyRelocations(uint8_t *buf, ArrayRef rels) { - InputSectionBase *sec = getRelocatedSection(); +void InputSection::copyRelocations(uint8_t *Buf, ArrayRef Rels) { + InputSectionBase *Sec = getRelocatedSection(); - for (const RelTy &rel : rels) { - RelType type = rel.getType(config->isMips64EL); - const ObjFile *file = getFile(); - Symbol &sym = file->getRelocTargetSym(rel); + for (const RelTy &Rel : Rels) { + RelType Type = Rel.getType(Config->IsMips64EL); + const ObjFile *File = getFile(); + Symbol &Sym = File->getRelocTargetSym(Rel); - auto *p = reinterpret_cast(buf); - buf += sizeof(RelTy); + auto *P = reinterpret_cast(Buf); + Buf += sizeof(RelTy); if (RelTy::IsRela) - p->r_addend = getAddend(rel); + P->r_addend = getAddend(Rel); // Output section VA is zero for -r, so r_offset is an offset within the // section, but for --emit-relocs it is an virtual address. - p->r_offset = sec->getVA(rel.r_offset); - p->setSymbolAndType(in.symTab->getSymbolIndex(&sym), type, - config->isMips64EL); + P->r_offset = Sec->getVA(Rel.r_offset); + P->setSymbolAndType(In.SymTab->getSymbolIndex(&Sym), Type, + Config->IsMips64EL); - if (sym.type == STT_SECTION) { + if (Sym.Type == STT_SECTION) { // We combine multiple section symbols into only one per // section. This means we have to update the addend. That is // trivial for Elf_Rela, but for Elf_Rel we have to write to the @@ -440,34 +440,34 @@ void InputSection::copyRelocations(uint8_t *buf, ArrayRef rels) { // on .gcc_except_table and debug sections. // // See the comment in maybeReportUndefined for PPC64 .toc . - auto *d = dyn_cast(&sym); - if (!d) { - if (!sec->name.startswith(".debug") && - !sec->name.startswith(".zdebug") && sec->name != ".eh_frame" && - sec->name != ".gcc_except_table" && sec->name != ".toc") { - uint32_t secIdx = cast(sym).discardedSecIdx; - Elf_Shdr_Impl sec = - CHECK(file->getObj().sections(), file)[secIdx]; + auto *D = dyn_cast(&Sym); + if (!D) { + if (!Sec->Name.startswith(".debug") && + !Sec->Name.startswith(".zdebug") && Sec->Name != ".eh_frame" && + Sec->Name != ".gcc_except_table" && Sec->Name != ".toc") { + uint32_t SecIdx = cast(Sym).DiscardedSecIdx; + Elf_Shdr_Impl Sec = + CHECK(File->getObj().sections(), File)[SecIdx]; warn("relocation refers to a discarded section: " + - CHECK(file->getObj().getSectionName(&sec), file) + - "\n>>> referenced by " + getObjMsg(p->r_offset)); + CHECK(File->getObj().getSectionName(&Sec), File) + + "\n>>> referenced by " + getObjMsg(P->r_offset)); } - p->setSymbolAndType(0, 0, false); + P->setSymbolAndType(0, 0, false); continue; } - SectionBase *section = d->section->repl; - if (!section->isLive()) { - p->setSymbolAndType(0, 0, false); + SectionBase *Section = D->Section->Repl; + if (!Section->isLive()) { + P->setSymbolAndType(0, 0, false); continue; } - int64_t addend = getAddend(rel); - const uint8_t *bufLoc = sec->data().begin() + rel.r_offset; + int64_t Addend = getAddend(Rel); + const uint8_t *BufLoc = Sec->data().begin() + Rel.r_offset; if (!RelTy::IsRela) - addend = target->getImplicitAddend(bufLoc, type); + Addend = Target->getImplicitAddend(BufLoc, Type); - if (config->emachine == EM_MIPS && config->relocatable && - target->getRelExpr(type, sym, bufLoc) == R_MIPS_GOTREL) { + if (Config->EMachine == EM_MIPS && Config->Relocatable && + Target->getRelExpr(Type, Sym, BufLoc) == R_MIPS_GOTREL) { // Some MIPS relocations depend on "gp" value. By default, // this value has 0x7ff0 offset from a .got section. But // relocatable files produced by a complier or a linker @@ -479,13 +479,13 @@ void InputSection::copyRelocations(uint8_t *buf, ArrayRef rels) { // individual "gp" values used by each input object file. // As a workaround we add the "gp" value to the relocation // addend and save it back to the file. - addend += sec->getFile()->mipsGp0; + Addend += Sec->getFile()->MipsGp0; } if (RelTy::IsRela) - p->r_addend = sym.getVA(addend) - section->getOutputSection()->addr; - else if (config->relocatable && type != target->noneRel) - sec->relocations.push_back({R_ABS, type, rel.r_offset, addend, &sym}); + P->r_addend = Sym.getVA(Addend) - Section->getOutputSection()->Addr; + else if (Config->Relocatable && Type != Target->NoneRel) + Sec->Relocations.push_back({R_ABS, Type, Rel.r_offset, Addend, &Sym}); } } } @@ -495,13 +495,13 @@ void InputSection::copyRelocations(uint8_t *buf, ArrayRef rels) { // this context is the address of the place P. A further special case is that // branch relocations to an undefined weak reference resolve to the next // instruction. -static uint32_t getARMUndefinedRelativeWeakVA(RelType type, uint32_t a, - uint32_t p) { - switch (type) { +static uint32_t getARMUndefinedRelativeWeakVA(RelType Type, uint32_t A, + uint32_t P) { + switch (Type) { // Unresolved branch relocations to weak references resolve to next // instruction, this will be either 2 or 4 bytes on from P. case R_ARM_THM_JUMP11: - return p + 2 + a; + return P + 2 + A; case R_ARM_CALL: case R_ARM_JUMP24: case R_ARM_PC24: @@ -509,10 +509,10 @@ static uint32_t getARMUndefinedRelativeWeakVA(RelType type, uint32_t a, case R_ARM_PREL31: case R_ARM_THM_JUMP19: case R_ARM_THM_JUMP24: - return p + 4 + a; + return P + 4 + A; case R_ARM_THM_CALL: // We don't want an interworking BLX to ARM - return p + 5 + a; + return P + 5 + A; // Unresolved non branch pc-relative relocations // R_ARM_TARGET2 which can be resolved relatively is not present as it never // targets a weak-reference. @@ -521,29 +521,29 @@ static uint32_t getARMUndefinedRelativeWeakVA(RelType type, uint32_t a, case R_ARM_REL32: case R_ARM_THM_MOVW_PREL_NC: case R_ARM_THM_MOVT_PREL: - return p + a; + return P + A; } llvm_unreachable("ARM pc-relative relocation expected\n"); } // The comment above getARMUndefinedRelativeWeakVA applies to this function. -static uint64_t getAArch64UndefinedRelativeWeakVA(uint64_t type, uint64_t a, - uint64_t p) { - switch (type) { +static uint64_t getAArch64UndefinedRelativeWeakVA(uint64_t Type, uint64_t A, + uint64_t P) { + switch (Type) { // Unresolved branch relocations to weak references resolve to next // instruction, this is 4 bytes on from P. case R_AARCH64_CALL26: case R_AARCH64_CONDBR19: case R_AARCH64_JUMP26: case R_AARCH64_TSTBR14: - return p + 4 + a; + return P + 4 + A; // Unresolved non branch pc-relative relocations case R_AARCH64_PREL16: case R_AARCH64_PREL32: case R_AARCH64_PREL64: case R_AARCH64_ADR_PREL_LO21: case R_AARCH64_LD_PREL_LO19: - return p + a; + return P + A; } llvm_unreachable("AArch64 pc-relative relocation expected\n"); } @@ -555,11 +555,11 @@ static uint64_t getAArch64UndefinedRelativeWeakVA(uint64_t type, uint64_t a, // The procedure call standard only defines a Read Write Position Independent // RWPI variant so in practice we should expect the static base to be the base // of the RW segment. -static uint64_t getARMStaticBase(const Symbol &sym) { - OutputSection *os = sym.getOutputSection(); - if (!os || !os->ptLoad || !os->ptLoad->firstSec) - fatal("SBREL relocation to " + sym.getName() + " without static base"); - return os->ptLoad->firstSec->addr; +static uint64_t getARMStaticBase(const Symbol &Sym) { + OutputSection *OS = Sym.getOutputSection(); + if (!OS || !OS->PtLoad || !OS->PtLoad->FirstSec) + fatal("SBREL relocation to " + Sym.getName() + " without static base"); + return OS->PtLoad->FirstSec->Addr; } // For R_RISCV_PC_INDIRECT (R_RISCV_PCREL_LO12_{I,S}), the symbol actually @@ -568,126 +568,107 @@ static uint64_t getARMStaticBase(const Symbol &sym) { // // This function returns the R_RISCV_PCREL_HI20 relocation from // R_RISCV_PCREL_LO12's symbol and addend. -static Relocation *getRISCVPCRelHi20(const Symbol *sym, uint64_t addend) { - const Defined *d = cast(sym); - if (!d->section) { - error("R_RISCV_PCREL_LO12 relocation points to an absolute symbol: " + - sym->getName()); - return nullptr; - } - InputSection *isec = cast(d->section); +static Relocation *getRISCVPCRelHi20(const Symbol *Sym, uint64_t Addend) { + const Defined *D = cast(Sym); + InputSection *IS = cast(D->Section); - if (addend != 0) + if (Addend != 0) warn("Non-zero addend in R_RISCV_PCREL_LO12 relocation to " + - isec->getObjMsg(d->value) + " is ignored"); + IS->getObjMsg(D->Value) + " is ignored"); // Relocations are sorted by offset, so we can use std::equal_range to do // binary search. - Relocation r; - r.offset = d->value; - auto range = - std::equal_range(isec->relocations.begin(), isec->relocations.end(), r, - [](const Relocation &lhs, const Relocation &rhs) { - return lhs.offset < rhs.offset; + Relocation R; + R.Offset = D->Value; + auto Range = + std::equal_range(IS->Relocations.begin(), IS->Relocations.end(), R, + [](const Relocation &LHS, const Relocation &RHS) { + return LHS.Offset < RHS.Offset; }); - for (auto it = range.first; it != range.second; ++it) - if (it->type == R_RISCV_PCREL_HI20 || it->type == R_RISCV_GOT_HI20 || - it->type == R_RISCV_TLS_GD_HI20 || it->type == R_RISCV_TLS_GOT_HI20) - return &*it; + for (auto It = Range.first; It != Range.second; ++It) + if (It->Expr == R_PC) + return &*It; - error("R_RISCV_PCREL_LO12 relocation points to " + isec->getObjMsg(d->value) + + error("R_RISCV_PCREL_LO12 relocation points to " + IS->getObjMsg(D->Value) + " without an associated R_RISCV_PCREL_HI20 relocation"); return nullptr; } // A TLS symbol's virtual address is relative to the TLS segment. Add a // target-specific adjustment to produce a thread-pointer-relative offset. -static int64_t getTlsTpOffset(const Symbol &s) { +static int64_t getTlsTpOffset(const Symbol &S) { // On targets that support TLSDESC, _TLS_MODULE_BASE_@tpoff = 0. - if (&s == ElfSym::tlsModuleBase) + if (&S == ElfSym::TlsModuleBase) return 0; - // There are 2 TLS layouts. Among targets we support, x86 uses TLS Variant 2 - // while most others use Variant 1. At run time TP will be aligned to p_align. - - // Variant 1. TP will be followed by an optional gap (which is the size of 2 - // pointers on ARM/AArch64, 0 on other targets), followed by alignment - // padding, then the static TLS blocks. The alignment padding is added so that - // (TP + gap + padding) is congruent to p_vaddr modulo p_align. - // - // Variant 2. Static TLS blocks, followed by alignment padding are placed - // before TP. The alignment padding is added so that (TP - padding - - // p_memsz) is congruent to p_vaddr modulo p_align. - elf::PhdrEntry *tls = Out::tlsPhdr; - switch (config->emachine) { - // Variant 1. + switch (Config->EMachine) { case EM_ARM: case EM_AARCH64: - return s.getVA(0) + config->wordsize * 2 + - ((tls->p_vaddr - config->wordsize * 2) & (tls->p_align - 1)); - case EM_MIPS: - case EM_PPC: - case EM_PPC64: - // Adjusted Variant 1. TP is placed with a displacement of 0x7000, which is - // to allow a signed 16-bit offset to reach 0x1000 of TCB/thread-library - // data and 0xf000 of the program's TLS segment. - return s.getVA(0) + (tls->p_vaddr & (tls->p_align - 1)) - 0x7000; - case EM_RISCV: - return s.getVA(0) + (tls->p_vaddr & (tls->p_align - 1)); - - // Variant 2. + // Variant 1. The thread pointer points to a TCB with a fixed 2-word size, + // followed by a variable amount of alignment padding, followed by the TLS + // segment. + return S.getVA(0) + alignTo(Config->Wordsize * 2, Out::TlsPhdr->p_align); case EM_386: case EM_X86_64: - return s.getVA(0) - tls->p_memsz - - ((-tls->p_vaddr - tls->p_memsz) & (tls->p_align - 1)); + // Variant 2. The TLS segment is located just before the thread pointer. + return S.getVA(0) - alignTo(Out::TlsPhdr->p_memsz, Out::TlsPhdr->p_align); + case EM_PPC: + case EM_PPC64: + // The thread pointer points to a fixed offset from the start of the + // executable's TLS segment. An offset of 0x7000 allows a signed 16-bit + // offset to reach 0x1000 of TCB/thread-library data and 0xf000 of the + // program's TLS segment. + return S.getVA(0) - 0x7000; default: llvm_unreachable("unhandled Config->EMachine"); } } -static uint64_t getRelocTargetVA(const InputFile *file, RelType type, int64_t a, - uint64_t p, const Symbol &sym, RelExpr expr) { - switch (expr) { +static uint64_t getRelocTargetVA(const InputFile *File, RelType Type, int64_t A, + uint64_t P, const Symbol &Sym, RelExpr Expr) { + switch (Expr) { case R_ABS: case R_DTPREL: case R_RELAX_TLS_LD_TO_LE_ABS: case R_RELAX_GOT_PC_NOPIC: case R_RISCV_ADD: - return sym.getVA(a); + return Sym.getVA(A); case R_ADDEND: - return a; + return A; case R_ARM_SBREL: - return sym.getVA(a) - getARMStaticBase(sym); + return Sym.getVA(A) - getARMStaticBase(Sym); case R_GOT: case R_RELAX_TLS_GD_TO_IE_ABS: - return sym.getGotVA() + a; + return Sym.getGotVA() + A; case R_GOTONLY_PC: - return in.got->getVA() + a - p; + return In.Got->getVA() + A - P; case R_GOTPLTONLY_PC: - return in.gotPlt->getVA() + a - p; + return In.GotPlt->getVA() + A - P; case R_GOTREL: case R_PPC64_RELAX_TOC: - return sym.getVA(a) - in.got->getVA(); + return Sym.getVA(A) - In.Got->getVA(); case R_GOTPLTREL: - return sym.getVA(a) - in.gotPlt->getVA(); + return Sym.getVA(A) - In.GotPlt->getVA(); case R_GOTPLT: case R_RELAX_TLS_GD_TO_IE_GOTPLT: - return sym.getGotVA() + a - in.gotPlt->getVA(); + return Sym.getGotVA() + A - In.GotPlt->getVA(); case R_TLSLD_GOT_OFF: case R_GOT_OFF: case R_RELAX_TLS_GD_TO_IE_GOT_OFF: - return sym.getGotOffset() + a; + return Sym.getGotOffset() + A; case R_AARCH64_GOT_PAGE_PC: case R_AARCH64_RELAX_TLS_GD_TO_IE_PAGE_PC: - return getAArch64Page(sym.getGotVA() + a) - getAArch64Page(p); + return getAArch64Page(Sym.getGotVA() + A) - getAArch64Page(P); case R_GOT_PC: case R_RELAX_TLS_GD_TO_IE: - return sym.getGotVA() + a - p; + return Sym.getGotVA() + A - P; + case R_HEXAGON_GOT: + return Sym.getGotVA() - In.GotPlt->getVA(); case R_MIPS_GOTREL: - return sym.getVA(a) - in.mipsGot->getGp(file); + return Sym.getVA(A) - In.MipsGot->getGp(File); case R_MIPS_GOT_GP: - return in.mipsGot->getGp(file) + a; + return In.MipsGot->getGp(File) + A; case R_MIPS_GOT_GP_PC: { // R_MIPS_LO16 expression has R_MIPS_GOT_GP_PC type iif the target // is _gp_disp symbol. In that case we should use the following @@ -696,76 +677,76 @@ static uint64_t getRelocTargetVA(const InputFile *file, RelType type, int64_t a, // microMIPS variants of these relocations use slightly different // expressions: AHL + GP - P + 3 for %lo() and AHL + GP - P - 1 for %hi() // to correctly handle less-sugnificant bit of the microMIPS symbol. - uint64_t v = in.mipsGot->getGp(file) + a - p; - if (type == R_MIPS_LO16 || type == R_MICROMIPS_LO16) - v += 4; - if (type == R_MICROMIPS_LO16 || type == R_MICROMIPS_HI16) - v -= 1; - return v; + uint64_t V = In.MipsGot->getGp(File) + A - P; + if (Type == R_MIPS_LO16 || Type == R_MICROMIPS_LO16) + V += 4; + if (Type == R_MICROMIPS_LO16 || Type == R_MICROMIPS_HI16) + V -= 1; + return V; } case R_MIPS_GOT_LOCAL_PAGE: // If relocation against MIPS local symbol requires GOT entry, this entry // should be initialized by 'page address'. This address is high 16-bits // of sum the symbol's value and the addend. - return in.mipsGot->getVA() + in.mipsGot->getPageEntryOffset(file, sym, a) - - in.mipsGot->getGp(file); + return In.MipsGot->getVA() + In.MipsGot->getPageEntryOffset(File, Sym, A) - + In.MipsGot->getGp(File); case R_MIPS_GOT_OFF: case R_MIPS_GOT_OFF32: // In case of MIPS if a GOT relocation has non-zero addend this addend // should be applied to the GOT entry content not to the GOT entry offset. // That is why we use separate expression type. - return in.mipsGot->getVA() + in.mipsGot->getSymEntryOffset(file, sym, a) - - in.mipsGot->getGp(file); + return In.MipsGot->getVA() + In.MipsGot->getSymEntryOffset(File, Sym, A) - + In.MipsGot->getGp(File); case R_MIPS_TLSGD: - return in.mipsGot->getVA() + in.mipsGot->getGlobalDynOffset(file, sym) - - in.mipsGot->getGp(file); + return In.MipsGot->getVA() + In.MipsGot->getGlobalDynOffset(File, Sym) - + In.MipsGot->getGp(File); case R_MIPS_TLSLD: - return in.mipsGot->getVA() + in.mipsGot->getTlsIndexOffset(file) - - in.mipsGot->getGp(file); + return In.MipsGot->getVA() + In.MipsGot->getTlsIndexOffset(File) - + In.MipsGot->getGp(File); case R_AARCH64_PAGE_PC: { - uint64_t val = sym.isUndefWeak() ? p + a : sym.getVA(a); - return getAArch64Page(val) - getAArch64Page(p); + uint64_t Val = Sym.isUndefWeak() ? P + A : Sym.getVA(A); + return getAArch64Page(Val) - getAArch64Page(P); } case R_RISCV_PC_INDIRECT: { - if (const Relocation *hiRel = getRISCVPCRelHi20(&sym, a)) - return getRelocTargetVA(file, hiRel->type, hiRel->addend, sym.getVA(), - *hiRel->sym, hiRel->expr); + if (const Relocation *HiRel = getRISCVPCRelHi20(&Sym, A)) + return getRelocTargetVA(File, HiRel->Type, HiRel->Addend, Sym.getVA(), + *HiRel->Sym, HiRel->Expr); return 0; } case R_PC: { - uint64_t dest; - if (sym.isUndefWeak()) { + uint64_t Dest; + if (Sym.isUndefWeak()) { // On ARM and AArch64 a branch to an undefined weak resolves to the // next instruction, otherwise the place. - if (config->emachine == EM_ARM) - dest = getARMUndefinedRelativeWeakVA(type, a, p); - else if (config->emachine == EM_AARCH64) - dest = getAArch64UndefinedRelativeWeakVA(type, a, p); - else if (config->emachine == EM_PPC) - dest = p; + if (Config->EMachine == EM_ARM) + Dest = getARMUndefinedRelativeWeakVA(Type, A, P); + else if (Config->EMachine == EM_AARCH64) + Dest = getAArch64UndefinedRelativeWeakVA(Type, A, P); + else if (Config->EMachine == EM_PPC) + Dest = P; else - dest = sym.getVA(a); + Dest = Sym.getVA(A); } else { - dest = sym.getVA(a); + Dest = Sym.getVA(A); } - return dest - p; + return Dest - P; } case R_PLT: - return sym.getPltVA() + a; + return Sym.getPltVA() + A; case R_PLT_PC: case R_PPC64_CALL_PLT: - return sym.getPltVA() + a - p; + return Sym.getPltVA() + A - P; case R_PPC32_PLTREL: // R_PPC_PLTREL24 uses the addend (usually 0 or 0x8000) to indicate r30 // stores _GLOBAL_OFFSET_TABLE_ or .got2+0x8000. The addend is ignored for // target VA compuation. - return sym.getPltVA() - p; + return Sym.getPltVA() - P; case R_PPC64_CALL: { - uint64_t symVA = sym.getVA(a); + uint64_t SymVA = Sym.getVA(A); // If we have an undefined weak symbol, we might get here with a symbol // address of zero. That could overflow, but the code must be unreachable, // so don't bother doing anything at all. - if (!symVA) + if (!SymVA) return 0; // PPC64 V2 ABI describes two entry points to a function. The global entry @@ -774,12 +755,12 @@ static uint64_t getRelocTargetVA(const InputFile *file, RelType type, int64_t a, // the callee. For local calls the caller and callee share the same // TOC base and so the TOC pointer initialization code should be skipped by // branching to the local entry point. - return symVA - p + getPPC64GlobalEntryToLocalEntryOffset(sym.stOther); + return SymVA - P + getPPC64GlobalEntryToLocalEntryOffset(Sym.StOther); } case R_PPC64_TOCBASE: - return getPPC64TocBase() + a; + return getPPC64TocBase() + A; case R_RELAX_GOT_PC: - return sym.getVA(a) - p; + return Sym.getVA(A) - P; case R_RELAX_TLS_GD_TO_LE: case R_RELAX_TLS_IE_TO_LE: case R_RELAX_TLS_LD_TO_LE: @@ -788,35 +769,35 @@ static uint64_t getRelocTargetVA(const InputFile *file, RelType type, int64_t a, // --noinhibit-exec, even a non-weak undefined reference may reach here. // Just return A, which matches R_ABS, and the behavior of some dynamic // loaders. - if (sym.isUndefined()) - return a; - return getTlsTpOffset(sym) + a; + if (Sym.isUndefined()) + return A; + return getTlsTpOffset(Sym) + A; case R_RELAX_TLS_GD_TO_LE_NEG: case R_NEG_TLS: - if (sym.isUndefined()) - return a; - return -getTlsTpOffset(sym) + a; + if (Sym.isUndefined()) + return A; + return -getTlsTpOffset(Sym) + A; case R_SIZE: - return sym.getSize() + a; + return Sym.getSize() + A; case R_TLSDESC: - return in.got->getGlobalDynAddr(sym) + a; + return In.Got->getGlobalDynAddr(Sym) + A; case R_TLSDESC_PC: - return in.got->getGlobalDynAddr(sym) + a - p; + return In.Got->getGlobalDynAddr(Sym) + A - P; case R_AARCH64_TLSDESC_PAGE: - return getAArch64Page(in.got->getGlobalDynAddr(sym) + a) - - getAArch64Page(p); + return getAArch64Page(In.Got->getGlobalDynAddr(Sym) + A) - + getAArch64Page(P); case R_TLSGD_GOT: - return in.got->getGlobalDynOffset(sym) + a; + return In.Got->getGlobalDynOffset(Sym) + A; case R_TLSGD_GOTPLT: - return in.got->getVA() + in.got->getGlobalDynOffset(sym) + a - in.gotPlt->getVA(); + return In.Got->getVA() + In.Got->getGlobalDynOffset(Sym) + A - In.GotPlt->getVA(); case R_TLSGD_PC: - return in.got->getGlobalDynAddr(sym) + a - p; + return In.Got->getGlobalDynAddr(Sym) + A - P; case R_TLSLD_GOTPLT: - return in.got->getVA() + in.got->getTlsIndexOff() + a - in.gotPlt->getVA(); + return In.Got->getVA() + In.Got->getTlsIndexOff() + A - In.GotPlt->getVA(); case R_TLSLD_GOT: - return in.got->getTlsIndexOff() + a; + return In.Got->getTlsIndexOff() + A; case R_TLSLD_PC: - return in.got->getTlsIndexVA() + a - p; + return In.Got->getTlsIndexVA() + A - P; default: llvm_unreachable("invalid expression"); } @@ -830,36 +811,36 @@ static uint64_t getRelocTargetVA(const InputFile *file, RelType type, int64_t a, // So, we handle relocations for non-alloc sections directly in this // function as a performance optimization. template -void InputSection::relocateNonAlloc(uint8_t *buf, ArrayRef rels) { - const unsigned bits = sizeof(typename ELFT::uint) * 8; +void InputSection::relocateNonAlloc(uint8_t *Buf, ArrayRef Rels) { + const unsigned Bits = sizeof(typename ELFT::uint) * 8; - for (const RelTy &rel : rels) { - RelType type = rel.getType(config->isMips64EL); + for (const RelTy &Rel : Rels) { + RelType Type = Rel.getType(Config->IsMips64EL); // GCC 8.0 or earlier have a bug that they emit R_386_GOTPC relocations // against _GLOBAL_OFFSET_TABLE_ for .debug_info. The bug has been fixed // in 2017 (https://gcc.gnu.org/bugzilla/show_bug.cgi?id=82630), but we // need to keep this bug-compatible code for a while. - if (config->emachine == EM_386 && type == R_386_GOTPC) + if (Config->EMachine == EM_386 && Type == R_386_GOTPC) continue; - uint64_t offset = getOffset(rel.r_offset); - uint8_t *bufLoc = buf + offset; - int64_t addend = getAddend(rel); + uint64_t Offset = getOffset(Rel.r_offset); + uint8_t *BufLoc = Buf + Offset; + int64_t Addend = getAddend(Rel); if (!RelTy::IsRela) - addend += target->getImplicitAddend(bufLoc, type); + Addend += Target->getImplicitAddend(BufLoc, Type); - Symbol &sym = getFile()->getRelocTargetSym(rel); - RelExpr expr = target->getRelExpr(type, sym, bufLoc); - if (expr == R_NONE) + Symbol &Sym = getFile()->getRelocTargetSym(Rel); + RelExpr Expr = Target->getRelExpr(Type, Sym, BufLoc); + if (Expr == R_NONE) continue; - if (expr != R_ABS && expr != R_DTPREL && expr != R_RISCV_ADD) { - std::string msg = getLocation(offset) + - ": has non-ABS relocation " + toString(type) + - " against symbol '" + toString(sym) + "'"; - if (expr != R_PC) { - error(msg); + if (Expr != R_ABS && Expr != R_DTPREL) { + std::string Msg = getLocation(Offset) + + ": has non-ABS relocation " + toString(Type) + + " against symbol '" + toString(Sym) + "'"; + if (Expr != R_PC) { + error(Msg); return; } @@ -870,16 +851,16 @@ void InputSection::relocateNonAlloc(uint8_t *buf, ArrayRef rels) { // relocations without any errors and relocate them as if they were at // address 0. For bug-compatibilty, we accept them with warnings. We // know Steel Bank Common Lisp as of 2018 have this bug. - warn(msg); - target->relocateOne(bufLoc, type, - SignExtend64(sym.getVA(addend - offset))); + warn(Msg); + Target->relocateOne(BufLoc, Type, + SignExtend64(Sym.getVA(Addend - Offset))); continue; } - if (sym.isTls() && !Out::tlsPhdr) - target->relocateOne(bufLoc, type, 0); + if (Sym.isTls() && !Out::TlsPhdr) + Target->relocateOne(BufLoc, Type, 0); else - target->relocateOne(bufLoc, type, SignExtend64(sym.getVA(addend))); + Target->relocateOne(BufLoc, Type, SignExtend64(Sym.getVA(Addend))); } } @@ -888,100 +869,100 @@ void InputSection::relocateNonAlloc(uint8_t *buf, ArrayRef rels) { // relocations aimed to update addends. They are handled in relocateAlloc() // for allocatable sections, and this function does the same for // non-allocatable sections, such as sections with debug information. -static void relocateNonAllocForRelocatable(InputSection *sec, uint8_t *buf) { - const unsigned bits = config->is64 ? 64 : 32; +static void relocateNonAllocForRelocatable(InputSection *Sec, uint8_t *Buf) { + const unsigned Bits = Config->Is64 ? 64 : 32; - for (const Relocation &rel : sec->relocations) { + for (const Relocation &Rel : Sec->Relocations) { // InputSection::copyRelocations() adds only R_ABS relocations. - assert(rel.expr == R_ABS); - uint8_t *bufLoc = buf + rel.offset + sec->outSecOff; - uint64_t targetVA = SignExtend64(rel.sym->getVA(rel.addend), bits); - target->relocateOne(bufLoc, rel.type, targetVA); + assert(Rel.Expr == R_ABS); + uint8_t *BufLoc = Buf + Rel.Offset + Sec->OutSecOff; + uint64_t TargetVA = SignExtend64(Rel.Sym->getVA(Rel.Addend), Bits); + Target->relocateOne(BufLoc, Rel.Type, TargetVA); } } template -void InputSectionBase::relocate(uint8_t *buf, uint8_t *bufEnd) { - if (flags & SHF_EXECINSTR) - adjustSplitStackFunctionPrologues(buf, bufEnd); +void InputSectionBase::relocate(uint8_t *Buf, uint8_t *BufEnd) { + if (Flags & SHF_EXECINSTR) + adjustSplitStackFunctionPrologues(Buf, BufEnd); - if (flags & SHF_ALLOC) { - relocateAlloc(buf, bufEnd); + if (Flags & SHF_ALLOC) { + relocateAlloc(Buf, BufEnd); return; } - auto *sec = cast(this); - if (config->relocatable) - relocateNonAllocForRelocatable(sec, buf); - else if (sec->areRelocsRela) - sec->relocateNonAlloc(buf, sec->template relas()); + auto *Sec = cast(this); + if (Config->Relocatable) + relocateNonAllocForRelocatable(Sec, Buf); + else if (Sec->AreRelocsRela) + Sec->relocateNonAlloc(Buf, Sec->template relas()); else - sec->relocateNonAlloc(buf, sec->template rels()); + Sec->relocateNonAlloc(Buf, Sec->template rels()); } -void InputSectionBase::relocateAlloc(uint8_t *buf, uint8_t *bufEnd) { - assert(flags & SHF_ALLOC); - const unsigned bits = config->wordsize * 8; +void InputSectionBase::relocateAlloc(uint8_t *Buf, uint8_t *BufEnd) { + assert(Flags & SHF_ALLOC); + const unsigned Bits = Config->Wordsize * 8; - for (const Relocation &rel : relocations) { - uint64_t offset = rel.offset; - if (auto *sec = dyn_cast(this)) - offset += sec->outSecOff; - uint8_t *bufLoc = buf + offset; - RelType type = rel.type; + for (const Relocation &Rel : Relocations) { + uint64_t Offset = Rel.Offset; + if (auto *Sec = dyn_cast(this)) + Offset += Sec->OutSecOff; + uint8_t *BufLoc = Buf + Offset; + RelType Type = Rel.Type; - uint64_t addrLoc = getOutputSection()->addr + offset; - RelExpr expr = rel.expr; - uint64_t targetVA = SignExtend64( - getRelocTargetVA(file, type, rel.addend, addrLoc, *rel.sym, expr), - bits); + uint64_t AddrLoc = getOutputSection()->Addr + Offset; + RelExpr Expr = Rel.Expr; + uint64_t TargetVA = SignExtend64( + getRelocTargetVA(File, Type, Rel.Addend, AddrLoc, *Rel.Sym, Expr), + Bits); - switch (expr) { + switch (Expr) { case R_RELAX_GOT_PC: case R_RELAX_GOT_PC_NOPIC: - target->relaxGot(bufLoc, type, targetVA); + Target->relaxGot(BufLoc, Type, TargetVA); break; case R_PPC64_RELAX_TOC: - if (!tryRelaxPPC64TocIndirection(type, rel, bufLoc)) - target->relocateOne(bufLoc, type, targetVA); + if (!tryRelaxPPC64TocIndirection(Type, Rel, BufLoc)) + Target->relocateOne(BufLoc, Type, TargetVA); break; case R_RELAX_TLS_IE_TO_LE: - target->relaxTlsIeToLe(bufLoc, type, targetVA); + Target->relaxTlsIeToLe(BufLoc, Type, TargetVA); break; case R_RELAX_TLS_LD_TO_LE: case R_RELAX_TLS_LD_TO_LE_ABS: - target->relaxTlsLdToLe(bufLoc, type, targetVA); + Target->relaxTlsLdToLe(BufLoc, Type, TargetVA); break; case R_RELAX_TLS_GD_TO_LE: case R_RELAX_TLS_GD_TO_LE_NEG: - target->relaxTlsGdToLe(bufLoc, type, targetVA); + Target->relaxTlsGdToLe(BufLoc, Type, TargetVA); break; case R_AARCH64_RELAX_TLS_GD_TO_IE_PAGE_PC: case R_RELAX_TLS_GD_TO_IE: case R_RELAX_TLS_GD_TO_IE_ABS: case R_RELAX_TLS_GD_TO_IE_GOT_OFF: case R_RELAX_TLS_GD_TO_IE_GOTPLT: - target->relaxTlsGdToIe(bufLoc, type, targetVA); + Target->relaxTlsGdToIe(BufLoc, Type, TargetVA); break; case R_PPC64_CALL: // If this is a call to __tls_get_addr, it may be part of a TLS // sequence that has been relaxed and turned into a nop. In this // case, we don't want to handle it as a call. - if (read32(bufLoc) == 0x60000000) // nop + if (read32(BufLoc) == 0x60000000) // nop break; // Patch a nop (0x60000000) to a ld. - if (rel.sym->needsTocRestore) { - if (bufLoc + 8 > bufEnd || read32(bufLoc + 4) != 0x60000000) { - error(getErrorLocation(bufLoc) + "call lacks nop, can't restore toc"); + if (Rel.Sym->NeedsTocRestore) { + if (BufLoc + 8 > BufEnd || read32(BufLoc + 4) != 0x60000000) { + error(getErrorLocation(BufLoc) + "call lacks nop, can't restore toc"); break; } - write32(bufLoc + 4, 0xe8410018); // ld %r2, 24(%r1) + write32(BufLoc + 4, 0xe8410018); // ld %r2, 24(%r1) } - target->relocateOne(bufLoc, type, targetVA); + Target->relocateOne(BufLoc, Type, TargetVA); break; default: - target->relocateOne(bufLoc, type, targetVA); + Target->relocateOne(BufLoc, Type, TargetVA); break; } } @@ -990,44 +971,44 @@ void InputSectionBase::relocateAlloc(uint8_t *buf, uint8_t *bufEnd) { // For each function-defining prologue, find any calls to __morestack, // and replace them with calls to __morestack_non_split. static void switchMorestackCallsToMorestackNonSplit( - DenseSet &prologues, std::vector &morestackCalls) { + DenseSet &Prologues, std::vector &MorestackCalls) { // If the target adjusted a function's prologue, all calls to // __morestack inside that function should be switched to // __morestack_non_split. - Symbol *moreStackNonSplit = symtab->find("__morestack_non_split"); - if (!moreStackNonSplit) { + Symbol *MoreStackNonSplit = Symtab->find("__morestack_non_split"); + if (!MoreStackNonSplit) { error("Mixing split-stack objects requires a definition of " "__morestack_non_split"); return; } // Sort both collections to compare addresses efficiently. - llvm::sort(morestackCalls, [](const Relocation *l, const Relocation *r) { - return l->offset < r->offset; + llvm::sort(MorestackCalls, [](const Relocation *L, const Relocation *R) { + return L->Offset < R->Offset; }); - std::vector functions(prologues.begin(), prologues.end()); - llvm::sort(functions, [](const Defined *l, const Defined *r) { - return l->value < r->value; + std::vector Functions(Prologues.begin(), Prologues.end()); + llvm::sort(Functions, [](const Defined *L, const Defined *R) { + return L->Value < R->Value; }); - auto it = morestackCalls.begin(); - for (Defined *f : functions) { + auto It = MorestackCalls.begin(); + for (Defined *F : Functions) { // Find the first call to __morestack within the function. - while (it != morestackCalls.end() && (*it)->offset < f->value) - ++it; + while (It != MorestackCalls.end() && (*It)->Offset < F->Value) + ++It; // Adjust all calls inside the function. - while (it != morestackCalls.end() && (*it)->offset < f->value + f->size) { - (*it)->sym = moreStackNonSplit; - ++it; + while (It != MorestackCalls.end() && (*It)->Offset < F->Value + F->Size) { + (*It)->Sym = MoreStackNonSplit; + ++It; } } } -static bool enclosingPrologueAttempted(uint64_t offset, - const DenseSet &prologues) { - for (Defined *f : prologues) - if (f->value <= offset && offset < f->value + f->size) +static bool enclosingPrologueAttempted(uint64_t Offset, + const DenseSet &Prologues) { + for (Defined *F : Prologues) + if (F->Value <= Offset && Offset < F->Value + F->Size) return true; return false; } @@ -1037,30 +1018,30 @@ static bool enclosingPrologueAttempted(uint64_t offset, // adjusted to ensure that the called function will have enough stack // available. Find those functions, and adjust their prologues. template -void InputSectionBase::adjustSplitStackFunctionPrologues(uint8_t *buf, - uint8_t *end) { - if (!getFile()->splitStack) +void InputSectionBase::adjustSplitStackFunctionPrologues(uint8_t *Buf, + uint8_t *End) { + if (!getFile()->SplitStack) return; - DenseSet prologues; - std::vector morestackCalls; + DenseSet Prologues; + std::vector MorestackCalls; - for (Relocation &rel : relocations) { + for (Relocation &Rel : Relocations) { // Local symbols can't possibly be cross-calls, and should have been // resolved long before this line. - if (rel.sym->isLocal()) + if (Rel.Sym->isLocal()) continue; // Ignore calls into the split-stack api. - if (rel.sym->getName().startswith("__morestack")) { - if (rel.sym->getName().equals("__morestack")) - morestackCalls.push_back(&rel); + if (Rel.Sym->getName().startswith("__morestack")) { + if (Rel.Sym->getName().equals("__morestack")) + MorestackCalls.push_back(&Rel); continue; } // A relocation to non-function isn't relevant. Sometimes // __morestack is not marked as a function, so this check comes // after the name check. - if (rel.sym->type != STT_FUNC) + if (Rel.Sym->Type != STT_FUNC) continue; // If the callee's-file was compiled with split stack, nothing to do. In @@ -1068,117 +1049,117 @@ void InputSectionBase::adjustSplitStackFunctionPrologues(uint8_t *buf, // being produced". So an "undefined" symbol might be provided by a shared // library. It is not possible to tell how such symbols were compiled, so be // conservative. - if (Defined *d = dyn_cast(rel.sym)) - if (InputSection *isec = cast_or_null(d->section)) - if (!isec || !isec->getFile() || isec->getFile()->splitStack) + if (Defined *D = dyn_cast(Rel.Sym)) + if (InputSection *IS = cast_or_null(D->Section)) + if (!IS || !IS->getFile() || IS->getFile()->SplitStack) continue; - if (enclosingPrologueAttempted(rel.offset, prologues)) + if (enclosingPrologueAttempted(Rel.Offset, Prologues)) continue; - if (Defined *f = getEnclosingFunction(rel.offset)) { - prologues.insert(f); - if (target->adjustPrologueForCrossSplitStack(buf + getOffset(f->value), - end, f->stOther)) + if (Defined *F = getEnclosingFunction(Rel.Offset)) { + Prologues.insert(F); + if (Target->adjustPrologueForCrossSplitStack(Buf + getOffset(F->Value), + End, F->StOther)) continue; - if (!getFile()->someNoSplitStack) - error(lld::toString(this) + ": " + f->getName() + - " (with -fsplit-stack) calls " + rel.sym->getName() + + if (!getFile()->SomeNoSplitStack) + error(lld::toString(this) + ": " + F->getName() + + " (with -fsplit-stack) calls " + Rel.Sym->getName() + " (without -fsplit-stack), but couldn't adjust its prologue"); } } - if (target->needsMoreStackNonSplit) - switchMorestackCallsToMorestackNonSplit(prologues, morestackCalls); + if (Target->NeedsMoreStackNonSplit) + switchMorestackCallsToMorestackNonSplit(Prologues, MorestackCalls); } -template void InputSection::writeTo(uint8_t *buf) { - if (type == SHT_NOBITS) +template void InputSection::writeTo(uint8_t *Buf) { + if (Type == SHT_NOBITS) return; - if (auto *s = dyn_cast(this)) { - s->writeTo(buf + outSecOff); + if (auto *S = dyn_cast(this)) { + S->writeTo(Buf + OutSecOff); return; } // If -r or --emit-relocs is given, then an InputSection // may be a relocation section. - if (type == SHT_RELA) { - copyRelocations(buf + outSecOff, getDataAs()); + if (Type == SHT_RELA) { + copyRelocations(Buf + OutSecOff, getDataAs()); return; } - if (type == SHT_REL) { - copyRelocations(buf + outSecOff, getDataAs()); + if (Type == SHT_REL) { + copyRelocations(Buf + OutSecOff, getDataAs()); return; } // If -r is given, we may have a SHT_GROUP section. - if (type == SHT_GROUP) { - copyShtGroup(buf + outSecOff); + if (Type == SHT_GROUP) { + copyShtGroup(Buf + OutSecOff); return; } // If this is a compressed section, uncompress section contents directly // to the buffer. - if (uncompressedSize >= 0) { - size_t size = uncompressedSize; - if (Error e = zlib::uncompress(toStringRef(rawData), - (char *)(buf + outSecOff), size)) + if (UncompressedSize >= 0) { + size_t Size = UncompressedSize; + if (Error E = zlib::uncompress(toStringRef(RawData), + (char *)(Buf + OutSecOff), Size)) fatal(toString(this) + - ": uncompress failed: " + llvm::toString(std::move(e))); - uint8_t *bufEnd = buf + outSecOff + size; - relocate(buf, bufEnd); + ": uncompress failed: " + llvm::toString(std::move(E))); + uint8_t *BufEnd = Buf + OutSecOff + Size; + relocate(Buf, BufEnd); return; } // Copy section contents from source object file to output file // and then apply relocations. - memcpy(buf + outSecOff, data().data(), data().size()); - uint8_t *bufEnd = buf + outSecOff + data().size(); - relocate(buf, bufEnd); + memcpy(Buf + OutSecOff, data().data(), data().size()); + uint8_t *BufEnd = Buf + OutSecOff + data().size(); + relocate(Buf, BufEnd); } -void InputSection::replace(InputSection *other) { - alignment = std::max(alignment, other->alignment); +void InputSection::replace(InputSection *Other) { + Alignment = std::max(Alignment, Other->Alignment); // When a section is replaced with another section that was allocated to // another partition, the replacement section (and its associated sections) // need to be placed in the main partition so that both partitions will be // able to access it. - if (partition != other->partition) { - partition = 1; - for (InputSection *isec : dependentSections) - isec->partition = 1; + if (Partition != Other->Partition) { + Partition = 1; + for (InputSection *IS : DependentSections) + IS->Partition = 1; } - other->repl = repl; - other->markDead(); + Other->Repl = Repl; + Other->markDead(); } template -EhInputSection::EhInputSection(ObjFile &f, - const typename ELFT::Shdr &header, - StringRef name) - : InputSectionBase(f, header, name, InputSectionBase::EHFrame) {} +EhInputSection::EhInputSection(ObjFile &F, + const typename ELFT::Shdr &Header, + StringRef Name) + : InputSectionBase(F, Header, Name, InputSectionBase::EHFrame) {} SyntheticSection *EhInputSection::getParent() const { - return cast_or_null(parent); + return cast_or_null(Parent); } // Returns the index of the first relocation that points to a region between // Begin and Begin+Size. template -static unsigned getReloc(IntTy begin, IntTy size, const ArrayRef &rels, - unsigned &relocI) { +static unsigned getReloc(IntTy Begin, IntTy Size, const ArrayRef &Rels, + unsigned &RelocI) { // Start search from RelocI for fast access. That works because the // relocations are sorted in .eh_frame. - for (unsigned n = rels.size(); relocI < n; ++relocI) { - const RelTy &rel = rels[relocI]; - if (rel.r_offset < begin) + for (unsigned N = Rels.size(); RelocI < N; ++RelocI) { + const RelTy &Rel = Rels[RelocI]; + if (Rel.r_offset < Begin) continue; - if (rel.r_offset < begin + size) - return relocI; + if (Rel.r_offset < Begin + Size) + return RelocI; return -1; } return -1; @@ -1187,84 +1168,84 @@ static unsigned getReloc(IntTy begin, IntTy size, const ArrayRef &rels, // .eh_frame is a sequence of CIE or FDE records. // This function splits an input section into records and returns them. template void EhInputSection::split() { - if (areRelocsRela) + if (AreRelocsRela) split(relas()); else split(rels()); } template -void EhInputSection::split(ArrayRef rels) { - unsigned relI = 0; - for (size_t off = 0, end = data().size(); off != end;) { - size_t size = readEhRecordSize(this, off); - pieces.emplace_back(off, this, size, getReloc(off, size, rels, relI)); +void EhInputSection::split(ArrayRef Rels) { + unsigned RelI = 0; + for (size_t Off = 0, End = data().size(); Off != End;) { + size_t Size = readEhRecordSize(this, Off); + Pieces.emplace_back(Off, this, Size, getReloc(Off, Size, Rels, RelI)); // The empty record is the end marker. - if (size == 4) + if (Size == 4) break; - off += size; + Off += Size; } } -static size_t findNull(StringRef s, size_t entSize) { +static size_t findNull(StringRef S, size_t EntSize) { // Optimize the common case. - if (entSize == 1) - return s.find(0); + if (EntSize == 1) + return S.find(0); - for (unsigned i = 0, n = s.size(); i != n; i += entSize) { - const char *b = s.begin() + i; - if (std::all_of(b, b + entSize, [](char c) { return c == 0; })) - return i; + for (unsigned I = 0, N = S.size(); I != N; I += EntSize) { + const char *B = S.begin() + I; + if (std::all_of(B, B + EntSize, [](char C) { return C == 0; })) + return I; } return StringRef::npos; } SyntheticSection *MergeInputSection::getParent() const { - return cast_or_null(parent); + return cast_or_null(Parent); } // Split SHF_STRINGS section. Such section is a sequence of // null-terminated strings. -void MergeInputSection::splitStrings(ArrayRef data, size_t entSize) { - size_t off = 0; - bool isAlloc = flags & SHF_ALLOC; - StringRef s = toStringRef(data); - - while (!s.empty()) { - size_t end = findNull(s, entSize); - if (end == StringRef::npos) +void MergeInputSection::splitStrings(ArrayRef Data, size_t EntSize) { + size_t Off = 0; + bool IsAlloc = Flags & SHF_ALLOC; + StringRef S = toStringRef(Data); + + while (!S.empty()) { + size_t End = findNull(S, EntSize); + if (End == StringRef::npos) fatal(toString(this) + ": string is not null terminated"); - size_t size = end + entSize; + size_t Size = End + EntSize; - pieces.emplace_back(off, xxHash64(s.substr(0, size)), !isAlloc); - s = s.substr(size); - off += size; + Pieces.emplace_back(Off, xxHash64(S.substr(0, Size)), !IsAlloc); + S = S.substr(Size); + Off += Size; } } // Split non-SHF_STRINGS section. Such section is a sequence of // fixed size records. -void MergeInputSection::splitNonStrings(ArrayRef data, - size_t entSize) { - size_t size = data.size(); - assert((size % entSize) == 0); - bool isAlloc = flags & SHF_ALLOC; - - for (size_t i = 0; i != size; i += entSize) - pieces.emplace_back(i, xxHash64(data.slice(i, entSize)), !isAlloc); +void MergeInputSection::splitNonStrings(ArrayRef Data, + size_t EntSize) { + size_t Size = Data.size(); + assert((Size % EntSize) == 0); + bool IsAlloc = Flags & SHF_ALLOC; + + for (size_t I = 0; I != Size; I += EntSize) + Pieces.emplace_back(I, xxHash64(Data.slice(I, EntSize)), !IsAlloc); } template -MergeInputSection::MergeInputSection(ObjFile &f, - const typename ELFT::Shdr &header, - StringRef name) - : InputSectionBase(f, header, name, InputSectionBase::Merge) {} +MergeInputSection::MergeInputSection(ObjFile &F, + const typename ELFT::Shdr &Header, + StringRef Name) + : InputSectionBase(F, Header, Name, InputSectionBase::Merge) {} -MergeInputSection::MergeInputSection(uint64_t flags, uint32_t type, - uint64_t entsize, ArrayRef data, - StringRef name) - : InputSectionBase(nullptr, flags, type, entsize, /*Link*/ 0, /*Info*/ 0, - /*Alignment*/ entsize, data, name, SectionBase::Merge) {} +MergeInputSection::MergeInputSection(uint64_t Flags, uint32_t Type, + uint64_t Entsize, ArrayRef Data, + StringRef Name) + : InputSectionBase(nullptr, Flags, Type, Entsize, /*Link*/ 0, /*Info*/ 0, + /*Alignment*/ Entsize, Data, Name, SectionBase::Merge) {} // This function is called after we obtain a complete list of input sections // that need to be linked. This is responsible to split section contents @@ -1273,35 +1254,35 @@ MergeInputSection::MergeInputSection(uint64_t flags, uint32_t type, // Note that this function is called from parallelForEach. This must be // thread-safe (i.e. no memory allocation from the pools). void MergeInputSection::splitIntoPieces() { - assert(pieces.empty()); + assert(Pieces.empty()); - if (flags & SHF_STRINGS) - splitStrings(data(), entsize); + if (Flags & SHF_STRINGS) + splitStrings(data(), Entsize); else - splitNonStrings(data(), entsize); + splitNonStrings(data(), Entsize); } -SectionPiece *MergeInputSection::getSectionPiece(uint64_t offset) { - if (this->data().size() <= offset) +SectionPiece *MergeInputSection::getSectionPiece(uint64_t Offset) { + if (this->data().size() <= Offset) fatal(toString(this) + ": offset is outside the section"); // If Offset is not at beginning of a section piece, it is not in the map. // In that case we need to do a binary search of the original section piece vector. - auto it = partition_point( - pieces, [=](SectionPiece p) { return p.inputOff <= offset; }); - return &it[-1]; + auto It = llvm::bsearch(Pieces, + [=](SectionPiece P) { return Offset < P.InputOff; }); + return &It[-1]; } // Returns the offset in an output section for a given input offset. // Because contents of a mergeable section is not contiguous in output, // it is not just an addition to a base output offset. -uint64_t MergeInputSection::getParentOffset(uint64_t offset) const { +uint64_t MergeInputSection::getParentOffset(uint64_t Offset) const { // If Offset is not at beginning of a section piece, it is not in the map. // In that case we need to search from the original section piece vector. - const SectionPiece &piece = - *(const_cast(this)->getSectionPiece (offset)); - uint64_t addend = offset - piece.inputOff; - return piece.outputOff + addend; + const SectionPiece &Piece = + *(const_cast(this)->getSectionPiece (Offset)); + uint64_t Addend = Offset - Piece.InputOff; + return Piece.OutputOff + Addend; } template InputSection::InputSection(ObjFile &, const ELF32LE::Shdr &, diff --git a/lld/ELF/InputSection.h b/lld/ELF/InputSection.h index 3a974074e0e51a..bf678ce030bc63 100644 --- a/lld/ELF/InputSection.h +++ b/lld/ELF/InputSection.h @@ -31,7 +31,7 @@ class MergeSyntheticSection; template class ObjFile; class OutputSection; -extern std::vector partitions; +extern std::vector Partitions; // This is the base class of all sections that lld handles. Some are sections in // input files, some are sections in the produced output file and some exist @@ -41,18 +41,18 @@ class SectionBase { public: enum Kind { Regular, EHFrame, Merge, Synthetic, Output }; - Kind kind() const { return (Kind)sectionKind; } + Kind kind() const { return (Kind)SectionKind; } - StringRef name; + StringRef Name; // This pointer points to the "real" instance of this instance. // Usually Repl == this. However, if ICF merges two sections, // Repl pointer of one section points to another section. So, // if you need to get a pointer to this instance, do not use // this but instead this->Repl. - SectionBase *repl; + SectionBase *Repl; - unsigned sectionKind : 3; + unsigned SectionKind : 3; // The next three bit fields are only used by InputSectionBase, but we // put them here so the struct packs better. @@ -68,26 +68,26 @@ class SectionBase { // .foo takes all .text sections, and .bar becomes empty. To achieve // this, we need to memorize whether a section has been placed or // not for each input section. - unsigned assigned : 1; + unsigned Assigned : 1; - unsigned bss : 1; + unsigned Bss : 1; // Set for sections that should not be folded by ICF. - unsigned keepUnique : 1; + unsigned KeepUnique : 1; // The 1-indexed partition that this section is assigned to by the garbage // collector, or 0 if this section is dead. Normally there is only one // partition, so this will either be 0 or 1. - uint8_t partition; + uint8_t Partition; elf::Partition &getPartition() const; // These corresponds to the fields in Elf_Shdr. - uint32_t alignment; - uint64_t flags; - uint64_t entsize; - uint32_t type; - uint32_t link; - uint32_t info; + uint32_t Alignment; + uint64_t Flags; + uint64_t Entsize; + uint32_t Type; + uint32_t Link; + uint32_t Info; OutputSection *getOutputSection(); const OutputSection *getOutputSection() const { @@ -96,55 +96,55 @@ class SectionBase { // Translate an offset in the input section to an offset in the output // section. - uint64_t getOffset(uint64_t offset) const; + uint64_t getOffset(uint64_t Offset) const; - uint64_t getVA(uint64_t offset = 0) const; + uint64_t getVA(uint64_t Offset = 0) const; - bool isLive() const { return partition != 0; } - void markLive() { partition = 1; } - void markDead() { partition = 0; } + bool isLive() const { return Partition != 0; } + void markLive() { Partition = 1; } + void markDead() { Partition = 0; } protected: - SectionBase(Kind sectionKind, StringRef name, uint64_t flags, - uint64_t entsize, uint64_t alignment, uint32_t type, - uint32_t info, uint32_t link) - : name(name), repl(this), sectionKind(sectionKind), assigned(false), - bss(false), keepUnique(false), partition(0), alignment(alignment), - flags(flags), entsize(entsize), type(type), link(link), info(info) {} + SectionBase(Kind SectionKind, StringRef Name, uint64_t Flags, + uint64_t Entsize, uint64_t Alignment, uint32_t Type, + uint32_t Info, uint32_t Link) + : Name(Name), Repl(this), SectionKind(SectionKind), Assigned(false), + Bss(false), KeepUnique(false), Partition(0), Alignment(Alignment), + Flags(Flags), Entsize(Entsize), Type(Type), Link(Link), Info(Info) {} }; // This corresponds to a section of an input file. class InputSectionBase : public SectionBase { public: template - InputSectionBase(ObjFile &file, const typename ELFT::Shdr &header, - StringRef name, Kind sectionKind); + InputSectionBase(ObjFile &File, const typename ELFT::Shdr &Header, + StringRef Name, Kind SectionKind); - InputSectionBase(InputFile *file, uint64_t flags, uint32_t type, - uint64_t entsize, uint32_t link, uint32_t info, - uint32_t alignment, ArrayRef data, StringRef name, - Kind sectionKind); + InputSectionBase(InputFile *File, uint64_t Flags, uint32_t Type, + uint64_t Entsize, uint32_t Link, uint32_t Info, + uint32_t Alignment, ArrayRef Data, StringRef Name, + Kind SectionKind); - static bool classof(const SectionBase *s) { return s->kind() != Output; } + static bool classof(const SectionBase *S) { return S->kind() != Output; } // Relocations that refer to this section. - unsigned numRelocations : 31; - unsigned areRelocsRela : 1; - const void *firstRelocation = nullptr; + unsigned NumRelocations : 31; + unsigned AreRelocsRela : 1; + const void *FirstRelocation = nullptr; // The file which contains this section. Its dynamic type is always // ObjFile, but in order to avoid ELFT, we use InputFile as // its static type. - InputFile *file; + InputFile *File; template ObjFile *getFile() const { - return cast_or_null>(file); + return cast_or_null>(File); } ArrayRef data() const { - if (uncompressedSize >= 0) + if (UncompressedSize >= 0) uncompress(); - return rawData; + return RawData; } uint64_t getOffsetInFile() const; @@ -153,24 +153,24 @@ class InputSectionBase : public SectionBase { // like .eh_frame and merge sections are first combined into a // synthetic section that is then added to an output section. In all // cases this points one level up. - SectionBase *parent = nullptr; + SectionBase *Parent = nullptr; template ArrayRef rels() const { - assert(!areRelocsRela); + assert(!AreRelocsRela); return llvm::makeArrayRef( - static_cast(firstRelocation), - numRelocations); + static_cast(FirstRelocation), + NumRelocations); } template ArrayRef relas() const { - assert(areRelocsRela); + assert(AreRelocsRela); return llvm::makeArrayRef( - static_cast(firstRelocation), - numRelocations); + static_cast(FirstRelocation), + NumRelocations); } // InputSections that are dependent on us (reverse dependency for GC) - llvm::TinyPtrVector dependentSections; + llvm::TinyPtrVector DependentSections; // Returns the size of this section (even if this is a common or BSS.) size_t getSize() const; @@ -180,23 +180,23 @@ class InputSectionBase : public SectionBase { // Get the function symbol that encloses this offset from within the // section. template - Defined *getEnclosingFunction(uint64_t offset); + Defined *getEnclosingFunction(uint64_t Offset); // Returns a source location string. Used to construct an error message. - template std::string getLocation(uint64_t offset); - std::string getSrcMsg(const Symbol &sym, uint64_t offset); - std::string getObjMsg(uint64_t offset); + template std::string getLocation(uint64_t Offset); + std::string getSrcMsg(const Symbol &Sym, uint64_t Offset); + std::string getObjMsg(uint64_t Offset); // Each section knows how to relocate itself. These functions apply // relocations, assuming that Buf points to this section's copy in // the mmap'ed output buffer. - template void relocate(uint8_t *buf, uint8_t *bufEnd); - void relocateAlloc(uint8_t *buf, uint8_t *bufEnd); + template void relocate(uint8_t *Buf, uint8_t *BufEnd); + void relocateAlloc(uint8_t *Buf, uint8_t *BufEnd); // The native ELF reloc data type is not very convenient to handle. // So we convert ELF reloc records to our own records in Relocations.cpp. // This vector contains such "cooked" relocations. - std::vector relocations; + std::vector Relocations; // A function compiled with -fsplit-stack calling a function // compiled without -fsplit-stack needs its prologue adjusted. Find @@ -204,26 +204,26 @@ class InputSectionBase : public SectionBase { // to relocation. See https://gcc.gnu.org/wiki/SplitStacks for more // information. template - void adjustSplitStackFunctionPrologues(uint8_t *buf, uint8_t *end); + void adjustSplitStackFunctionPrologues(uint8_t *Buf, uint8_t *End); template llvm::ArrayRef getDataAs() const { - size_t s = data().size(); - assert(s % sizeof(T) == 0); - return llvm::makeArrayRef((const T *)data().data(), s / sizeof(T)); + size_t S = data().size(); + assert(S % sizeof(T) == 0); + return llvm::makeArrayRef((const T *)data().data(), S / sizeof(T)); } protected: void parseCompressedHeader(); void uncompress() const; - mutable ArrayRef rawData; + mutable ArrayRef RawData; - // This field stores the uncompressed size of the compressed data in rawData, - // or -1 if rawData is not compressed (either because the section wasn't + // This field stores the uncompressed size of the compressed data in RawData, + // or -1 if RawData is not compressed (either because the section wasn't // compressed in the first place, or because we ended up uncompressing it). // Since the feature is not used often, this is usually -1. - mutable int64_t uncompressedSize = -1; + mutable int64_t UncompressedSize = -1; }; // SectionPiece represents a piece of splittable section contents. @@ -231,13 +231,13 @@ class InputSectionBase : public SectionBase { // have to be as compact as possible, which is why we don't store the size (can // be found by looking at the next one). struct SectionPiece { - SectionPiece(size_t off, uint32_t hash, bool live) - : inputOff(off), live(live || !config->gcSections), hash(hash >> 1) {} + SectionPiece(size_t Off, uint32_t Hash, bool Live) + : InputOff(Off), Live(Live || !Config->GcSections), Hash(Hash >> 1) {} - uint32_t inputOff; - uint32_t live : 1; - uint32_t hash : 31; - uint64_t outputOff = 0; + uint32_t InputOff; + uint32_t Live : 1; + uint32_t Hash : 31; + uint64_t OutputOff = 0; }; static_assert(sizeof(SectionPiece) == 16, "SectionPiece is too big"); @@ -246,74 +246,74 @@ static_assert(sizeof(SectionPiece) == 16, "SectionPiece is too big"); class MergeInputSection : public InputSectionBase { public: template - MergeInputSection(ObjFile &f, const typename ELFT::Shdr &header, - StringRef name); - MergeInputSection(uint64_t flags, uint32_t type, uint64_t entsize, - ArrayRef data, StringRef name); + MergeInputSection(ObjFile &F, const typename ELFT::Shdr &Header, + StringRef Name); + MergeInputSection(uint64_t Flags, uint32_t Type, uint64_t Entsize, + ArrayRef Data, StringRef Name); - static bool classof(const SectionBase *s) { return s->kind() == Merge; } + static bool classof(const SectionBase *S) { return S->kind() == Merge; } void splitIntoPieces(); // Translate an offset in the input section to an offset in the parent // MergeSyntheticSection. - uint64_t getParentOffset(uint64_t offset) const; + uint64_t getParentOffset(uint64_t Offset) const; // Splittable sections are handled as a sequence of data // rather than a single large blob of data. - std::vector pieces; + std::vector Pieces; // Returns I'th piece's data. This function is very hot when // string merging is enabled, so we want to inline. LLVM_ATTRIBUTE_ALWAYS_INLINE - llvm::CachedHashStringRef getData(size_t i) const { - size_t begin = pieces[i].inputOff; - size_t end = - (pieces.size() - 1 == i) ? data().size() : pieces[i + 1].inputOff; - return {toStringRef(data().slice(begin, end - begin)), pieces[i].hash}; + llvm::CachedHashStringRef getData(size_t I) const { + size_t Begin = Pieces[I].InputOff; + size_t End = + (Pieces.size() - 1 == I) ? data().size() : Pieces[I + 1].InputOff; + return {toStringRef(data().slice(Begin, End - Begin)), Pieces[I].Hash}; } // Returns the SectionPiece at a given input section offset. - SectionPiece *getSectionPiece(uint64_t offset); - const SectionPiece *getSectionPiece(uint64_t offset) const { - return const_cast(this)->getSectionPiece(offset); + SectionPiece *getSectionPiece(uint64_t Offset); + const SectionPiece *getSectionPiece(uint64_t Offset) const { + return const_cast(this)->getSectionPiece(Offset); } SyntheticSection *getParent() const; private: - void splitStrings(ArrayRef a, size_t size); - void splitNonStrings(ArrayRef a, size_t size); + void splitStrings(ArrayRef A, size_t Size); + void splitNonStrings(ArrayRef A, size_t Size); }; struct EhSectionPiece { - EhSectionPiece(size_t off, InputSectionBase *sec, uint32_t size, - unsigned firstRelocation) - : inputOff(off), sec(sec), size(size), firstRelocation(firstRelocation) {} + EhSectionPiece(size_t Off, InputSectionBase *Sec, uint32_t Size, + unsigned FirstRelocation) + : InputOff(Off), Sec(Sec), Size(Size), FirstRelocation(FirstRelocation) {} ArrayRef data() { - return {sec->data().data() + this->inputOff, size}; + return {Sec->data().data() + this->InputOff, Size}; } - size_t inputOff; - ssize_t outputOff = -1; - InputSectionBase *sec; - uint32_t size; - unsigned firstRelocation; + size_t InputOff; + ssize_t OutputOff = -1; + InputSectionBase *Sec; + uint32_t Size; + unsigned FirstRelocation; }; // This corresponds to a .eh_frame section of an input file. class EhInputSection : public InputSectionBase { public: template - EhInputSection(ObjFile &f, const typename ELFT::Shdr &header, - StringRef name); - static bool classof(const SectionBase *s) { return s->kind() == EHFrame; } + EhInputSection(ObjFile &F, const typename ELFT::Shdr &Header, + StringRef Name); + static bool classof(const SectionBase *S) { return S->kind() == EHFrame; } template void split(); - template void split(ArrayRef rels); + template void split(ArrayRef Rels); // Splittable sections are handled as a sequence of data // rather than a single large blob of data. - std::vector pieces; + std::vector Pieces; SyntheticSection *getParent() const; }; @@ -324,17 +324,17 @@ class EhInputSection : public InputSectionBase { // .eh_frame. It also includes the synthetic sections themselves. class InputSection : public InputSectionBase { public: - InputSection(InputFile *f, uint64_t flags, uint32_t type, uint32_t alignment, - ArrayRef data, StringRef name, Kind k = Regular); + InputSection(InputFile *F, uint64_t Flags, uint32_t Type, uint32_t Alignment, + ArrayRef Data, StringRef Name, Kind K = Regular); template - InputSection(ObjFile &f, const typename ELFT::Shdr &header, - StringRef name); + InputSection(ObjFile &F, const typename ELFT::Shdr &Header, + StringRef Name); // Write this section to a mmap'ed file, assuming Buf is pointing to // beginning of the output section. - template void writeTo(uint8_t *buf); + template void writeTo(uint8_t *Buf); - uint64_t getOffset(uint64_t offset) const { return outSecOff + offset; } + uint64_t getOffset(uint64_t Offset) const { return OutSecOff + Offset; } OutputSection *getParent() const; @@ -342,32 +342,32 @@ class InputSection : public InputSectionBase { // OutputSection's InputSection list, and is used when ordering SHF_LINK_ORDER // sections. After assignAddresses is called, it represents the offset from // the beginning of the output section this section was assigned to. - uint64_t outSecOff = 0; + uint64_t OutSecOff = 0; - static bool classof(const SectionBase *s); + static bool classof(const SectionBase *S); InputSectionBase *getRelocatedSection() const; template - void relocateNonAlloc(uint8_t *buf, llvm::ArrayRef rels); + void relocateNonAlloc(uint8_t *Buf, llvm::ArrayRef Rels); // Used by ICF. - uint32_t eqClass[2] = {0, 0}; + uint32_t Class[2] = {0, 0}; // Called by ICF to merge two input sections. - void replace(InputSection *other); + void replace(InputSection *Other); - static InputSection discarded; + static InputSection Discarded; private: template - void copyRelocations(uint8_t *buf, llvm::ArrayRef rels); + void copyRelocations(uint8_t *Buf, llvm::ArrayRef Rels); - template void copyShtGroup(uint8_t *buf); + template void copyShtGroup(uint8_t *Buf); }; // The list of all input sections. -extern std::vector inputSections; +extern std::vector InputSections; } // namespace elf diff --git a/lld/ELF/LTO.cpp b/lld/ELF/LTO.cpp index 00c87fd5f489d5..361205973c08f5 100644 --- a/lld/ELF/LTO.cpp +++ b/lld/ELF/LTO.cpp @@ -47,137 +47,135 @@ using namespace lld::elf; // Creates an empty file to store a list of object files for final // linking of distributed ThinLTO. -static std::unique_ptr openFile(StringRef file) { - std::error_code ec; - auto ret = - std::make_unique(file, ec, sys::fs::OpenFlags::OF_None); - if (ec) { - error("cannot open " + file + ": " + ec.message()); +static std::unique_ptr openFile(StringRef File) { + std::error_code EC; + auto Ret = + llvm::make_unique(File, EC, sys::fs::OpenFlags::F_None); + if (EC) { + error("cannot open " + File + ": " + EC.message()); return nullptr; } - return ret; + return Ret; } -static std::string getThinLTOOutputFile(StringRef modulePath) { - return lto::getThinLTOOutputFile(modulePath, - config->thinLTOPrefixReplace.first, - config->thinLTOPrefixReplace.second); +static std::string getThinLTOOutputFile(StringRef ModulePath) { + return lto::getThinLTOOutputFile(ModulePath, + Config->ThinLTOPrefixReplace.first, + Config->ThinLTOPrefixReplace.second); } static lto::Config createConfig() { - lto::Config c; + lto::Config C; // LLD supports the new relocations and address-significance tables. - c.Options = initTargetOptionsFromCodeGenFlags(); - c.Options.RelaxELFRelocations = true; - c.Options.EmitAddrsig = true; + C.Options = initTargetOptionsFromCodeGenFlags(); + C.Options.RelaxELFRelocations = true; + C.Options.EmitAddrsig = true; // Always emit a section per function/datum with LTO. - c.Options.FunctionSections = true; - c.Options.DataSections = true; - - if (auto relocModel = getRelocModelFromCMModel()) - c.RelocModel = *relocModel; - else if (config->relocatable) - c.RelocModel = None; - else if (config->isPic) - c.RelocModel = Reloc::PIC_; + C.Options.FunctionSections = true; + C.Options.DataSections = true; + + if (Config->Relocatable) + C.RelocModel = None; + else if (Config->Pic) + C.RelocModel = Reloc::PIC_; else - c.RelocModel = Reloc::Static; + C.RelocModel = Reloc::Static; - c.CodeModel = getCodeModelFromCMModel(); - c.DisableVerify = config->disableVerify; - c.DiagHandler = diagnosticHandler; - c.OptLevel = config->ltoo; - c.CPU = getCPUStr(); - c.MAttrs = getMAttrs(); - c.CGOptLevel = args::getCGOptLevel(config->ltoo); + C.CodeModel = getCodeModelFromCMModel(); + C.DisableVerify = Config->DisableVerify; + C.DiagHandler = diagnosticHandler; + C.OptLevel = Config->LTOO; + C.CPU = getCPUStr(); + C.MAttrs = getMAttrs(); + C.CGOptLevel = args::getCGOptLevel(Config->LTOO); // Set up a custom pipeline if we've been asked to. - c.OptPipeline = config->ltoNewPmPasses; - c.AAPipeline = config->ltoAAPipeline; + C.OptPipeline = Config->LTONewPmPasses; + C.AAPipeline = Config->LTOAAPipeline; // Set up optimization remarks if we've been asked to. - c.RemarksFilename = config->optRemarksFilename; - c.RemarksPasses = config->optRemarksPasses; - c.RemarksWithHotness = config->optRemarksWithHotness; - c.RemarksFormat = config->optRemarksFormat; - - c.SampleProfile = config->ltoSampleProfile; - c.UseNewPM = config->ltoNewPassManager; - c.DebugPassManager = config->ltoDebugPassManager; - c.DwoDir = config->dwoDir; - - c.CSIRProfile = config->ltoCSProfileFile; - c.RunCSIRInstr = config->ltoCSProfileGenerate; - - if (config->emitLLVM) { - c.PostInternalizeModuleHook = [](size_t task, const Module &m) { - if (std::unique_ptr os = openFile(config->outputFile)) - WriteBitcodeToFile(m, *os, false); + C.RemarksFilename = Config->OptRemarksFilename; + C.RemarksPasses = Config->OptRemarksPasses; + C.RemarksWithHotness = Config->OptRemarksWithHotness; + C.RemarksFormat = Config->OptRemarksFormat; + + C.SampleProfile = Config->LTOSampleProfile; + C.UseNewPM = Config->LTONewPassManager; + C.DebugPassManager = Config->LTODebugPassManager; + C.DwoDir = Config->DwoDir; + + C.CSIRProfile = Config->LTOCSProfileFile; + C.RunCSIRInstr = Config->LTOCSProfileGenerate; + + if (Config->EmitLLVM) { + C.PostInternalizeModuleHook = [](size_t Task, const Module &M) { + if (std::unique_ptr OS = openFile(Config->OutputFile)) + WriteBitcodeToFile(M, *OS, false); return false; }; } - if (config->saveTemps) - checkError(c.addSaveTemps(config->outputFile.str() + ".", + if (Config->SaveTemps) + checkError(C.addSaveTemps(Config->OutputFile.str() + ".", /*UseInputModulePath*/ true)); - return c; + return C; } BitcodeCompiler::BitcodeCompiler() { - // Initialize indexFile. - if (!config->thinLTOIndexOnlyArg.empty()) - indexFile = openFile(config->thinLTOIndexOnlyArg); - - // Initialize ltoObj. - lto::ThinBackend backend; - if (config->thinLTOIndexOnly) { - auto onIndexWrite = [&](StringRef s) { thinIndices.erase(s); }; - backend = lto::createWriteIndexesThinBackend( - config->thinLTOPrefixReplace.first, config->thinLTOPrefixReplace.second, - config->thinLTOEmitImportsFiles, indexFile.get(), onIndexWrite); - } else if (config->thinLTOJobs != -1U) { - backend = lto::createInProcessThinBackend(config->thinLTOJobs); + // Initialize IndexFile. + if (!Config->ThinLTOIndexOnlyArg.empty()) + IndexFile = openFile(Config->ThinLTOIndexOnlyArg); + + // Initialize LTOObj. + lto::ThinBackend Backend; + if (Config->ThinLTOIndexOnly) { + auto OnIndexWrite = [&](StringRef S) { ThinIndices.erase(S); }; + Backend = lto::createWriteIndexesThinBackend( + Config->ThinLTOPrefixReplace.first, Config->ThinLTOPrefixReplace.second, + Config->ThinLTOEmitImportsFiles, IndexFile.get(), OnIndexWrite); + } else if (Config->ThinLTOJobs != -1U) { + Backend = lto::createInProcessThinBackend(Config->ThinLTOJobs); } - ltoObj = std::make_unique(createConfig(), backend, - config->ltoPartitions); + LTOObj = llvm::make_unique(createConfig(), Backend, + Config->LTOPartitions); - // Initialize usedStartStop. - symtab->forEachSymbol([&](Symbol *sym) { - StringRef s = sym->getName(); - for (StringRef prefix : {"__start_", "__stop_"}) - if (s.startswith(prefix)) - usedStartStop.insert(s.substr(prefix.size())); + // Initialize UsedStartStop. + Symtab->forEachSymbol([&](Symbol *Sym) { + StringRef S = Sym->getName(); + for (StringRef Prefix : {"__start_", "__stop_"}) + if (S.startswith(Prefix)) + UsedStartStop.insert(S.substr(Prefix.size())); }); } BitcodeCompiler::~BitcodeCompiler() = default; -void BitcodeCompiler::add(BitcodeFile &f) { - lto::InputFile &obj = *f.obj; - bool isExec = !config->shared && !config->relocatable; +void BitcodeCompiler::add(BitcodeFile &F) { + lto::InputFile &Obj = *F.Obj; + bool IsExec = !Config->Shared && !Config->Relocatable; - if (config->thinLTOIndexOnly) - thinIndices.insert(obj.getName()); + if (Config->ThinLTOIndexOnly) + ThinIndices.insert(Obj.getName()); - ArrayRef syms = f.getSymbols(); - ArrayRef objSyms = obj.symbols(); - std::vector resols(syms.size()); + ArrayRef Syms = F.getSymbols(); + ArrayRef ObjSyms = Obj.symbols(); + std::vector Resols(Syms.size()); // Provide a resolution to the LTO API for each symbol. - for (size_t i = 0, e = syms.size(); i != e; ++i) { - Symbol *sym = syms[i]; - const lto::InputFile::Symbol &objSym = objSyms[i]; - lto::SymbolResolution &r = resols[i]; + for (size_t I = 0, E = Syms.size(); I != E; ++I) { + Symbol *Sym = Syms[I]; + const lto::InputFile::Symbol &ObjSym = ObjSyms[I]; + lto::SymbolResolution &R = Resols[I]; // Ideally we shouldn't check for SF_Undefined but currently IRObjectFile // reports two symbols for module ASM defined. Without this check, lld // flags an undefined in IR with a definition in ASM as prevailing. // Once IRObjectFile is fixed to report only one symbol this hack can // be removed. - r.Prevailing = !objSym.isUndefined() && sym->file == &f; + R.Prevailing = !ObjSym.isUndefined() && Sym->File == &F; // We ask LTO to preserve following global symbols: // 1) All symbols when doing relocatable link, so that them can be used @@ -185,121 +183,121 @@ void BitcodeCompiler::add(BitcodeFile &f) { // 2) Symbols that are used in regular objects. // 3) C named sections if we have corresponding __start_/__stop_ symbol. // 4) Symbols that are defined in bitcode files and used for dynamic linking. - r.VisibleToRegularObj = config->relocatable || sym->isUsedInRegularObj || - (r.Prevailing && sym->includeInDynsym()) || - usedStartStop.count(objSym.getSectionName()); - const auto *dr = dyn_cast(sym); - r.FinalDefinitionInLinkageUnit = - (isExec || sym->visibility != STV_DEFAULT) && dr && + R.VisibleToRegularObj = Config->Relocatable || Sym->IsUsedInRegularObj || + (R.Prevailing && Sym->includeInDynsym()) || + UsedStartStop.count(ObjSym.getSectionName()); + const auto *DR = dyn_cast(Sym); + R.FinalDefinitionInLinkageUnit = + (IsExec || Sym->Visibility != STV_DEFAULT) && DR && // Skip absolute symbols from ELF objects, otherwise PC-rel relocations // will be generated by for them, triggering linker errors. // Symbol section is always null for bitcode symbols, hence the check // for isElf(). Skip linker script defined symbols as well: they have // no File defined. - !(dr->section == nullptr && (!sym->file || sym->file->isElf())); + !(DR->Section == nullptr && (!Sym->File || Sym->File->isElf())); - if (r.Prevailing) - sym->replace(Undefined{nullptr, sym->getName(), STB_GLOBAL, STV_DEFAULT, - sym->type}); + if (R.Prevailing) + Sym->replace(Undefined{nullptr, Sym->getName(), STB_GLOBAL, STV_DEFAULT, + Sym->Type}); // We tell LTO to not apply interprocedural optimization for wrapped // (with --wrap) symbols because otherwise LTO would inline them while // their values are still not final. - r.LinkerRedefined = !sym->canInline; + R.LinkerRedefined = !Sym->CanInline; } - checkError(ltoObj->add(std::move(f.obj), resols)); + checkError(LTOObj->add(std::move(F.Obj), Resols)); } // If LazyObjFile has not been added to link, emit empty index files. // This is needed because this is what GNU gold plugin does and we have a // distributed build system that depends on that behavior. static void thinLTOCreateEmptyIndexFiles() { - for (LazyObjFile *f : lazyObjFiles) { - if (!isBitcode(f->mb)) + for (LazyObjFile *F : LazyObjFiles) { + if (!isBitcode(F->MB)) continue; - std::string path = replaceThinLTOSuffix(getThinLTOOutputFile(f->getName())); - std::unique_ptr os = openFile(path + ".thinlto.bc"); - if (!os) + std::string Path = replaceThinLTOSuffix(getThinLTOOutputFile(F->getName())); + std::unique_ptr OS = openFile(Path + ".thinlto.bc"); + if (!OS) continue; - ModuleSummaryIndex m(/*HaveGVs*/ false); - m.setSkipModuleByDistributedBackend(); - WriteIndexToFile(m, *os); - if (config->thinLTOEmitImportsFiles) - openFile(path + ".imports"); + ModuleSummaryIndex M(/*HaveGVs*/ false); + M.setSkipModuleByDistributedBackend(); + WriteIndexToFile(M, *OS); + if (Config->ThinLTOEmitImportsFiles) + openFile(Path + ".imports"); } } // Merge all the bitcode files we have seen, codegen the result // and return the resulting ObjectFile(s). std::vector BitcodeCompiler::compile() { - unsigned maxTasks = ltoObj->getMaxTasks(); - buf.resize(maxTasks); - files.resize(maxTasks); + unsigned MaxTasks = LTOObj->getMaxTasks(); + Buf.resize(MaxTasks); + Files.resize(MaxTasks); // The --thinlto-cache-dir option specifies the path to a directory in which // to cache native object files for ThinLTO incremental builds. If a path was // specified, configure LTO to use it as the cache directory. - lto::NativeObjectCache cache; - if (!config->thinLTOCacheDir.empty()) - cache = check( - lto::localCache(config->thinLTOCacheDir, - [&](size_t task, std::unique_ptr mb) { - files[task] = std::move(mb); + lto::NativeObjectCache Cache; + if (!Config->ThinLTOCacheDir.empty()) + Cache = check( + lto::localCache(Config->ThinLTOCacheDir, + [&](size_t Task, std::unique_ptr MB) { + Files[Task] = std::move(MB); })); - if (!bitcodeFiles.empty()) - checkError(ltoObj->run( - [&](size_t task) { - return std::make_unique( - std::make_unique(buf[task])); + if (!BitcodeFiles.empty()) + checkError(LTOObj->run( + [&](size_t Task) { + return llvm::make_unique( + llvm::make_unique(Buf[Task])); }, - cache)); + Cache)); // Emit empty index files for non-indexed files - for (StringRef s : thinIndices) { - std::string path = getThinLTOOutputFile(s); - openFile(path + ".thinlto.bc"); - if (config->thinLTOEmitImportsFiles) - openFile(path + ".imports"); + for (StringRef S : ThinIndices) { + std::string Path = getThinLTOOutputFile(S); + openFile(Path + ".thinlto.bc"); + if (Config->ThinLTOEmitImportsFiles) + openFile(Path + ".imports"); } - if (config->thinLTOIndexOnly) { + if (Config->ThinLTOIndexOnly) { thinLTOCreateEmptyIndexFiles(); - if (!config->ltoObjPath.empty()) - saveBuffer(buf[0], config->ltoObjPath); + if (!Config->LTOObjPath.empty()) + saveBuffer(Buf[0], Config->LTOObjPath); // ThinLTO with index only option is required to generate only the index // files. After that, we exit from linker and ThinLTO backend runs in a // distributed environment. - if (indexFile) - indexFile->close(); + if (IndexFile) + IndexFile->close(); return {}; } - if (!config->thinLTOCacheDir.empty()) - pruneCache(config->thinLTOCacheDir, config->thinLTOCachePolicy); + if (!Config->ThinLTOCacheDir.empty()) + pruneCache(Config->ThinLTOCacheDir, Config->ThinLTOCachePolicy); - if (!config->ltoObjPath.empty()) { - saveBuffer(buf[0], config->ltoObjPath); - for (unsigned i = 1; i != maxTasks; ++i) - saveBuffer(buf[i], config->ltoObjPath + Twine(i)); + if (!Config->LTOObjPath.empty()) { + saveBuffer(Buf[0], Config->LTOObjPath); + for (unsigned I = 1; I != MaxTasks; ++I) + saveBuffer(Buf[I], Config->LTOObjPath + Twine(I)); } - if (config->saveTemps) { - saveBuffer(buf[0], config->outputFile + ".lto.o"); - for (unsigned i = 1; i != maxTasks; ++i) - saveBuffer(buf[i], config->outputFile + Twine(i) + ".lto.o"); + if (Config->SaveTemps) { + saveBuffer(Buf[0], Config->OutputFile + ".lto.o"); + for (unsigned I = 1; I != MaxTasks; ++I) + saveBuffer(Buf[I], Config->OutputFile + Twine(I) + ".lto.o"); } - std::vector ret; - for (unsigned i = 0; i != maxTasks; ++i) - if (!buf[i].empty()) - ret.push_back(createObjectFile(MemoryBufferRef(buf[i], "lto.tmp"))); + std::vector Ret; + for (unsigned I = 0; I != MaxTasks; ++I) + if (!Buf[I].empty()) + Ret.push_back(createObjectFile(MemoryBufferRef(Buf[I], "lto.tmp"))); - for (std::unique_ptr &file : files) - if (file) - ret.push_back(createObjectFile(*file)); - return ret; + for (std::unique_ptr &File : Files) + if (File) + Ret.push_back(createObjectFile(*File)); + return Ret; } diff --git a/lld/ELF/LTO.h b/lld/ELF/LTO.h index 4cb42d84d919f8..0f0b5bce7180b7 100644 --- a/lld/ELF/LTO.h +++ b/lld/ELF/LTO.h @@ -45,16 +45,16 @@ class BitcodeCompiler { BitcodeCompiler(); ~BitcodeCompiler(); - void add(BitcodeFile &f); + void add(BitcodeFile &F); std::vector compile(); private: - std::unique_ptr ltoObj; - std::vector> buf; - std::vector> files; - llvm::DenseSet usedStartStop; - std::unique_ptr indexFile; - llvm::DenseSet thinIndices; + std::unique_ptr LTOObj; + std::vector> Buf; + std::vector> Files; + llvm::DenseSet UsedStartStop; + std::unique_ptr IndexFile; + llvm::DenseSet ThinIndices; }; } // namespace elf } // namespace lld diff --git a/lld/ELF/LinkerScript.cpp b/lld/ELF/LinkerScript.cpp index dbf705dc7f0641..b964a542015800 100644 --- a/lld/ELF/LinkerScript.cpp +++ b/lld/ELF/LinkerScript.cpp @@ -46,24 +46,26 @@ using namespace llvm::support::endian; using namespace lld; using namespace lld::elf; -LinkerScript *elf::script; +LinkerScript *elf::Script; -static uint64_t getOutputSectionVA(SectionBase *sec) { - OutputSection *os = sec->getOutputSection(); - assert(os && "input section has no output section assigned"); - return os ? os->addr : 0; +static uint64_t getOutputSectionVA(SectionBase *InputSec, StringRef Loc) { + if (OutputSection *OS = InputSec->getOutputSection()) + return OS->Addr; + error(Loc + ": unable to evaluate expression: input section " + + InputSec->Name + " has no output section assigned"); + return 0; } uint64_t ExprValue::getValue() const { - if (sec) - return alignTo(sec->getOffset(val) + getOutputSectionVA(sec), - alignment); - return alignTo(val, alignment); + if (Sec) + return alignTo(Sec->getOffset(Val) + getOutputSectionVA(Sec, Loc), + Alignment); + return alignTo(Val, Alignment); } uint64_t ExprValue::getSecAddr() const { - if (sec) - return sec->getOffset(0) + getOutputSectionVA(sec); + if (Sec) + return Sec->getOffset(0) + getOutputSectionVA(Sec, Loc); return 0; } @@ -71,100 +73,100 @@ uint64_t ExprValue::getSectionOffset() const { // If the alignment is trivial, we don't have to compute the full // value to know the offset. This allows this function to succeed in // cases where the output section is not yet known. - if (alignment == 1 && !sec) - return val; + if (Alignment == 1 && (!Sec || !Sec->getOutputSection())) + return Val; return getValue() - getSecAddr(); } -OutputSection *LinkerScript::createOutputSection(StringRef name, - StringRef location) { - OutputSection *&secRef = nameToOutputSection[name]; - OutputSection *sec; - if (secRef && secRef->location.empty()) { +OutputSection *LinkerScript::createOutputSection(StringRef Name, + StringRef Location) { + OutputSection *&SecRef = NameToOutputSection[Name]; + OutputSection *Sec; + if (SecRef && SecRef->Location.empty()) { // There was a forward reference. - sec = secRef; + Sec = SecRef; } else { - sec = make(name, SHT_PROGBITS, 0); - if (!secRef) - secRef = sec; + Sec = make(Name, SHT_PROGBITS, 0); + if (!SecRef) + SecRef = Sec; } - sec->location = location; - return sec; + Sec->Location = Location; + return Sec; } -OutputSection *LinkerScript::getOrCreateOutputSection(StringRef name) { - OutputSection *&cmdRef = nameToOutputSection[name]; - if (!cmdRef) - cmdRef = make(name, SHT_PROGBITS, 0); - return cmdRef; +OutputSection *LinkerScript::getOrCreateOutputSection(StringRef Name) { + OutputSection *&CmdRef = NameToOutputSection[Name]; + if (!CmdRef) + CmdRef = make(Name, SHT_PROGBITS, 0); + return CmdRef; } // Expands the memory region by the specified size. -static void expandMemoryRegion(MemoryRegion *memRegion, uint64_t size, - StringRef regionName, StringRef secName) { - memRegion->curPos += size; - uint64_t newSize = memRegion->curPos - memRegion->origin; - if (newSize > memRegion->length) - error("section '" + secName + "' will not fit in region '" + regionName + - "': overflowed by " + Twine(newSize - memRegion->length) + " bytes"); +static void expandMemoryRegion(MemoryRegion *MemRegion, uint64_t Size, + StringRef RegionName, StringRef SecName) { + MemRegion->CurPos += Size; + uint64_t NewSize = MemRegion->CurPos - MemRegion->Origin; + if (NewSize > MemRegion->Length) + error("section '" + SecName + "' will not fit in region '" + RegionName + + "': overflowed by " + Twine(NewSize - MemRegion->Length) + " bytes"); } -void LinkerScript::expandMemoryRegions(uint64_t size) { - if (ctx->memRegion) - expandMemoryRegion(ctx->memRegion, size, ctx->memRegion->name, - ctx->outSec->name); - // Only expand the LMARegion if it is different from memRegion. - if (ctx->lmaRegion && ctx->memRegion != ctx->lmaRegion) - expandMemoryRegion(ctx->lmaRegion, size, ctx->lmaRegion->name, - ctx->outSec->name); +void LinkerScript::expandMemoryRegions(uint64_t Size) { + if (Ctx->MemRegion) + expandMemoryRegion(Ctx->MemRegion, Size, Ctx->MemRegion->Name, + Ctx->OutSec->Name); + // Only expand the LMARegion if it is different from MemRegion. + if (Ctx->LMARegion && Ctx->MemRegion != Ctx->LMARegion) + expandMemoryRegion(Ctx->LMARegion, Size, Ctx->LMARegion->Name, + Ctx->OutSec->Name); } -void LinkerScript::expandOutputSection(uint64_t size) { - ctx->outSec->size += size; - expandMemoryRegions(size); +void LinkerScript::expandOutputSection(uint64_t Size) { + Ctx->OutSec->Size += Size; + expandMemoryRegions(Size); } -void LinkerScript::setDot(Expr e, const Twine &loc, bool inSec) { - uint64_t val = e().getValue(); - if (val < dot && inSec) - error(loc + ": unable to move location counter backward for: " + - ctx->outSec->name); +void LinkerScript::setDot(Expr E, const Twine &Loc, bool InSec) { + uint64_t Val = E().getValue(); + if (Val < Dot && InSec) + error(Loc + ": unable to move location counter backward for: " + + Ctx->OutSec->Name); // Update to location counter means update to section size. - if (inSec) - expandOutputSection(val - dot); + if (InSec) + expandOutputSection(Val - Dot); - dot = val; + Dot = Val; } // Used for handling linker symbol assignments, for both finalizing // their values and doing early declarations. Returns true if symbol // should be defined from linker script. -static bool shouldDefineSym(SymbolAssignment *cmd) { - if (cmd->name == ".") +static bool shouldDefineSym(SymbolAssignment *Cmd) { + if (Cmd->Name == ".") return false; - if (!cmd->provide) + if (!Cmd->Provide) return true; // If a symbol was in PROVIDE(), we need to define it only // when it is a referenced undefined symbol. - Symbol *b = symtab->find(cmd->name); - if (b && !b->isDefined()) + Symbol *B = Symtab->find(Cmd->Name); + if (B && !B->isDefined()) return true; return false; } -// Called by processSymbolAssignments() to assign definitions to -// linker-script-defined symbols. -void LinkerScript::addSymbol(SymbolAssignment *cmd) { - if (!shouldDefineSym(cmd)) +// This function is called from processSectionCommands, +// while we are fixing the output section layout. +void LinkerScript::addSymbol(SymbolAssignment *Cmd) { + if (!shouldDefineSym(Cmd)) return; // Define a symbol. - ExprValue value = cmd->expression(); - SectionBase *sec = value.isAbsolute() ? nullptr : value.sec; - uint8_t visibility = cmd->hidden ? STV_HIDDEN : STV_DEFAULT; + ExprValue Value = Cmd->Expression(); + SectionBase *Sec = Value.isAbsolute() ? nullptr : Value.Sec; + uint8_t Visibility = Cmd->Hidden ? STV_HIDDEN : STV_DEFAULT; // When this function is called, section addresses have not been // fixed yet. So, we may or may not know the value of the RHS @@ -177,111 +179,73 @@ void LinkerScript::addSymbol(SymbolAssignment *cmd) { // We want to set symbol values early if we can. This allows us to // use symbols as variables in linker scripts. Doing so allows us to // write expressions like this: `alignment = 16; . = ALIGN(., alignment)`. - uint64_t symValue = value.sec ? 0 : value.getValue(); + uint64_t SymValue = Value.Sec ? 0 : Value.getValue(); - Defined newSym(nullptr, cmd->name, STB_GLOBAL, visibility, STT_NOTYPE, - symValue, 0, sec); + Defined New(nullptr, Cmd->Name, STB_GLOBAL, Visibility, STT_NOTYPE, SymValue, + 0, Sec); - Symbol *sym = symtab->insert(cmd->name); - sym->mergeProperties(newSym); - sym->replace(newSym); - cmd->sym = cast(sym); + Symbol *Sym = Symtab->insert(Cmd->Name); + Sym->mergeProperties(New); + Sym->replace(New); + Cmd->Sym = cast(Sym); } // This function is called from LinkerScript::declareSymbols. // It creates a placeholder symbol if needed. -static void declareSymbol(SymbolAssignment *cmd) { - if (!shouldDefineSym(cmd)) +static void declareSymbol(SymbolAssignment *Cmd) { + if (!shouldDefineSym(Cmd)) return; - uint8_t visibility = cmd->hidden ? STV_HIDDEN : STV_DEFAULT; - Defined newSym(nullptr, cmd->name, STB_GLOBAL, visibility, STT_NOTYPE, 0, 0, - nullptr); + uint8_t Visibility = Cmd->Hidden ? STV_HIDDEN : STV_DEFAULT; + Defined New(nullptr, Cmd->Name, STB_GLOBAL, Visibility, STT_NOTYPE, 0, 0, + nullptr); // We can't calculate final value right now. - Symbol *sym = symtab->insert(cmd->name); - sym->mergeProperties(newSym); - sym->replace(newSym); - - cmd->sym = cast(sym); - cmd->provide = false; - sym->scriptDefined = true; -} - -using SymbolAssignmentMap = - DenseMap>; - -// Collect section/value pairs of linker-script-defined symbols. This is used to -// check whether symbol values converge. -static SymbolAssignmentMap -getSymbolAssignmentValues(const std::vector §ionCommands) { - SymbolAssignmentMap ret; - for (BaseCommand *base : sectionCommands) { - if (auto *cmd = dyn_cast(base)) { - if (cmd->sym) // sym is nullptr for dot. - ret.try_emplace(cmd->sym, - std::make_pair(cmd->sym->section, cmd->sym->value)); - continue; - } - for (BaseCommand *sub_base : cast(base)->sectionCommands) - if (auto *cmd = dyn_cast(sub_base)) - if (cmd->sym) - ret.try_emplace(cmd->sym, - std::make_pair(cmd->sym->section, cmd->sym->value)); - } - return ret; -} + Symbol *Sym = Symtab->insert(Cmd->Name); + Sym->mergeProperties(New); + Sym->replace(New); -// Returns the lexicographical smallest (for determinism) Defined whose -// section/value has changed. -static const Defined * -getChangedSymbolAssignment(const SymbolAssignmentMap &oldValues) { - const Defined *changed = nullptr; - for (auto &it : oldValues) { - const Defined *sym = it.first; - if (std::make_pair(sym->section, sym->value) != it.second && - (!changed || sym->getName() < changed->getName())) - changed = sym; - } - return changed; + Cmd->Sym = cast(Sym); + Cmd->Provide = false; + Sym->ScriptDefined = true; } // This method is used to handle INSERT AFTER statement. Here we rebuild // the list of script commands to mix sections inserted into. void LinkerScript::processInsertCommands() { - std::vector v; - auto insert = [&](std::vector &from) { - v.insert(v.end(), from.begin(), from.end()); - from.clear(); + std::vector V; + auto Insert = [&](std::vector &From) { + V.insert(V.end(), From.begin(), From.end()); + From.clear(); }; - for (BaseCommand *base : sectionCommands) { - if (auto *os = dyn_cast(base)) { - insert(insertBeforeCommands[os->name]); - v.push_back(base); - insert(insertAfterCommands[os->name]); + for (BaseCommand *Base : SectionCommands) { + if (auto *OS = dyn_cast(Base)) { + Insert(InsertBeforeCommands[OS->Name]); + V.push_back(Base); + Insert(InsertAfterCommands[OS->Name]); continue; } - v.push_back(base); + V.push_back(Base); } - for (auto &cmds : {insertBeforeCommands, insertAfterCommands}) - for (const std::pair> &p : cmds) - if (!p.second.empty()) - error("unable to INSERT AFTER/BEFORE " + p.first + + for (auto &Cmds : {InsertBeforeCommands, InsertAfterCommands}) + for (const std::pair> &P : Cmds) + if (!P.second.empty()) + error("unable to INSERT AFTER/BEFORE " + P.first + ": section not defined"); - sectionCommands = std::move(v); + SectionCommands = std::move(V); } // Symbols defined in script should not be inlined by LTO. At the same time // we don't know their final values until late stages of link. Here we scan // over symbol assignment commands and create placeholder symbols if needed. void LinkerScript::declareSymbols() { - assert(!ctx); - for (BaseCommand *base : sectionCommands) { - if (auto *cmd = dyn_cast(base)) { - declareSymbol(cmd); + assert(!Ctx); + for (BaseCommand *Base : SectionCommands) { + if (auto *Cmd = dyn_cast(Base)) { + declareSymbol(Cmd); continue; } @@ -289,96 +253,98 @@ void LinkerScript::declareSymbols() { // we can't say for sure if it is going to be included or not. // Skip such sections for now. Improve the checks if we ever // need symbols from that sections to be declared early. - auto *sec = cast(base); - if (sec->constraint != ConstraintKind::NoConstraint) + auto *Sec = cast(Base); + if (Sec->Constraint != ConstraintKind::NoConstraint) continue; - for (BaseCommand *base2 : sec->sectionCommands) - if (auto *cmd = dyn_cast(base2)) - declareSymbol(cmd); + for (BaseCommand *Base2 : Sec->SectionCommands) + if (auto *Cmd = dyn_cast(Base2)) + declareSymbol(Cmd); } } // This function is called from assignAddresses, while we are // fixing the output section addresses. This function is supposed // to set the final value for a given symbol assignment. -void LinkerScript::assignSymbol(SymbolAssignment *cmd, bool inSec) { - if (cmd->name == ".") { - setDot(cmd->expression, cmd->location, inSec); +void LinkerScript::assignSymbol(SymbolAssignment *Cmd, bool InSec) { + if (Cmd->Name == ".") { + setDot(Cmd->Expression, Cmd->Location, InSec); return; } - if (!cmd->sym) + if (!Cmd->Sym) return; - ExprValue v = cmd->expression(); - if (v.isAbsolute()) { - cmd->sym->section = nullptr; - cmd->sym->value = v.getValue(); + ExprValue V = Cmd->Expression(); + if (V.isAbsolute()) { + Cmd->Sym->Section = nullptr; + Cmd->Sym->Value = V.getValue(); } else { - cmd->sym->section = v.sec; - cmd->sym->value = v.getSectionOffset(); + Cmd->Sym->Section = V.Sec; + Cmd->Sym->Value = V.getSectionOffset(); } } -static std::string getFilename(InputFile *file) { - if (!file) +static std::string getFilename(InputFile *File) { + if (!File) return ""; - if (file->archiveName.empty()) - return file->getName(); - return (file->archiveName + "(" + file->getName() + ")").str(); + if (File->ArchiveName.empty()) + return File->getName(); + return (File->ArchiveName + "(" + File->getName() + ")").str(); } -bool LinkerScript::shouldKeep(InputSectionBase *s) { - if (keptSections.empty()) +bool LinkerScript::shouldKeep(InputSectionBase *S) { + if (KeptSections.empty()) return false; - std::string filename = getFilename(s->file); - for (InputSectionDescription *id : keptSections) - if (id->filePat.match(filename)) - for (SectionPattern &p : id->sectionPatterns) - if (p.sectionPat.match(s->name)) + std::string Filename = getFilename(S->File); + for (InputSectionDescription *ID : KeptSections) + if (ID->FilePat.match(Filename)) + for (SectionPattern &P : ID->SectionPatterns) + if (P.SectionPat.match(S->Name)) return true; return false; } // A helper function for the SORT() command. -static bool matchConstraints(ArrayRef sections, - ConstraintKind kind) { - if (kind == ConstraintKind::NoConstraint) +static std::function +getComparator(SortSectionPolicy K) { + switch (K) { + case SortSectionPolicy::Alignment: + return [](InputSectionBase *A, InputSectionBase *B) { + // ">" is not a mistake. Sections with larger alignments are placed + // before sections with smaller alignments in order to reduce the + // amount of padding necessary. This is compatible with GNU. + return A->Alignment > B->Alignment; + }; + case SortSectionPolicy::Name: + return [](InputSectionBase *A, InputSectionBase *B) { + return A->Name < B->Name; + }; + case SortSectionPolicy::Priority: + return [](InputSectionBase *A, InputSectionBase *B) { + return getPriority(A->Name) < getPriority(B->Name); + }; + default: + llvm_unreachable("unknown sort policy"); + } +} + +// A helper function for the SORT() command. +static bool matchConstraints(ArrayRef Sections, + ConstraintKind Kind) { + if (Kind == ConstraintKind::NoConstraint) return true; - bool isRW = llvm::any_of( - sections, [](InputSection *sec) { return sec->flags & SHF_WRITE; }); + bool IsRW = llvm::any_of( + Sections, [](InputSection *Sec) { return Sec->Flags & SHF_WRITE; }); - return (isRW && kind == ConstraintKind::ReadWrite) || - (!isRW && kind == ConstraintKind::ReadOnly); + return (IsRW && Kind == ConstraintKind::ReadWrite) || + (!IsRW && Kind == ConstraintKind::ReadOnly); } -static void sortSections(MutableArrayRef vec, - SortSectionPolicy k) { - auto alignmentComparator = [](InputSectionBase *a, InputSectionBase *b) { - // ">" is not a mistake. Sections with larger alignments are placed - // before sections with smaller alignments in order to reduce the - // amount of padding necessary. This is compatible with GNU. - return a->alignment > b->alignment; - }; - auto nameComparator = [](InputSectionBase *a, InputSectionBase *b) { - return a->name < b->name; - }; - auto priorityComparator = [](InputSectionBase *a, InputSectionBase *b) { - return getPriority(a->name) < getPriority(b->name); - }; - - switch (k) { - case SortSectionPolicy::Default: - case SortSectionPolicy::None: - return; - case SortSectionPolicy::Alignment: - return llvm::stable_sort(vec, alignmentComparator); - case SortSectionPolicy::Name: - return llvm::stable_sort(vec, nameComparator); - case SortSectionPolicy::Priority: - return llvm::stable_sort(vec, priorityComparator); - } +static void sortSections(MutableArrayRef Vec, + SortSectionPolicy K) { + if (K != SortSectionPolicy::Default && K != SortSectionPolicy::None) + llvm::stable_sort(Vec, getComparator(K)); } // Sort sections as instructed by SORT-family commands and --sort-section @@ -392,29 +358,29 @@ static void sortSections(MutableArrayRef vec, // --sort-section is handled as an inner SORT command. // 3. If one SORT command is given, and if it is SORT_NONE, don't sort. // 4. If no SORT command is given, sort according to --sort-section. -static void sortInputSections(MutableArrayRef vec, - const SectionPattern &pat) { - if (pat.sortOuter == SortSectionPolicy::None) +static void sortInputSections(MutableArrayRef Vec, + const SectionPattern &Pat) { + if (Pat.SortOuter == SortSectionPolicy::None) return; - if (pat.sortInner == SortSectionPolicy::Default) - sortSections(vec, config->sortSection); + if (Pat.SortInner == SortSectionPolicy::Default) + sortSections(Vec, Config->SortSection); else - sortSections(vec, pat.sortInner); - sortSections(vec, pat.sortOuter); + sortSections(Vec, Pat.SortInner); + sortSections(Vec, Pat.SortOuter); } // Compute and remember which sections the InputSectionDescription matches. std::vector -LinkerScript::computeInputSections(const InputSectionDescription *cmd) { - std::vector ret; +LinkerScript::computeInputSections(const InputSectionDescription *Cmd) { + std::vector Ret; // Collects all sections that satisfy constraints of Cmd. - for (const SectionPattern &pat : cmd->sectionPatterns) { - size_t sizeBefore = ret.size(); + for (const SectionPattern &Pat : Cmd->SectionPatterns) { + size_t SizeBefore = Ret.size(); - for (InputSectionBase *sec : inputSections) { - if (!sec->isLive() || sec->assigned) + for (InputSectionBase *Sec : InputSections) { + if (!Sec->isLive() || Sec->Assigned) continue; // For -emit-relocs we have to ignore entries like @@ -422,72 +388,99 @@ LinkerScript::computeInputSections(const InputSectionDescription *cmd) { // which are common because they are in the default bfd script. // We do not ignore SHT_REL[A] linker-synthesized sections here because // want to support scripts that do custom layout for them. - // - // It is safe to assume that Sec is an InputSection because mergeable or - // EH input sections have already been handled and eliminated. - if (cast(sec)->getRelocatedSection()) + if (auto *IS = dyn_cast(Sec)) + if (IS->getRelocatedSection()) + continue; + + std::string Filename = getFilename(Sec->File); + if (!Cmd->FilePat.match(Filename) || + Pat.ExcludedFilePat.match(Filename) || + !Pat.SectionPat.match(Sec->Name)) continue; - std::string filename = getFilename(sec->file); - if (!cmd->filePat.match(filename) || - pat.excludedFilePat.match(filename) || - !pat.sectionPat.match(sec->name)) - continue; - - ret.push_back(cast(sec)); - sec->assigned = true; + // It is safe to assume that Sec is an InputSection + // because mergeable or EH input sections have already been + // handled and eliminated. + Ret.push_back(cast(Sec)); + Sec->Assigned = true; } - sortInputSections(MutableArrayRef(ret).slice(sizeBefore), - pat); + sortInputSections(MutableArrayRef(Ret).slice(SizeBefore), + Pat); } - return ret; + return Ret; } -void LinkerScript::discard(ArrayRef v) { - for (InputSection *s : v) { - if (s == in.shStrTab || s == mainPart->relaDyn || s == mainPart->relrDyn) - error("discarding " + s->name + " section is not allowed"); +void LinkerScript::discard(ArrayRef V) { + for (InputSection *S : V) { + if (S == In.ShStrTab || S == Main->RelaDyn || S == Main->RelrDyn) + error("discarding " + S->Name + " section is not allowed"); // You can discard .hash and .gnu.hash sections by linker scripts. Since // they are synthesized sections, we need to handle them differently than // other regular sections. - if (s == mainPart->gnuHashTab) - mainPart->gnuHashTab = nullptr; - if (s == mainPart->hashTab) - mainPart->hashTab = nullptr; - - s->assigned = false; - s->markDead(); - discard(s->dependentSections); + if (S == Main->GnuHashTab) + Main->GnuHashTab = nullptr; + if (S == Main->HashTab) + Main->HashTab = nullptr; + + S->Assigned = false; + S->markDead(); + discard(S->DependentSections); } } std::vector -LinkerScript::createInputSectionList(OutputSection &outCmd) { - std::vector ret; +LinkerScript::createInputSectionList(OutputSection &OutCmd) { + std::vector Ret; - for (BaseCommand *base : outCmd.sectionCommands) { - if (auto *cmd = dyn_cast(base)) { - cmd->sections = computeInputSections(cmd); - ret.insert(ret.end(), cmd->sections.begin(), cmd->sections.end()); + for (BaseCommand *Base : OutCmd.SectionCommands) { + if (auto *Cmd = dyn_cast(Base)) { + Cmd->Sections = computeInputSections(Cmd); + Ret.insert(Ret.end(), Cmd->Sections.begin(), Cmd->Sections.end()); } } - return ret; + return Ret; } -// Create output sections described by SECTIONS commands. void LinkerScript::processSectionCommands() { - size_t i = 0; - for (BaseCommand *base : sectionCommands) { - if (auto *sec = dyn_cast(base)) { - std::vector v = createInputSectionList(*sec); + // A symbol can be assigned before any section is mentioned in the linker + // script. In an DSO, the symbol values are addresses, so the only important + // section values are: + // * SHN_UNDEF + // * SHN_ABS + // * Any value meaning a regular section. + // To handle that, create a dummy aether section that fills the void before + // the linker scripts switches to another section. It has an index of one + // which will map to whatever the first actual section is. + Aether = make("", 0, SHF_ALLOC); + Aether->SectionIndex = 1; + + // Ctx captures the local AddressState and makes it accessible deliberately. + // This is needed as there are some cases where we cannot just + // thread the current state through to a lambda function created by the + // script parser. + auto Deleter = make_unique(); + Ctx = Deleter.get(); + Ctx->OutSec = Aether; + + size_t I = 0; + // Add input sections to output sections. + for (BaseCommand *Base : SectionCommands) { + // Handle symbol assignments outside of any output section. + if (auto *Cmd = dyn_cast(Base)) { + addSymbol(Cmd); + continue; + } + + if (auto *Sec = dyn_cast(Base)) { + std::vector V = createInputSectionList(*Sec); // The output section name `/DISCARD/' is special. // Any input section assigned to it is discarded. - if (sec->name == "/DISCARD/") { - discard(v); - sec->sectionCommands.clear(); + if (Sec->Name == "/DISCARD/") { + discard(V); + Sec->SectionCommands.clear(); continue; } @@ -498,81 +491,61 @@ void LinkerScript::processSectionCommands() { // // Because we'll iterate over SectionCommands many more times, the easy // way to "make it as if it wasn't present" is to make it empty. - if (!matchConstraints(v, sec->constraint)) { - for (InputSectionBase *s : v) - s->assigned = false; - sec->sectionCommands.clear(); + if (!matchConstraints(V, Sec->Constraint)) { + for (InputSectionBase *S : V) + S->Assigned = false; + Sec->SectionCommands.clear(); continue; } + // A directive may contain symbol definitions like this: + // ".foo : { ...; bar = .; }". Handle them. + for (BaseCommand *Base : Sec->SectionCommands) + if (auto *OutCmd = dyn_cast(Base)) + addSymbol(OutCmd); + // Handle subalign (e.g. ".foo : SUBALIGN(32) { ... }"). If subalign // is given, input sections are aligned to that value, whether the // given value is larger or smaller than the original section alignment. - if (sec->subalignExpr) { - uint32_t subalign = sec->subalignExpr().getValue(); - for (InputSectionBase *s : v) - s->alignment = subalign; + if (Sec->SubalignExpr) { + uint32_t Subalign = Sec->SubalignExpr().getValue(); + for (InputSectionBase *S : V) + S->Alignment = Subalign; } - // Some input sections may be removed from the list after ICF. - for (InputSection *s : v) - sec->addSection(s); + // Add input sections to an output section. + for (InputSection *S : V) + Sec->addSection(S); - sec->sectionIndex = i++; - if (sec->noload) - sec->type = SHT_NOBITS; - if (sec->nonAlloc) - sec->flags &= ~(uint64_t)SHF_ALLOC; + Sec->SectionIndex = I++; + if (Sec->Noload) + Sec->Type = SHT_NOBITS; + if (Sec->NonAlloc) + Sec->Flags &= ~(uint64_t)SHF_ALLOC; } } + Ctx = nullptr; } -void LinkerScript::processSymbolAssignments() { - // Dot outside an output section still represents a relative address, whose - // sh_shndx should not be SHN_UNDEF or SHN_ABS. Create a dummy aether section - // that fills the void outside a section. It has an index of one, which is - // indistinguishable from any other regular section index. - aether = make("", 0, SHF_ALLOC); - aether->sectionIndex = 1; - - // ctx captures the local AddressState and makes it accessible deliberately. - // This is needed as there are some cases where we cannot just thread the - // current state through to a lambda function created by the script parser. - AddressState state; - ctx = &state; - ctx->outSec = aether; - - for (BaseCommand *base : sectionCommands) { - if (auto *cmd = dyn_cast(base)) - addSymbol(cmd); - else - for (BaseCommand *sub_base : cast(base)->sectionCommands) - if (auto *cmd = dyn_cast(sub_base)) - addSymbol(cmd); - } - - ctx = nullptr; -} - -static OutputSection *findByName(ArrayRef vec, - StringRef name) { - for (BaseCommand *base : vec) - if (auto *sec = dyn_cast(base)) - if (sec->name == name) - return sec; +static OutputSection *findByName(ArrayRef Vec, + StringRef Name) { + for (BaseCommand *Base : Vec) + if (auto *Sec = dyn_cast(Base)) + if (Sec->Name == Name) + return Sec; return nullptr; } -static OutputSection *createSection(InputSectionBase *isec, - StringRef outsecName) { - OutputSection *sec = script->createOutputSection(outsecName, ""); - sec->addSection(cast(isec)); - return sec; +static OutputSection *createSection(InputSectionBase *IS, + StringRef OutsecName) { + OutputSection *Sec = Script->createOutputSection(OutsecName, ""); + Sec->addSection(cast(IS)); + return Sec; } static OutputSection * -addInputSec(StringMap> &map, - InputSectionBase *isec, StringRef outsecName) { +addInputSec(StringMap> &Map, + InputSectionBase *IS, StringRef OutsecName) { // Sections with SHT_GROUP or SHF_GROUP attributes reach here only when the -r // option is given. A section with SHT_GROUP defines a "section group", and // its members have SHF_GROUP attribute. Usually these flags have already been @@ -580,8 +553,8 @@ addInputSec(StringMap> &map, // However, for the -r option, we want to pass through all section groups // as-is because adding/removing members or merging them with other groups // change their semantics. - if (isec->type == SHT_GROUP || (isec->flags & SHF_GROUP)) - return createSection(isec, outsecName); + if (IS->Type == SHT_GROUP || (IS->Flags & SHF_GROUP)) + return createSection(IS, OutsecName); // Imagine .zed : { *(.foo) *(.bar) } script. Both foo and bar may have // relocation sections .rela.foo and .rela.bar for example. Most tools do @@ -589,25 +562,25 @@ addInputSec(StringMap> &map, // should combine these relocation sections into single output. // We skip synthetic sections because it can be .rela.dyn/.rela.plt or any // other REL[A] sections created by linker itself. - if (!isa(isec) && - (isec->type == SHT_REL || isec->type == SHT_RELA)) { - auto *sec = cast(isec); - OutputSection *out = sec->getRelocatedSection()->getOutputSection(); + if (!isa(IS) && + (IS->Type == SHT_REL || IS->Type == SHT_RELA)) { + auto *Sec = cast(IS); + OutputSection *Out = Sec->getRelocatedSection()->getOutputSection(); - if (out->relocationSection) { - out->relocationSection->addSection(sec); + if (Out->RelocationSection) { + Out->RelocationSection->addSection(Sec); return nullptr; } - out->relocationSection = createSection(isec, outsecName); - return out->relocationSection; + Out->RelocationSection = createSection(IS, OutsecName); + return Out->RelocationSection; } // When control reaches here, mergeable sections have already been merged into // synthetic sections. For relocatable case we want to create one output // section per syntetic section so that they have a valid sh_entsize. - if (config->relocatable && (isec->flags & SHF_MERGE)) - return createSection(isec, outsecName); + if (Config->Relocatable && (IS->Flags & SHF_MERGE)) + return createSection(IS, OutsecName); // The ELF spec just says // ---------------------------------------------------------------- @@ -651,169 +624,161 @@ addInputSec(StringMap> &map, // // Given the above issues, we instead merge sections by name and error on // incompatible types and flags. - TinyPtrVector &v = map[outsecName]; - for (OutputSection *sec : v) { - if (sec->partition != isec->partition) + TinyPtrVector &V = Map[OutsecName]; + for (OutputSection *Sec : V) { + if (Sec->Partition != IS->Partition) continue; - sec->addSection(cast(isec)); + Sec->addSection(cast(IS)); return nullptr; } - OutputSection *sec = createSection(isec, outsecName); - v.push_back(sec); - return sec; + OutputSection *Sec = createSection(IS, OutsecName); + V.push_back(Sec); + return Sec; } // Add sections that didn't match any sections command. void LinkerScript::addOrphanSections() { - StringMap> map; - std::vector v; + StringMap> Map; + std::vector V; - auto add = [&](InputSectionBase *s) { - if (!s->isLive() || s->parent) + auto Add = [&](InputSectionBase *S) { + if (!S->isLive() || S->Parent) return; - StringRef name = getOutputSectionName(s); + StringRef Name = getOutputSectionName(S); - if (config->orphanHandling == OrphanHandlingPolicy::Error) - error(toString(s) + " is being placed in '" + name + "'"); - else if (config->orphanHandling == OrphanHandlingPolicy::Warn) - warn(toString(s) + " is being placed in '" + name + "'"); + if (Config->OrphanHandling == OrphanHandlingPolicy::Error) + error(toString(S) + " is being placed in '" + Name + "'"); + else if (Config->OrphanHandling == OrphanHandlingPolicy::Warn) + warn(toString(S) + " is being placed in '" + Name + "'"); - if (OutputSection *sec = findByName(sectionCommands, name)) { - sec->addSection(cast(s)); + if (OutputSection *Sec = findByName(SectionCommands, Name)) { + Sec->addSection(cast(S)); return; } - if (OutputSection *os = addInputSec(map, s, name)) - v.push_back(os); - assert(s->getOutputSection()->sectionIndex == UINT32_MAX); + if (OutputSection *OS = addInputSec(Map, S, Name)) + V.push_back(OS); + assert(S->getOutputSection()->SectionIndex == UINT32_MAX); }; // For futher --emit-reloc handling code we need target output section // to be created before we create relocation output section, so we want // to create target sections first. We do not want priority handling // for synthetic sections because them are special. - for (InputSectionBase *isec : inputSections) { - if (auto *sec = dyn_cast(isec)) - if (InputSectionBase *rel = sec->getRelocatedSection()) - if (auto *relIS = dyn_cast_or_null(rel->parent)) - add(relIS); - add(isec); + for (InputSectionBase *IS : InputSections) { + if (auto *Sec = dyn_cast(IS)) + if (InputSectionBase *Rel = Sec->getRelocatedSection()) + if (auto *RelIS = dyn_cast_or_null(Rel->Parent)) + Add(RelIS); + Add(IS); } // If no SECTIONS command was given, we should insert sections commands // before others, so that we can handle scripts which refers them, // for example: "foo = ABSOLUTE(ADDR(.text)));". // When SECTIONS command is present we just add all orphans to the end. - if (hasSectionsCommand) - sectionCommands.insert(sectionCommands.end(), v.begin(), v.end()); + if (HasSectionsCommand) + SectionCommands.insert(SectionCommands.end(), V.begin(), V.end()); else - sectionCommands.insert(sectionCommands.begin(), v.begin(), v.end()); + SectionCommands.insert(SectionCommands.begin(), V.begin(), V.end()); } -uint64_t LinkerScript::advance(uint64_t size, unsigned alignment) { - bool isTbss = - (ctx->outSec->flags & SHF_TLS) && ctx->outSec->type == SHT_NOBITS; - uint64_t start = isTbss ? dot + ctx->threadBssOffset : dot; - start = alignTo(start, alignment); - uint64_t end = start + size; +uint64_t LinkerScript::advance(uint64_t Size, unsigned Alignment) { + bool IsTbss = + (Ctx->OutSec->Flags & SHF_TLS) && Ctx->OutSec->Type == SHT_NOBITS; + uint64_t Start = IsTbss ? Dot + Ctx->ThreadBssOffset : Dot; + Start = alignTo(Start, Alignment); + uint64_t End = Start + Size; - if (isTbss) - ctx->threadBssOffset = end - dot; + if (IsTbss) + Ctx->ThreadBssOffset = End - Dot; else - dot = end; - return end; + Dot = End; + return End; } -void LinkerScript::output(InputSection *s) { - assert(ctx->outSec == s->getParent()); - uint64_t before = advance(0, 1); - uint64_t pos = advance(s->getSize(), s->alignment); - s->outSecOff = pos - s->getSize() - ctx->outSec->addr; +void LinkerScript::output(InputSection *S) { + assert(Ctx->OutSec == S->getParent()); + uint64_t Before = advance(0, 1); + uint64_t Pos = advance(S->getSize(), S->Alignment); + S->OutSecOff = Pos - S->getSize() - Ctx->OutSec->Addr; // Update output section size after adding each section. This is so that // SIZEOF works correctly in the case below: // .foo { *(.aaa) a = SIZEOF(.foo); *(.bbb) } - expandOutputSection(pos - before); + expandOutputSection(Pos - Before); } -void LinkerScript::switchTo(OutputSection *sec) { - ctx->outSec = sec; +void LinkerScript::switchTo(OutputSection *Sec) { + Ctx->OutSec = Sec; - uint64_t before = advance(0, 1); - ctx->outSec->addr = advance(0, ctx->outSec->alignment); - expandMemoryRegions(ctx->outSec->addr - before); + uint64_t Before = advance(0, 1); + Ctx->OutSec->Addr = advance(0, Ctx->OutSec->Alignment); + expandMemoryRegions(Ctx->OutSec->Addr - Before); } // This function searches for a memory region to place the given output // section in. If found, a pointer to the appropriate memory region is // returned. Otherwise, a nullptr is returned. -MemoryRegion *LinkerScript::findMemoryRegion(OutputSection *sec) { +MemoryRegion *LinkerScript::findMemoryRegion(OutputSection *Sec) { // If a memory region name was specified in the output section command, // then try to find that region first. - if (!sec->memoryRegionName.empty()) { - if (MemoryRegion *m = memoryRegions.lookup(sec->memoryRegionName)) - return m; - error("memory region '" + sec->memoryRegionName + "' not declared"); + if (!Sec->MemoryRegionName.empty()) { + if (MemoryRegion *M = MemoryRegions.lookup(Sec->MemoryRegionName)) + return M; + error("memory region '" + Sec->MemoryRegionName + "' not declared"); return nullptr; } // If at least one memory region is defined, all sections must // belong to some memory region. Otherwise, we don't need to do // anything for memory regions. - if (memoryRegions.empty()) + if (MemoryRegions.empty()) return nullptr; // See if a region can be found by matching section flags. - for (auto &pair : memoryRegions) { - MemoryRegion *m = pair.second; - if ((m->flags & sec->flags) && (m->negFlags & sec->flags) == 0) - return m; + for (auto &Pair : MemoryRegions) { + MemoryRegion *M = Pair.second; + if ((M->Flags & Sec->Flags) && (M->NegFlags & Sec->Flags) == 0) + return M; } // Otherwise, no suitable region was found. - if (sec->flags & SHF_ALLOC) - error("no memory region specified for section '" + sec->name + "'"); + if (Sec->Flags & SHF_ALLOC) + error("no memory region specified for section '" + Sec->Name + "'"); return nullptr; } -static OutputSection *findFirstSection(PhdrEntry *load) { - for (OutputSection *sec : outputSections) - if (sec->ptLoad == load) - return sec; +static OutputSection *findFirstSection(PhdrEntry *Load) { + for (OutputSection *Sec : OutputSections) + if (Sec->PtLoad == Load) + return Sec; return nullptr; } // This function assigns offsets to input sections and an output section // for a single sections command (e.g. ".text { *(.text); }"). -void LinkerScript::assignOffsets(OutputSection *sec) { - if (!(sec->flags & SHF_ALLOC)) - dot = 0; +void LinkerScript::assignOffsets(OutputSection *Sec) { + if (!(Sec->Flags & SHF_ALLOC)) + Dot = 0; - ctx->memRegion = sec->memRegion; - ctx->lmaRegion = sec->lmaRegion; - if (ctx->memRegion) - dot = ctx->memRegion->curPos; + Ctx->MemRegion = Sec->MemRegion; + Ctx->LMARegion = Sec->LMARegion; + if (Ctx->MemRegion) + Dot = Ctx->MemRegion->CurPos; - if ((sec->flags & SHF_ALLOC) && sec->addrExpr) - setDot(sec->addrExpr, sec->location, false); + if ((Sec->Flags & SHF_ALLOC) && Sec->AddrExpr) + setDot(Sec->AddrExpr, Sec->Location, false); - // If the address of the section has been moved forward by an explicit - // expression so that it now starts past the current curPos of the enclosing - // region, we need to expand the current region to account for the space - // between the previous section, if any, and the start of this section. - if (ctx->memRegion && ctx->memRegion->curPos < dot) - expandMemoryRegion(ctx->memRegion, dot - ctx->memRegion->curPos, - ctx->memRegion->name, sec->name); + switchTo(Sec); - switchTo(sec); + if (Sec->LMAExpr) + Ctx->LMAOffset = Sec->LMAExpr().getValue() - Dot; - if (sec->lmaExpr) - ctx->lmaOffset = sec->lmaExpr().getValue() - dot; - - if (MemoryRegion *mr = sec->lmaRegion) - ctx->lmaOffset = mr->curPos - dot; + if (MemoryRegion *MR = Sec->LMARegion) + Ctx->LMAOffset = MR->CurPos - Dot; // If neither AT nor AT> is specified for an allocatable section, the linker // will set the LMA such that the difference between VMA and LMA for the @@ -821,71 +786,71 @@ void LinkerScript::assignOffsets(OutputSection *sec) { // https://sourceware.org/binutils/docs-2.20/ld/Output-Section-LMA.html // This, however, should only be done by the first "non-header" section // in the segment. - if (PhdrEntry *l = ctx->outSec->ptLoad) - if (sec == findFirstSection(l)) - l->lmaOffset = ctx->lmaOffset; + if (PhdrEntry *L = Ctx->OutSec->PtLoad) + if (Sec == findFirstSection(L)) + L->LMAOffset = Ctx->LMAOffset; // We can call this method multiple times during the creation of // thunks and want to start over calculation each time. - sec->size = 0; + Sec->Size = 0; // We visited SectionsCommands from processSectionCommands to // layout sections. Now, we visit SectionsCommands again to fix // section offsets. - for (BaseCommand *base : sec->sectionCommands) { + for (BaseCommand *Base : Sec->SectionCommands) { // This handles the assignments to symbol or to the dot. - if (auto *cmd = dyn_cast(base)) { - cmd->addr = dot; - assignSymbol(cmd, true); - cmd->size = dot - cmd->addr; + if (auto *Cmd = dyn_cast(Base)) { + Cmd->Addr = Dot; + assignSymbol(Cmd, true); + Cmd->Size = Dot - Cmd->Addr; continue; } // Handle BYTE(), SHORT(), LONG(), or QUAD(). - if (auto *cmd = dyn_cast(base)) { - cmd->offset = dot - ctx->outSec->addr; - dot += cmd->size; - expandOutputSection(cmd->size); + if (auto *Cmd = dyn_cast(Base)) { + Cmd->Offset = Dot - Ctx->OutSec->Addr; + Dot += Cmd->Size; + expandOutputSection(Cmd->Size); continue; } // Handle a single input section description command. // It calculates and assigns the offsets for each section and also // updates the output section size. - for (InputSection *sec : cast(base)->sections) - output(sec); + for (InputSection *Sec : cast(Base)->Sections) + output(Sec); } } -static bool isDiscardable(OutputSection &sec) { - if (sec.name == "/DISCARD/") +static bool isDiscardable(OutputSection &Sec) { + if (Sec.Name == "/DISCARD/") return true; // We do not remove empty sections that are explicitly // assigned to any segment. - if (!sec.phdrs.empty()) + if (!Sec.Phdrs.empty()) return false; // We do not want to remove OutputSections with expressions that reference // symbols even if the OutputSection is empty. We want to ensure that the // expressions can be evaluated and report an error if they cannot. - if (sec.expressionsUseSymbols) + if (Sec.ExpressionsUseSymbols) return false; // OutputSections may be referenced by name in ADDR and LOADADDR expressions, // as an empty Section can has a valid VMA and LMA we keep the OutputSection // to maintain the integrity of the other Expression. - if (sec.usedInExpression) + if (Sec.UsedInExpression) return false; - for (BaseCommand *base : sec.sectionCommands) { - if (auto cmd = dyn_cast(base)) + for (BaseCommand *Base : Sec.SectionCommands) { + if (auto Cmd = dyn_cast(Base)) // Don't create empty output sections just for unreferenced PROVIDE // symbols. - if (cmd->name != "." && !cmd->sym) + if (Cmd->Name != "." && !Cmd->Sym) continue; - if (!isa(*base)) + if (!isa(*Base)) return false; } return true; @@ -912,35 +877,35 @@ void LinkerScript::adjustSectionsBeforeSorting() { // The other option is to pick flags that minimize the impact the section // will have on the rest of the linker. That is why we copy the flags from // the previous sections. Only a few flags are needed to keep the impact low. - uint64_t flags = SHF_ALLOC; + uint64_t Flags = SHF_ALLOC; - for (BaseCommand *&cmd : sectionCommands) { - auto *sec = dyn_cast(cmd); - if (!sec) + for (BaseCommand *&Cmd : SectionCommands) { + auto *Sec = dyn_cast(Cmd); + if (!Sec) continue; // Handle align (e.g. ".foo : ALIGN(16) { ... }"). - if (sec->alignExpr) - sec->alignment = - std::max(sec->alignment, sec->alignExpr().getValue()); + if (Sec->AlignExpr) + Sec->Alignment = + std::max(Sec->Alignment, Sec->AlignExpr().getValue()); // The input section might have been removed (if it was an empty synthetic // section), but we at least know the flags. - if (sec->hasInputSections) - flags = sec->flags; + if (Sec->HasInputSections) + Flags = Sec->Flags; // We do not want to keep any special flags for output section // in case it is empty. - bool isEmpty = getInputSections(sec).empty(); - if (isEmpty) - sec->flags = flags & ((sec->nonAlloc ? 0 : (uint64_t)SHF_ALLOC) | + bool IsEmpty = getInputSections(Sec).empty(); + if (IsEmpty) + Sec->Flags = Flags & ((Sec->NonAlloc ? 0 : (uint64_t)SHF_ALLOC) | SHF_WRITE | SHF_EXECINSTR); - if (isEmpty && isDiscardable(*sec)) { - sec->markDead(); - cmd = nullptr; - } else if (!sec->isLive()) { - sec->markLive(); + if (IsEmpty && isDiscardable(*Sec)) { + Sec->markDead(); + Cmd = nullptr; + } else if (!Sec->isLive()) { + Sec->markLive(); } } @@ -950,20 +915,20 @@ void LinkerScript::adjustSectionsBeforeSorting() { // clutter the output. // We instead remove trivially empty sections. The bfd linker seems even // more aggressive at removing them. - llvm::erase_if(sectionCommands, [&](BaseCommand *base) { return !base; }); + llvm::erase_if(SectionCommands, [&](BaseCommand *Base) { return !Base; }); } void LinkerScript::adjustSectionsAfterSorting() { // Try and find an appropriate memory region to assign offsets in. - for (BaseCommand *base : sectionCommands) { - if (auto *sec = dyn_cast(base)) { - if (!sec->lmaRegionName.empty()) { - if (MemoryRegion *m = memoryRegions.lookup(sec->lmaRegionName)) - sec->lmaRegion = m; + for (BaseCommand *Base : SectionCommands) { + if (auto *Sec = dyn_cast(Base)) { + if (!Sec->LMARegionName.empty()) { + if (MemoryRegion *M = MemoryRegions.lookup(Sec->LMARegionName)) + Sec->LMARegion = M; else - error("memory region '" + sec->lmaRegionName + "' not declared"); + error("memory region '" + Sec->LMARegionName + "' not declared"); } - sec->memRegion = findMemoryRegion(sec); + Sec->MemRegion = findMemoryRegion(Sec); } } @@ -973,38 +938,38 @@ void LinkerScript::adjustSectionsAfterSorting() { // Below is an example of such linker script: // PHDRS { seg PT_LOAD; } // SECTIONS { .aaa : { *(.aaa) } } - std::vector defPhdrs; - auto firstPtLoad = llvm::find_if(phdrsCommands, [](const PhdrsCommand &cmd) { - return cmd.type == PT_LOAD; + std::vector DefPhdrs; + auto FirstPtLoad = llvm::find_if(PhdrsCommands, [](const PhdrsCommand &Cmd) { + return Cmd.Type == PT_LOAD; }); - if (firstPtLoad != phdrsCommands.end()) - defPhdrs.push_back(firstPtLoad->name); + if (FirstPtLoad != PhdrsCommands.end()) + DefPhdrs.push_back(FirstPtLoad->Name); // Walk the commands and propagate the program headers to commands that don't // explicitly specify them. - for (BaseCommand *base : sectionCommands) { - auto *sec = dyn_cast(base); - if (!sec) + for (BaseCommand *Base : SectionCommands) { + auto *Sec = dyn_cast(Base); + if (!Sec) continue; - if (sec->phdrs.empty()) { + if (Sec->Phdrs.empty()) { // To match the bfd linker script behaviour, only propagate program // headers to sections that are allocated. - if (sec->flags & SHF_ALLOC) - sec->phdrs = defPhdrs; + if (Sec->Flags & SHF_ALLOC) + Sec->Phdrs = DefPhdrs; } else { - defPhdrs = sec->phdrs; + DefPhdrs = Sec->Phdrs; } } } -static uint64_t computeBase(uint64_t min, bool allocateHeaders) { +static uint64_t computeBase(uint64_t Min, bool AllocateHeaders) { // If there is no SECTIONS or if the linkerscript is explicit about program // headers, do our best to allocate them. - if (!script->hasSectionsCommand || allocateHeaders) + if (!Script->HasSectionsCommand || AllocateHeaders) return 0; // Otherwise only allocate program headers if that would not add a page. - return alignDown(min, config->maxPageSize); + return alignDown(Min, Config->MaxPageSize); } // Try to find an address for the file and program headers output sections, @@ -1018,125 +983,120 @@ static uint64_t computeBase(uint64_t min, bool allocateHeaders) { // // If there isn't enough space for these sections, we'll remove them from the // PT_LOAD segment, and we'll also remove the PT_PHDR segment. -void LinkerScript::allocateHeaders(std::vector &phdrs) { - uint64_t min = std::numeric_limits::max(); - for (OutputSection *sec : outputSections) - if (sec->flags & SHF_ALLOC) - min = std::min(min, sec->addr); - - auto it = llvm::find_if( - phdrs, [](const PhdrEntry *e) { return e->p_type == PT_LOAD; }); - if (it == phdrs.end()) +void LinkerScript::allocateHeaders(std::vector &Phdrs) { + uint64_t Min = std::numeric_limits::max(); + for (OutputSection *Sec : OutputSections) + if (Sec->Flags & SHF_ALLOC) + Min = std::min(Min, Sec->Addr); + + auto It = llvm::find_if( + Phdrs, [](const PhdrEntry *E) { return E->p_type == PT_LOAD; }); + if (It == Phdrs.end()) return; - PhdrEntry *firstPTLoad = *it; + PhdrEntry *FirstPTLoad = *It; - bool hasExplicitHeaders = - llvm::any_of(phdrsCommands, [](const PhdrsCommand &cmd) { - return cmd.hasPhdrs || cmd.hasFilehdr; + bool HasExplicitHeaders = + llvm::any_of(PhdrsCommands, [](const PhdrsCommand &Cmd) { + return Cmd.HasPhdrs || Cmd.HasFilehdr; }); - bool paged = !config->omagic && !config->nmagic; - uint64_t headerSize = getHeaderSize(); - if ((paged || hasExplicitHeaders) && - headerSize <= min - computeBase(min, hasExplicitHeaders)) { - min = alignDown(min - headerSize, config->maxPageSize); - Out::elfHeader->addr = min; - Out::programHeaders->addr = min + Out::elfHeader->size; + bool Paged = !Config->Omagic && !Config->Nmagic; + uint64_t HeaderSize = getHeaderSize(); + if ((Paged || HasExplicitHeaders) && + HeaderSize <= Min - computeBase(Min, HasExplicitHeaders)) { + Min = alignDown(Min - HeaderSize, Config->MaxPageSize); + Out::ElfHeader->Addr = Min; + Out::ProgramHeaders->Addr = Min + Out::ElfHeader->Size; return; } // Error if we were explicitly asked to allocate headers. - if (hasExplicitHeaders) + if (HasExplicitHeaders) error("could not allocate headers"); - Out::elfHeader->ptLoad = nullptr; - Out::programHeaders->ptLoad = nullptr; - firstPTLoad->firstSec = findFirstSection(firstPTLoad); + Out::ElfHeader->PtLoad = nullptr; + Out::ProgramHeaders->PtLoad = nullptr; + FirstPTLoad->FirstSec = findFirstSection(FirstPTLoad); - llvm::erase_if(phdrs, - [](const PhdrEntry *e) { return e->p_type == PT_PHDR; }); + llvm::erase_if(Phdrs, + [](const PhdrEntry *E) { return E->p_type == PT_PHDR; }); } LinkerScript::AddressState::AddressState() { - for (auto &mri : script->memoryRegions) { - MemoryRegion *mr = mri.second; - mr->curPos = mr->origin; + for (auto &MRI : Script->MemoryRegions) { + MemoryRegion *MR = MRI.second; + MR->CurPos = MR->Origin; } } static uint64_t getInitialDot() { // By default linker scripts use an initial value of 0 for '.', // but prefer -image-base if set. - if (script->hasSectionsCommand) - return config->imageBase ? *config->imageBase : 0; + if (Script->HasSectionsCommand) + return Config->ImageBase ? *Config->ImageBase : 0; - uint64_t startAddr = UINT64_MAX; - // The sections with -T
have been sorted in order of ascending - // address. We must lower startAddr if the lowest -T
as + uint64_t StartAddr = UINT64_MAX; + // The Sections with -T
have been sorted in order of ascending + // address. We must lower StartAddr if the lowest -T
as // calls to setDot() must be monotonically increasing. - for (auto &kv : config->sectionStartMap) - startAddr = std::min(startAddr, kv.second); - return std::min(startAddr, target->getImageBase() + elf::getHeaderSize()); + for (auto &KV : Config->SectionStartMap) + StartAddr = std::min(StartAddr, KV.second); + return std::min(StartAddr, Target->getImageBase() + elf::getHeaderSize()); } // Here we assign addresses as instructed by linker script SECTIONS // sub-commands. Doing that allows us to use final VA values, so here // we also handle rest commands like symbol assignments and ASSERTs. -// Returns a symbol that has changed its section or value, or nullptr if no -// symbol has changed. -const Defined *LinkerScript::assignAddresses() { - dot = getInitialDot(); - - auto deleter = std::make_unique(); - ctx = deleter.get(); - errorOnMissingSection = true; - switchTo(aether); - - SymbolAssignmentMap oldValues = getSymbolAssignmentValues(sectionCommands); - for (BaseCommand *base : sectionCommands) { - if (auto *cmd = dyn_cast(base)) { - cmd->addr = dot; - assignSymbol(cmd, false); - cmd->size = dot - cmd->addr; +void LinkerScript::assignAddresses() { + Dot = getInitialDot(); + + auto Deleter = make_unique(); + Ctx = Deleter.get(); + ErrorOnMissingSection = true; + switchTo(Aether); + + for (BaseCommand *Base : SectionCommands) { + if (auto *Cmd = dyn_cast(Base)) { + Cmd->Addr = Dot; + assignSymbol(Cmd, false); + Cmd->Size = Dot - Cmd->Addr; continue; } - assignOffsets(cast(base)); + assignOffsets(cast(Base)); } - - ctx = nullptr; - return getChangedSymbolAssignment(oldValues); + Ctx = nullptr; } // Creates program headers as instructed by PHDRS linker script command. std::vector LinkerScript::createPhdrs() { - std::vector ret; + std::vector Ret; // Process PHDRS and FILEHDR keywords because they are not // real output sections and cannot be added in the following loop. - for (const PhdrsCommand &cmd : phdrsCommands) { - PhdrEntry *phdr = make(cmd.type, cmd.flags ? *cmd.flags : PF_R); + for (const PhdrsCommand &Cmd : PhdrsCommands) { + PhdrEntry *Phdr = make(Cmd.Type, Cmd.Flags ? *Cmd.Flags : PF_R); - if (cmd.hasFilehdr) - phdr->add(Out::elfHeader); - if (cmd.hasPhdrs) - phdr->add(Out::programHeaders); + if (Cmd.HasFilehdr) + Phdr->add(Out::ElfHeader); + if (Cmd.HasPhdrs) + Phdr->add(Out::ProgramHeaders); - if (cmd.lmaExpr) { - phdr->p_paddr = cmd.lmaExpr().getValue(); - phdr->hasLMA = true; + if (Cmd.LMAExpr) { + Phdr->p_paddr = Cmd.LMAExpr().getValue(); + Phdr->HasLMA = true; } - ret.push_back(phdr); + Ret.push_back(Phdr); } // Add output sections to program headers. - for (OutputSection *sec : outputSections) { + for (OutputSection *Sec : OutputSections) { // Assign headers specified by linker script - for (size_t id : getPhdrIndices(sec)) { - ret[id]->add(sec); - if (!phdrsCommands[id].flags.hasValue()) - ret[id]->p_flags |= sec->getPhdrFlags(); + for (size_t Id : getPhdrIndices(Sec)) { + Ret[Id]->add(Sec); + if (!PhdrsCommands[Id].Flags.hasValue()) + Ret[Id]->p_flags |= Sec->getPhdrFlags(); } } - return ret; + return Ret; } // Returns true if we should emit an .interp section. @@ -1145,54 +1105,54 @@ std::vector LinkerScript::createPhdrs() { // no PT_INTERP is there, there's no place to emit an // .interp, so we don't do that in that case. bool LinkerScript::needsInterpSection() { - if (phdrsCommands.empty()) + if (PhdrsCommands.empty()) return true; - for (PhdrsCommand &cmd : phdrsCommands) - if (cmd.type == PT_INTERP) + for (PhdrsCommand &Cmd : PhdrsCommands) + if (Cmd.Type == PT_INTERP) return true; return false; } -ExprValue LinkerScript::getSymbolValue(StringRef name, const Twine &loc) { - if (name == ".") { - if (ctx) - return {ctx->outSec, false, dot - ctx->outSec->addr, loc}; - error(loc + ": unable to get location counter value"); +ExprValue LinkerScript::getSymbolValue(StringRef Name, const Twine &Loc) { + if (Name == ".") { + if (Ctx) + return {Ctx->OutSec, false, Dot - Ctx->OutSec->Addr, Loc}; + error(Loc + ": unable to get location counter value"); return 0; } - if (Symbol *sym = symtab->find(name)) { - if (auto *ds = dyn_cast(sym)) - return {ds->section, false, ds->value, loc}; - if (isa(sym)) - if (!errorOnMissingSection) - return {nullptr, false, 0, loc}; + if (Symbol *Sym = Symtab->find(Name)) { + if (auto *DS = dyn_cast(Sym)) + return {DS->Section, false, DS->Value, Loc}; + if (isa(Sym)) + if (!ErrorOnMissingSection) + return {nullptr, false, 0, Loc}; } - error(loc + ": symbol not found: " + name); + error(Loc + ": symbol not found: " + Name); return 0; } // Returns the index of the segment named Name. -static Optional getPhdrIndex(ArrayRef vec, - StringRef name) { - for (size_t i = 0; i < vec.size(); ++i) - if (vec[i].name == name) - return i; +static Optional getPhdrIndex(ArrayRef Vec, + StringRef Name) { + for (size_t I = 0; I < Vec.size(); ++I) + if (Vec[I].Name == Name) + return I; return None; } // Returns indices of ELF headers containing specific section. Each index is a // zero based number of ELF header listed within PHDRS {} script block. -std::vector LinkerScript::getPhdrIndices(OutputSection *cmd) { - std::vector ret; - - for (StringRef s : cmd->phdrs) { - if (Optional idx = getPhdrIndex(phdrsCommands, s)) - ret.push_back(*idx); - else if (s != "NONE") - error(cmd->location + ": section header '" + s + +std::vector LinkerScript::getPhdrIndices(OutputSection *Cmd) { + std::vector Ret; + + for (StringRef S : Cmd->Phdrs) { + if (Optional Idx = getPhdrIndex(PhdrsCommands, S)) + Ret.push_back(*Idx); + else if (S != "NONE") + error(Cmd->Location + ": section header '" + S + "' is not listed in PHDRS"); } - return ret; + return Ret; } diff --git a/lld/ELF/LinkerScript.h b/lld/ELF/LinkerScript.h index 4ac9e2a390930d..fe092b27d6f038 100644 --- a/lld/ELF/LinkerScript.h +++ b/lld/ELF/LinkerScript.h @@ -38,29 +38,29 @@ class ThunkSection; // This represents an r-value in the linker script. struct ExprValue { - ExprValue(SectionBase *sec, bool forceAbsolute, uint64_t val, - const Twine &loc) - : sec(sec), forceAbsolute(forceAbsolute), val(val), loc(loc.str()) {} + ExprValue(SectionBase *Sec, bool ForceAbsolute, uint64_t Val, + const Twine &Loc) + : Sec(Sec), ForceAbsolute(ForceAbsolute), Val(Val), Loc(Loc.str()) {} - ExprValue(uint64_t val) : ExprValue(nullptr, false, val, "") {} + ExprValue(uint64_t Val) : ExprValue(nullptr, false, Val, "") {} - bool isAbsolute() const { return forceAbsolute || sec == nullptr; } + bool isAbsolute() const { return ForceAbsolute || Sec == nullptr; } uint64_t getValue() const; uint64_t getSecAddr() const; uint64_t getSectionOffset() const; // If a value is relative to a section, it has a non-null Sec. - SectionBase *sec; + SectionBase *Sec; // True if this expression is enclosed in ABSOLUTE(). // This flag affects the return value of getValue(). - bool forceAbsolute; + bool ForceAbsolute; - uint64_t val; - uint64_t alignment = 1; + uint64_t Val; + uint64_t Alignment = 1; // Original source location. Used for error messages. - std::string loc; + std::string Loc; }; // This represents an expression in the linker script. @@ -78,42 +78,42 @@ enum SectionsCommandKind { }; struct BaseCommand { - BaseCommand(int k) : kind(k) {} - int kind; + BaseCommand(int K) : Kind(K) {} + int Kind; }; // This represents ". = " or " = ". struct SymbolAssignment : BaseCommand { - SymbolAssignment(StringRef name, Expr e, std::string loc) - : BaseCommand(AssignmentKind), name(name), expression(e), location(loc) {} + SymbolAssignment(StringRef Name, Expr E, std::string Loc) + : BaseCommand(AssignmentKind), Name(Name), Expression(E), Location(Loc) {} - static bool classof(const BaseCommand *c) { - return c->kind == AssignmentKind; + static bool classof(const BaseCommand *C) { + return C->Kind == AssignmentKind; } // The LHS of an expression. Name is either a symbol name or ".". - StringRef name; - Defined *sym = nullptr; + StringRef Name; + Defined *Sym = nullptr; // The RHS of an expression. - Expr expression; + Expr Expression; // Command attributes for PROVIDE, HIDDEN and PROVIDE_HIDDEN. - bool provide = false; - bool hidden = false; + bool Provide = false; + bool Hidden = false; // Holds file name and line number for error reporting. - std::string location; + std::string Location; // A string representation of this command. We use this for -Map. - std::string commandString; + std::string CommandString; // Address of this assignment command. - unsigned addr; + unsigned Addr; // Size of this assignment command. This is usually 0, but if // you move '.' this may be greater than 0. - unsigned size; + unsigned Size; }; // Linker scripts allow additional constraints to be put on ouput sections. @@ -126,83 +126,83 @@ enum class ConstraintKind { NoConstraint, ReadOnly, ReadWrite }; // target memory. Instances of the struct are created by parsing the // MEMORY command. struct MemoryRegion { - MemoryRegion(StringRef name, uint64_t origin, uint64_t length, uint32_t flags, - uint32_t negFlags) - : name(name), origin(origin), length(length), flags(flags), - negFlags(negFlags) {} - - std::string name; - uint64_t origin; - uint64_t length; - uint32_t flags; - uint32_t negFlags; - uint64_t curPos = 0; + MemoryRegion(StringRef Name, uint64_t Origin, uint64_t Length, uint32_t Flags, + uint32_t NegFlags) + : Name(Name), Origin(Origin), Length(Length), Flags(Flags), + NegFlags(NegFlags) {} + + std::string Name; + uint64_t Origin; + uint64_t Length; + uint32_t Flags; + uint32_t NegFlags; + uint64_t CurPos = 0; }; // This struct represents one section match pattern in SECTIONS() command. // It can optionally have negative match pattern for EXCLUDED_FILE command. // Also it may be surrounded with SORT() command, so contains sorting rules. struct SectionPattern { - SectionPattern(StringMatcher &&pat1, StringMatcher &&pat2) - : excludedFilePat(pat1), sectionPat(pat2), - sortOuter(SortSectionPolicy::Default), - sortInner(SortSectionPolicy::Default) {} - - StringMatcher excludedFilePat; - StringMatcher sectionPat; - SortSectionPolicy sortOuter; - SortSectionPolicy sortInner; + SectionPattern(StringMatcher &&Pat1, StringMatcher &&Pat2) + : ExcludedFilePat(Pat1), SectionPat(Pat2), + SortOuter(SortSectionPolicy::Default), + SortInner(SortSectionPolicy::Default) {} + + StringMatcher ExcludedFilePat; + StringMatcher SectionPat; + SortSectionPolicy SortOuter; + SortSectionPolicy SortInner; }; struct InputSectionDescription : BaseCommand { - InputSectionDescription(StringRef filePattern) - : BaseCommand(InputSectionKind), filePat(filePattern) {} + InputSectionDescription(StringRef FilePattern) + : BaseCommand(InputSectionKind), FilePat(FilePattern) {} - static bool classof(const BaseCommand *c) { - return c->kind == InputSectionKind; + static bool classof(const BaseCommand *C) { + return C->Kind == InputSectionKind; } - StringMatcher filePat; + StringMatcher FilePat; // Input sections that matches at least one of SectionPatterns // will be associated with this InputSectionDescription. - std::vector sectionPatterns; + std::vector SectionPatterns; - std::vector sections; + std::vector Sections; // Temporary record of synthetic ThunkSection instances and the pass that // they were created in. This is used to insert newly created ThunkSections // into Sections at the end of a createThunks() pass. - std::vector> thunkSections; + std::vector> ThunkSections; }; // Represents BYTE(), SHORT(), LONG(), or QUAD(). struct ByteCommand : BaseCommand { - ByteCommand(Expr e, unsigned size, std::string commandString) - : BaseCommand(ByteKind), commandString(commandString), expression(e), - size(size) {} + ByteCommand(Expr E, unsigned Size, std::string CommandString) + : BaseCommand(ByteKind), CommandString(CommandString), Expression(E), + Size(Size) {} - static bool classof(const BaseCommand *c) { return c->kind == ByteKind; } + static bool classof(const BaseCommand *C) { return C->Kind == ByteKind; } // Keeps string representing the command. Used for -Map" is perhaps better. - std::string commandString; + std::string CommandString; - Expr expression; + Expr Expression; // This is just an offset of this assignment command in the output section. - unsigned offset; + unsigned Offset; // Size of this data command. - unsigned size; + unsigned Size; }; struct PhdrsCommand { - StringRef name; - unsigned type = llvm::ELF::PT_NULL; - bool hasFilehdr = false; - bool hasPhdrs = false; - llvm::Optional flags; - Expr lmaExpr = nullptr; + StringRef Name; + unsigned Type = llvm::ELF::PT_NULL; + bool HasFilehdr = false; + bool HasPhdrs = false; + llvm::Optional Flags; + Expr LMAExpr = nullptr; }; class LinkerScript final { @@ -211,35 +211,35 @@ class LinkerScript final { // not be used outside of the scope of a call to the above functions. struct AddressState { AddressState(); - uint64_t threadBssOffset = 0; - OutputSection *outSec = nullptr; - MemoryRegion *memRegion = nullptr; - MemoryRegion *lmaRegion = nullptr; - uint64_t lmaOffset = 0; + uint64_t ThreadBssOffset = 0; + OutputSection *OutSec = nullptr; + MemoryRegion *MemRegion = nullptr; + MemoryRegion *LMARegion = nullptr; + uint64_t LMAOffset = 0; }; - llvm::DenseMap nameToOutputSection; + llvm::DenseMap NameToOutputSection; - void addSymbol(SymbolAssignment *cmd); - void assignSymbol(SymbolAssignment *cmd, bool inSec); - void setDot(Expr e, const Twine &loc, bool inSec); - void expandOutputSection(uint64_t size); - void expandMemoryRegions(uint64_t size); + void addSymbol(SymbolAssignment *Cmd); + void assignSymbol(SymbolAssignment *Cmd, bool InSec); + void setDot(Expr E, const Twine &Loc, bool InSec); + void expandOutputSection(uint64_t Size); + void expandMemoryRegions(uint64_t Size); std::vector computeInputSections(const InputSectionDescription *); - std::vector createInputSectionList(OutputSection &cmd); + std::vector createInputSectionList(OutputSection &Cmd); - std::vector getPhdrIndices(OutputSection *sec); + std::vector getPhdrIndices(OutputSection *Sec); - MemoryRegion *findMemoryRegion(OutputSection *sec); + MemoryRegion *findMemoryRegion(OutputSection *Sec); - void switchTo(OutputSection *sec); - uint64_t advance(uint64_t size, unsigned align); - void output(InputSection *sec); + void switchTo(OutputSection *Sec); + uint64_t advance(uint64_t Size, unsigned Align); + void output(InputSection *Sec); - void assignOffsets(OutputSection *sec); + void assignOffsets(OutputSection *Sec); // Ctx captures the local AddressState and makes it accessible // deliberately. This is needed as there are some cases where we cannot just @@ -247,21 +247,21 @@ class LinkerScript final { // script parser. // This should remain a plain pointer as its lifetime is smaller than // LinkerScript. - AddressState *ctx = nullptr; + AddressState *Ctx = nullptr; - OutputSection *aether; + OutputSection *Aether; - uint64_t dot; + uint64_t Dot; public: - OutputSection *createOutputSection(StringRef name, StringRef location); - OutputSection *getOrCreateOutputSection(StringRef name); + OutputSection *createOutputSection(StringRef Name, StringRef Location); + OutputSection *getOrCreateOutputSection(StringRef Name); - bool hasPhdrsCommands() { return !phdrsCommands.empty(); } - uint64_t getDot() { return dot; } - void discard(ArrayRef v); + bool hasPhdrsCommands() { return !PhdrsCommands.empty(); } + uint64_t getDot() { return Dot; } + void discard(ArrayRef V); - ExprValue getSymbolValue(StringRef name, const Twine &loc); + ExprValue getSymbolValue(StringRef Name, const Twine &Loc); void addOrphanSections(); void adjustSectionsBeforeSorting(); @@ -270,42 +270,41 @@ class LinkerScript final { std::vector createPhdrs(); bool needsInterpSection(); - bool shouldKeep(InputSectionBase *s); - const Defined *assignAddresses(); - void allocateHeaders(std::vector &phdrs); + bool shouldKeep(InputSectionBase *S); + void assignAddresses(); + void allocateHeaders(std::vector &Phdrs); void processSectionCommands(); - void processSymbolAssignments(); void declareSymbols(); // Used to handle INSERT AFTER statements. void processInsertCommands(); // SECTIONS command list. - std::vector sectionCommands; + std::vector SectionCommands; // PHDRS command list. - std::vector phdrsCommands; + std::vector PhdrsCommands; - bool hasSectionsCommand = false; - bool errorOnMissingSection = false; + bool HasSectionsCommand = false; + bool ErrorOnMissingSection = false; // List of section patterns specified with KEEP commands. They will // be kept even if they are unused and --gc-sections is specified. - std::vector keptSections; + std::vector KeptSections; // A map from memory region name to a memory region descriptor. - llvm::MapVector memoryRegions; + llvm::MapVector MemoryRegions; // A list of symbols referenced by the script. - std::vector referencedSymbols; + std::vector ReferencedSymbols; // Used to implement INSERT [AFTER|BEFORE]. Contains commands that need // to be inserted into SECTIONS commands list. - llvm::DenseMap> insertAfterCommands; - llvm::DenseMap> insertBeforeCommands; + llvm::DenseMap> InsertAfterCommands; + llvm::DenseMap> InsertBeforeCommands; }; -extern LinkerScript *script; +extern LinkerScript *Script; } // end namespace elf } // end namespace lld diff --git a/lld/ELF/MapFile.cpp b/lld/ELF/MapFile.cpp index 678f754eaa8b2b..f5d5d5a834ea75 100644 --- a/lld/ELF/MapFile.cpp +++ b/lld/ELF/MapFile.cpp @@ -39,65 +39,65 @@ using namespace lld::elf; using SymbolMapTy = DenseMap>; -static constexpr char indent8[] = " "; // 8 spaces -static constexpr char indent16[] = " "; // 16 spaces +static const std::string Indent8 = " "; // 8 spaces +static const std::string Indent16 = " "; // 16 spaces // Print out the first three columns of a line. -static void writeHeader(raw_ostream &os, uint64_t vma, uint64_t lma, - uint64_t size, uint64_t align) { - if (config->is64) - os << format("%16llx %16llx %8llx %5lld ", vma, lma, size, align); +static void writeHeader(raw_ostream &OS, uint64_t VMA, uint64_t LMA, + uint64_t Size, uint64_t Align) { + if (Config->Is64) + OS << format("%16llx %16llx %8llx %5lld ", VMA, LMA, Size, Align); else - os << format("%8llx %8llx %8llx %5lld ", vma, lma, size, align); + OS << format("%8llx %8llx %8llx %5lld ", VMA, LMA, Size, Align); } // Returns a list of all symbols that we want to print out. static std::vector getSymbols() { - std::vector v; - for (InputFile *file : objectFiles) - for (Symbol *b : file->getSymbols()) - if (auto *dr = dyn_cast(b)) - if (!dr->isSection() && dr->section && dr->section->isLive() && - (dr->file == file || dr->needsPltAddr || dr->section->bss)) - v.push_back(dr); - return v; + std::vector V; + for (InputFile *File : ObjectFiles) + for (Symbol *B : File->getSymbols()) + if (auto *DR = dyn_cast(B)) + if (!DR->isSection() && DR->Section && DR->Section->isLive() && + (DR->File == File || DR->NeedsPltAddr || DR->Section->Bss)) + V.push_back(DR); + return V; } // Returns a map from sections to their symbols. -static SymbolMapTy getSectionSyms(ArrayRef syms) { - SymbolMapTy ret; - for (Defined *dr : syms) - ret[dr->section].push_back(dr); +static SymbolMapTy getSectionSyms(ArrayRef Syms) { + SymbolMapTy Ret; + for (Defined *DR : Syms) + Ret[DR->Section].push_back(DR); // Sort symbols by address. We want to print out symbols in the // order in the output file rather than the order they appeared // in the input files. - for (auto &it : ret) - llvm::stable_sort(it.second, [](Defined *a, Defined *b) { - return a->getVA() < b->getVA(); + for (auto &It : Ret) + llvm::stable_sort(It.second, [](Defined *A, Defined *B) { + return A->getVA() < B->getVA(); }); - return ret; + return Ret; } // Construct a map from symbols to their stringified representations. // Demangling symbols (which is what toString() does) is slow, so // we do that in batch using parallel-for. static DenseMap -getSymbolStrings(ArrayRef syms) { - std::vector str(syms.size()); - parallelForEachN(0, syms.size(), [&](size_t i) { - raw_string_ostream os(str[i]); - OutputSection *osec = syms[i]->getOutputSection(); - uint64_t vma = syms[i]->getVA(); - uint64_t lma = osec ? osec->getLMA() + vma - osec->getVA(0) : 0; - writeHeader(os, vma, lma, syms[i]->getSize(), 1); - os << indent16 << toString(*syms[i]); +getSymbolStrings(ArrayRef Syms) { + std::vector Str(Syms.size()); + parallelForEachN(0, Syms.size(), [&](size_t I) { + raw_string_ostream OS(Str[I]); + OutputSection *OSec = Syms[I]->getOutputSection(); + uint64_t VMA = Syms[I]->getVA(); + uint64_t LMA = OSec ? OSec->getLMA() + VMA - OSec->getVA(0) : 0; + writeHeader(OS, VMA, LMA, Syms[I]->getSize(), 1); + OS << Indent16 << toString(*Syms[I]); }); - DenseMap ret; - for (size_t i = 0, e = syms.size(); i < e; ++i) - ret[syms[i]] = std::move(str[i]); - return ret; + DenseMap Ret; + for (size_t I = 0, E = Syms.size(); I < E; ++I) + Ret[Syms[I]] = std::move(Str[I]); + return Ret; } // Print .eh_frame contents. Since the section consists of EhSectionPieces, @@ -106,115 +106,115 @@ getSymbolStrings(ArrayRef syms) { // .eh_frame tend to contain a lot of section pieces that are contiguous // both in input file and output file. Such pieces are squashed before // being displayed to make output compact. -static void printEhFrame(raw_ostream &os, const EhFrameSection *sec) { - std::vector pieces; +static void printEhFrame(raw_ostream &OS, const EhFrameSection *Sec) { + std::vector Pieces; - auto add = [&](const EhSectionPiece &p) { + auto Add = [&](const EhSectionPiece &P) { // If P is adjacent to Last, squash the two. - if (!pieces.empty()) { - EhSectionPiece &last = pieces.back(); - if (last.sec == p.sec && last.inputOff + last.size == p.inputOff && - last.outputOff + last.size == p.outputOff) { - last.size += p.size; + if (!Pieces.empty()) { + EhSectionPiece &Last = Pieces.back(); + if (Last.Sec == P.Sec && Last.InputOff + Last.Size == P.InputOff && + Last.OutputOff + Last.Size == P.OutputOff) { + Last.Size += P.Size; return; } } - pieces.push_back(p); + Pieces.push_back(P); }; // Gather section pieces. - for (const CieRecord *rec : sec->getCieRecords()) { - add(*rec->cie); - for (const EhSectionPiece *fde : rec->fdes) - add(*fde); + for (const CieRecord *Rec : Sec->getCieRecords()) { + Add(*Rec->Cie); + for (const EhSectionPiece *Fde : Rec->Fdes) + Add(*Fde); } // Print out section pieces. - const OutputSection *osec = sec->getOutputSection(); - for (EhSectionPiece &p : pieces) { - writeHeader(os, osec->addr + p.outputOff, osec->getLMA() + p.outputOff, - p.size, 1); - os << indent8 << toString(p.sec->file) << ":(" << p.sec->name << "+0x" - << Twine::utohexstr(p.inputOff) + ")\n"; + const OutputSection *OSec = Sec->getOutputSection(); + for (EhSectionPiece &P : Pieces) { + writeHeader(OS, OSec->Addr + P.OutputOff, OSec->getLMA() + P.OutputOff, + P.Size, 1); + OS << Indent8 << toString(P.Sec->File) << ":(" << P.Sec->Name << "+0x" + << Twine::utohexstr(P.InputOff) + ")\n"; } } void elf::writeMapFile() { - if (config->mapFile.empty()) + if (Config->MapFile.empty()) return; // Open a map file for writing. - std::error_code ec; - raw_fd_ostream os(config->mapFile, ec, sys::fs::OF_None); - if (ec) { - error("cannot open " + config->mapFile + ": " + ec.message()); + std::error_code EC; + raw_fd_ostream OS(Config->MapFile, EC, sys::fs::F_None); + if (EC) { + error("cannot open " + Config->MapFile + ": " + EC.message()); return; } // Collect symbol info that we want to print out. - std::vector syms = getSymbols(); - SymbolMapTy sectionSyms = getSectionSyms(syms); - DenseMap symStr = getSymbolStrings(syms); + std::vector Syms = getSymbols(); + SymbolMapTy SectionSyms = getSectionSyms(Syms); + DenseMap SymStr = getSymbolStrings(Syms); // Print out the header line. - int w = config->is64 ? 16 : 8; - os << right_justify("VMA", w) << ' ' << right_justify("LMA", w) + int W = Config->Is64 ? 16 : 8; + OS << right_justify("VMA", W) << ' ' << right_justify("LMA", W) << " Size Align Out In Symbol\n"; - OutputSection* osec = nullptr; - for (BaseCommand *base : script->sectionCommands) { - if (auto *cmd = dyn_cast(base)) { - if (cmd->provide && !cmd->sym) + OutputSection* OSec = nullptr; + for (BaseCommand *Base : Script->SectionCommands) { + if (auto *Cmd = dyn_cast(Base)) { + if (Cmd->Provide && !Cmd->Sym) continue; - uint64_t lma = osec ? osec->getLMA() + cmd->addr - osec->getVA(0) : 0; - writeHeader(os, cmd->addr, lma, cmd->size, 1); - os << cmd->commandString << '\n'; + uint64_t LMA = OSec ? OSec->getLMA() + Cmd->Addr - OSec->getVA(0) : 0; + writeHeader(OS, Cmd->Addr, LMA, Cmd->Size, 1); + OS << Cmd->CommandString << '\n'; continue; } - osec = cast(base); - writeHeader(os, osec->addr, osec->getLMA(), osec->size, osec->alignment); - os << osec->name << '\n'; + OSec = cast(Base); + writeHeader(OS, OSec->Addr, OSec->getLMA(), OSec->Size, OSec->Alignment); + OS << OSec->Name << '\n'; // Dump symbols for each input section. - for (BaseCommand *base : osec->sectionCommands) { - if (auto *isd = dyn_cast(base)) { - for (InputSection *isec : isd->sections) { - if (auto *ehSec = dyn_cast(isec)) { - printEhFrame(os, ehSec); + for (BaseCommand *Base : OSec->SectionCommands) { + if (auto *ISD = dyn_cast(Base)) { + for (InputSection *IS : ISD->Sections) { + if (auto *EhSec = dyn_cast(IS)) { + printEhFrame(OS, EhSec); continue; } - writeHeader(os, isec->getVA(0), osec->getLMA() + isec->getOffset(0), - isec->getSize(), isec->alignment); - os << indent8 << toString(isec) << '\n'; - for (Symbol *sym : sectionSyms[isec]) - os << symStr[sym] << '\n'; + writeHeader(OS, IS->getVA(0), OSec->getLMA() + IS->getOffset(0), + IS->getSize(), IS->Alignment); + OS << Indent8 << toString(IS) << '\n'; + for (Symbol *Sym : SectionSyms[IS]) + OS << SymStr[Sym] << '\n'; } continue; } - if (auto *cmd = dyn_cast(base)) { - writeHeader(os, osec->addr + cmd->offset, osec->getLMA() + cmd->offset, - cmd->size, 1); - os << indent8 << cmd->commandString << '\n'; + if (auto *Cmd = dyn_cast(Base)) { + writeHeader(OS, OSec->Addr + Cmd->Offset, OSec->getLMA() + Cmd->Offset, + Cmd->Size, 1); + OS << Indent8 << Cmd->CommandString << '\n'; continue; } - if (auto *cmd = dyn_cast(base)) { - if (cmd->provide && !cmd->sym) + if (auto *Cmd = dyn_cast(Base)) { + if (Cmd->Provide && !Cmd->Sym) continue; - writeHeader(os, cmd->addr, osec->getLMA() + cmd->addr - osec->getVA(0), - cmd->size, 1); - os << indent8 << cmd->commandString << '\n'; + writeHeader(OS, Cmd->Addr, OSec->getLMA() + Cmd->Addr - OSec->getVA(0), + Cmd->Size, 1); + OS << Indent8 << Cmd->CommandString << '\n'; continue; } } } } -static void print(StringRef a, StringRef b) { - outs() << left_justify(a, 49) << " " << b << "\n"; +static void print(StringRef A, StringRef B) { + outs() << left_justify(A, 49) << " " << B << "\n"; } // Output a cross reference table to stdout. This is for --cref. @@ -229,18 +229,18 @@ static void print(StringRef a, StringRef b) { // In this case, strlen is defined by libc.so.6 and used by other two // files. void elf::writeCrossReferenceTable() { - if (!config->cref) + if (!Config->Cref) return; // Collect symbols and files. - MapVector> map; - for (InputFile *file : objectFiles) { - for (Symbol *sym : file->getSymbols()) { - if (isa(sym)) - map[sym].insert(file); - if (auto *d = dyn_cast(sym)) - if (!d->isLocal() && (!d->section || d->section->isLive())) - map[d].insert(file); + MapVector> Map; + for (InputFile *File : ObjectFiles) { + for (Symbol *Sym : File->getSymbols()) { + if (isa(Sym)) + Map[Sym].insert(File); + if (auto *D = dyn_cast(Sym)) + if (!D->isLocal() && (!D->Section || D->Section->isLive())) + Map[D].insert(File); } } @@ -249,13 +249,13 @@ void elf::writeCrossReferenceTable() { print("Symbol", "File"); // Print out a table. - for (auto kv : map) { - Symbol *sym = kv.first; - SetVector &files = kv.second; + for (auto KV : Map) { + Symbol *Sym = KV.first; + SetVector &Files = KV.second; - print(toString(*sym), toString(sym->file)); - for (InputFile *file : files) - if (file != sym->file) - print("", toString(file)); + print(toString(*Sym), toString(Sym->File)); + for (InputFile *File : Files) + if (File != Sym->File) + print("", toString(File)); } } diff --git a/lld/ELF/MarkLive.cpp b/lld/ELF/MarkLive.cpp index bd29be7a4549ec..ef85075e4a3279 100644 --- a/lld/ELF/MarkLive.cpp +++ b/lld/ELF/MarkLive.cpp @@ -45,76 +45,76 @@ using namespace lld::elf; namespace { template class MarkLive { public: - MarkLive(unsigned partition) : partition(partition) {} + MarkLive(unsigned Partition) : Partition(Partition) {} void run(); void moveToMain(); private: - void enqueue(InputSectionBase *sec, uint64_t offset); - void markSymbol(Symbol *sym); + void enqueue(InputSectionBase *Sec, uint64_t Offset); + void markSymbol(Symbol *Sym); void mark(); template - void resolveReloc(InputSectionBase &sec, RelTy &rel, bool isLSDA); + void resolveReloc(InputSectionBase &Sec, RelTy &Rel, bool IsLSDA); template - void scanEhFrameSection(EhInputSection &eh, ArrayRef rels); + void scanEhFrameSection(EhInputSection &EH, ArrayRef Rels); // The index of the partition that we are currently processing. - unsigned partition; + unsigned Partition; // A list of sections to visit. - SmallVector queue; + SmallVector Queue; // There are normally few input sections whose names are valid C // identifiers, so we just store a std::vector instead of a multimap. - DenseMap> cNamedSections; + DenseMap> CNamedSections; }; } // namespace template -static uint64_t getAddend(InputSectionBase &sec, - const typename ELFT::Rel &rel) { - return target->getImplicitAddend(sec.data().begin() + rel.r_offset, - rel.getType(config->isMips64EL)); +static uint64_t getAddend(InputSectionBase &Sec, + const typename ELFT::Rel &Rel) { + return Target->getImplicitAddend(Sec.data().begin() + Rel.r_offset, + Rel.getType(Config->IsMips64EL)); } template -static uint64_t getAddend(InputSectionBase &sec, - const typename ELFT::Rela &rel) { - return rel.r_addend; +static uint64_t getAddend(InputSectionBase &Sec, + const typename ELFT::Rela &Rel) { + return Rel.r_addend; } template template -void MarkLive::resolveReloc(InputSectionBase &sec, RelTy &rel, - bool isLSDA) { - Symbol &sym = sec.getFile()->getRelocTargetSym(rel); +void MarkLive::resolveReloc(InputSectionBase &Sec, RelTy &Rel, + bool IsLSDA) { + Symbol &Sym = Sec.getFile()->getRelocTargetSym(Rel); // If a symbol is referenced in a live section, it is used. - sym.used = true; + Sym.Used = true; - if (auto *d = dyn_cast(&sym)) { - auto *relSec = dyn_cast_or_null(d->section); - if (!relSec) + if (auto *D = dyn_cast(&Sym)) { + auto *RelSec = dyn_cast_or_null(D->Section); + if (!RelSec) return; - uint64_t offset = d->value; - if (d->isSection()) - offset += getAddend(sec, rel); + uint64_t Offset = D->Value; + if (D->isSection()) + Offset += getAddend(Sec, Rel); - if (!isLSDA || !(relSec->flags & SHF_EXECINSTR)) - enqueue(relSec, offset); + if (!IsLSDA || !(RelSec->Flags & SHF_EXECINSTR)) + enqueue(RelSec, Offset); return; } - if (auto *ss = dyn_cast(&sym)) - if (!ss->isWeak()) - ss->getFile().isNeeded = true; + if (auto *SS = dyn_cast(&Sym)) + if (!SS->isWeak()) + SS->getFile().IsNeeded = true; - for (InputSectionBase *sec : cNamedSections.lookup(sym.getName())) - enqueue(sec, 0); + for (InputSectionBase *Sec : CNamedSections.lookup(Sym.getName())) + enqueue(Sec, 0); } // The .eh_frame section is an unfortunate special case. @@ -133,80 +133,80 @@ void MarkLive::resolveReloc(InputSectionBase &sec, RelTy &rel, // LSDAs and personality functions if we found that they were unused. template template -void MarkLive::scanEhFrameSection(EhInputSection &eh, - ArrayRef rels) { - for (size_t i = 0, end = eh.pieces.size(); i < end; ++i) { - EhSectionPiece &piece = eh.pieces[i]; - size_t firstRelI = piece.firstRelocation; - if (firstRelI == (unsigned)-1) +void MarkLive::scanEhFrameSection(EhInputSection &EH, + ArrayRef Rels) { + for (size_t I = 0, End = EH.Pieces.size(); I < End; ++I) { + EhSectionPiece &Piece = EH.Pieces[I]; + size_t FirstRelI = Piece.FirstRelocation; + if (FirstRelI == (unsigned)-1) continue; - if (read32(piece.data().data() + 4) == 0) { + if (read32(Piece.data().data() + 4) == 0) { // This is a CIE, we only need to worry about the first relocation. It is // known to point to the personality function. - resolveReloc(eh, rels[firstRelI], false); + resolveReloc(EH, Rels[FirstRelI], false); continue; } // This is a FDE. The relocations point to the described function or to // a LSDA. We only need to keep the LSDA alive, so ignore anything that // points to executable sections. - uint64_t pieceEnd = piece.inputOff + piece.size; - for (size_t j = firstRelI, end2 = rels.size(); j < end2; ++j) - if (rels[j].r_offset < pieceEnd) - resolveReloc(eh, rels[j], true); + uint64_t PieceEnd = Piece.InputOff + Piece.Size; + for (size_t J = FirstRelI, End2 = Rels.size(); J < End2; ++J) + if (Rels[J].r_offset < PieceEnd) + resolveReloc(EH, Rels[J], true); } } // Some sections are used directly by the loader, so they should never be // garbage-collected. This function returns true if a given section is such // section. -static bool isReserved(InputSectionBase *sec) { - switch (sec->type) { +static bool isReserved(InputSectionBase *Sec) { + switch (Sec->Type) { case SHT_FINI_ARRAY: case SHT_INIT_ARRAY: case SHT_NOTE: case SHT_PREINIT_ARRAY: return true; default: - StringRef s = sec->name; - return s.startswith(".ctors") || s.startswith(".dtors") || - s.startswith(".init") || s.startswith(".fini") || - s.startswith(".jcr"); + StringRef S = Sec->Name; + return S.startswith(".ctors") || S.startswith(".dtors") || + S.startswith(".init") || S.startswith(".fini") || + S.startswith(".jcr"); } } template -void MarkLive::enqueue(InputSectionBase *sec, uint64_t offset) { +void MarkLive::enqueue(InputSectionBase *Sec, uint64_t Offset) { // Skip over discarded sections. This in theory shouldn't happen, because // the ELF spec doesn't allow a relocation to point to a deduplicated // COMDAT section directly. Unfortunately this happens in practice (e.g. // .eh_frame) so we need to add a check. - if (sec == &InputSection::discarded) + if (Sec == &InputSection::Discarded) return; // Usually, a whole section is marked as live or dead, but in mergeable // (splittable) sections, each piece of data has independent liveness bit. // So we explicitly tell it which offset is in use. - if (auto *ms = dyn_cast(sec)) - ms->getSectionPiece(offset)->live = true; + if (auto *MS = dyn_cast(Sec)) + MS->getSectionPiece(Offset)->Live = true; // Set Sec->Partition to the meet (i.e. the "minimum") of Partition and // Sec->Partition in the following lattice: 1 < other < 0. If Sec->Partition // doesn't change, we don't need to do anything. - if (sec->partition == 1 || sec->partition == partition) + if (Sec->Partition == 1 || Sec->Partition == Partition) return; - sec->partition = sec->partition ? 1 : partition; + Sec->Partition = Sec->Partition ? 1 : Partition; // Add input section to the queue. - if (InputSection *s = dyn_cast(sec)) - queue.push_back(s); + if (InputSection *S = dyn_cast(Sec)) + Queue.push_back(S); } -template void MarkLive::markSymbol(Symbol *sym) { - if (auto *d = dyn_cast_or_null(sym)) - if (auto *isec = dyn_cast_or_null(d->section)) - enqueue(isec, d->value); +template void MarkLive::markSymbol(Symbol *Sym) { + if (auto *D = dyn_cast_or_null(Sym)) + if (auto *IS = dyn_cast_or_null(D->Section)) + enqueue(IS, D->Value); } // This is the main function of the garbage collector. @@ -217,51 +217,51 @@ template void MarkLive::run() { // Preserve externally-visible symbols if the symbols defined by this // file can interrupt other ELF file's symbols at runtime. - symtab->forEachSymbol([&](Symbol *sym) { - if (sym->includeInDynsym() && sym->partition == partition) - markSymbol(sym); + Symtab->forEachSymbol([&](Symbol *Sym) { + if (Sym->includeInDynsym() && Sym->Partition == Partition) + markSymbol(Sym); }); // If this isn't the main partition, that's all that we need to preserve. - if (partition != 1) { + if (Partition != 1) { mark(); return; } - markSymbol(symtab->find(config->entry)); - markSymbol(symtab->find(config->init)); - markSymbol(symtab->find(config->fini)); - for (StringRef s : config->undefined) - markSymbol(symtab->find(s)); - for (StringRef s : script->referencedSymbols) - markSymbol(symtab->find(s)); + markSymbol(Symtab->find(Config->Entry)); + markSymbol(Symtab->find(Config->Init)); + markSymbol(Symtab->find(Config->Fini)); + for (StringRef S : Config->Undefined) + markSymbol(Symtab->find(S)); + for (StringRef S : Script->ReferencedSymbols) + markSymbol(Symtab->find(S)); // Preserve special sections and those which are specified in linker // script KEEP command. - for (InputSectionBase *sec : inputSections) { + for (InputSectionBase *Sec : InputSections) { // Mark .eh_frame sections as live because there are usually no relocations // that point to .eh_frames. Otherwise, the garbage collector would drop // all of them. We also want to preserve personality routines and LSDA // referenced by .eh_frame sections, so we scan them for that here. - if (auto *eh = dyn_cast(sec)) { - eh->markLive(); - if (!eh->numRelocations) + if (auto *EH = dyn_cast(Sec)) { + EH->markLive(); + if (!EH->NumRelocations) continue; - if (eh->areRelocsRela) - scanEhFrameSection(*eh, eh->template relas()); + if (EH->AreRelocsRela) + scanEhFrameSection(*EH, EH->template relas()); else - scanEhFrameSection(*eh, eh->template rels()); + scanEhFrameSection(*EH, EH->template rels()); } - if (sec->flags & SHF_LINK_ORDER) + if (Sec->Flags & SHF_LINK_ORDER) continue; - if (isReserved(sec) || script->shouldKeep(sec)) { - enqueue(sec, 0); - } else if (isValidCIdentifier(sec->name)) { - cNamedSections[saver.save("__start_" + sec->name)].push_back(sec); - cNamedSections[saver.save("__stop_" + sec->name)].push_back(sec); + if (isReserved(Sec) || Script->shouldKeep(Sec)) { + enqueue(Sec, 0); + } else if (isValidCIdentifier(Sec->Name)) { + CNamedSections[Saver.save("__start_" + Sec->Name)].push_back(Sec); + CNamedSections[Saver.save("__stop_" + Sec->Name)].push_back(Sec); } } @@ -270,19 +270,19 @@ template void MarkLive::run() { template void MarkLive::mark() { // Mark all reachable sections. - while (!queue.empty()) { - InputSectionBase &sec = *queue.pop_back_val(); + while (!Queue.empty()) { + InputSectionBase &Sec = *Queue.pop_back_val(); - if (sec.areRelocsRela) { - for (const typename ELFT::Rela &rel : sec.template relas()) - resolveReloc(sec, rel, false); + if (Sec.AreRelocsRela) { + for (const typename ELFT::Rela &Rel : Sec.template relas()) + resolveReloc(Sec, Rel, false); } else { - for (const typename ELFT::Rel &rel : sec.template rels()) - resolveReloc(sec, rel, false); + for (const typename ELFT::Rel &Rel : Sec.template rels()) + resolveReloc(Sec, Rel, false); } - for (InputSectionBase *isec : sec.dependentSections) - enqueue(isec, 0); + for (InputSectionBase *IS : Sec.DependentSections) + enqueue(IS, 0); } } @@ -291,25 +291,13 @@ template void MarkLive::mark() { // GOT, which means that the ifunc must be available when the main partition is // loaded) and TLS symbols (because we only know how to correctly process TLS // relocations for the main partition). -// -// We also need to move sections whose names are C identifiers that are referred -// to from __start_/__stop_ symbols because there will only be one set of -// symbols for the whole program. template void MarkLive::moveToMain() { - for (InputFile *file : objectFiles) - for (Symbol *s : file->getSymbols()) - if (auto *d = dyn_cast(s)) - if ((d->type == STT_GNU_IFUNC || d->type == STT_TLS) && d->section && - d->section->isLive()) - markSymbol(s); - - for (InputSectionBase *sec : inputSections) { - if (!sec->isLive() || !isValidCIdentifier(sec->name)) - continue; - if (symtab->find(("__start_" + sec->name).str()) || - symtab->find(("__stop_" + sec->name).str())) - enqueue(sec, 0); - } + for (InputFile *File : ObjectFiles) + for (Symbol *S : File->getSymbols()) + if (auto *D = dyn_cast(S)) + if ((D->Type == STT_GNU_IFUNC || D->Type == STT_TLS) && D->Section && + D->Section->isLive()) + markSymbol(S); mark(); } @@ -319,15 +307,15 @@ template void MarkLive::moveToMain() { // so that they are emitted to the output file. template void elf::markLive() { // If -gc-sections is not given, no sections are removed. - if (!config->gcSections) { - for (InputSectionBase *sec : inputSections) - sec->markLive(); + if (!Config->GcSections) { + for (InputSectionBase *Sec : InputSections) + Sec->markLive(); // If a DSO defines a symbol referenced in a regular object, it is needed. - symtab->forEachSymbol([](Symbol *sym) { - if (auto *s = dyn_cast(sym)) - if (s->isUsedInRegularObj && !s->isWeak()) - s->getFile().isNeeded = true; + Symtab->forEachSymbol([](Symbol *Sym) { + if (auto *S = dyn_cast(Sym)) + if (S->IsUsedInRegularObj && !S->isWeak()) + S->getFile().IsNeeded = true; }); return; } @@ -353,30 +341,30 @@ template void elf::markLive() { // or -emit-reloc were given. And they are subject of garbage // collection because, if we remove a text section, we also // remove its relocation section. - for (InputSectionBase *sec : inputSections) { - bool isAlloc = (sec->flags & SHF_ALLOC); - bool isLinkOrder = (sec->flags & SHF_LINK_ORDER); - bool isRel = (sec->type == SHT_REL || sec->type == SHT_RELA); + for (InputSectionBase *Sec : InputSections) { + bool IsAlloc = (Sec->Flags & SHF_ALLOC); + bool IsLinkOrder = (Sec->Flags & SHF_LINK_ORDER); + bool IsRel = (Sec->Type == SHT_REL || Sec->Type == SHT_RELA); - if (!isAlloc && !isLinkOrder && !isRel) - sec->markLive(); + if (!IsAlloc && !IsLinkOrder && !IsRel) + Sec->markLive(); } // Follow the graph to mark all live sections. - for (unsigned curPart = 1; curPart <= partitions.size(); ++curPart) - MarkLive(curPart).run(); + for (unsigned CurPart = 1; CurPart <= Partitions.size(); ++CurPart) + MarkLive(CurPart).run(); // If we have multiple partitions, some sections need to live in the main // partition even if they were allocated to a loadable partition. Move them // there now. - if (partitions.size() != 1) + if (Partitions.size() != 1) MarkLive(1).moveToMain(); // Report garbage-collected sections. - if (config->printGcSections) - for (InputSectionBase *sec : inputSections) - if (!sec->isLive()) - message("removing unused section " + toString(sec)); + if (Config->PrintGcSections) + for (InputSectionBase *Sec : InputSections) + if (!Sec->isLive()) + message("removing unused section " + toString(Sec)); } template void elf::markLive(); diff --git a/lld/ELF/Options.td b/lld/ELF/Options.td index 6246d84946b6f8..d45d9aaad9af9b 100644 --- a/lld/ELF/Options.td +++ b/lld/ELF/Options.td @@ -306,7 +306,7 @@ def push_state: F<"push-state">, def print_map: F<"print-map">, HelpText<"Print a link map to the standard output">; -defm reproduce: Eq<"reproduce", "Write a tar file containing input files and command line options to reproduce link">; +defm reproduce: Eq<"reproduce", "Dump linker invocation and input files for debugging">; defm rpath: Eq<"rpath", "Add a DT_RUNPATH to the output">; @@ -416,9 +416,6 @@ defm wrap: Eq<"wrap", "Use wrapper functions for symbol">, def z: JoinedOrSeparate<["-"], "z">, MetaVarName<"