From 39803d4d3cbf818641437afb7402da15fa076bec Mon Sep 17 00:00:00 2001 From: Jan Vorlicek Date: Wed, 28 Jul 2021 22:51:25 +0200 Subject: [PATCH] Fix redhat arm64 (#52244) * Fix RHEL 8 ARM64 Clang on ARM64 places the .rodata section into the same segment as .text. On RHEL 8 ARM64, the kernel is configured for 64kB memory pages. When we flip the page protection of the page containing the GS cookie to RW and back to RO, we assume that the cookie lives in a non-executable memory. This assumption is broken on RHEL 8 and we end up setting protection of a part of the coreclr code to read only instead of back to RX. This change switches the linker we use to lld from the previously used gnu linker. That linker places .rodata into a different segment than .text by default. Moreover, I was planning to move to using lld anyways to use all build tools from LLVM. * Fix ARM build to use PC relative addresses only The lld linker has revealed that we were using absolute addresses in some asm helpers and so load time relocation was necessary. This change fixes it by replacing all of those by PC relative ones. * Update docker images used for building runtime Use new images that have lld linker * Disable lld linker for s390x --- eng/common/templates/jobs/source-build.yml | 2 +- eng/native/configuretools.cmake | 6 ++++-- eng/native/functions.cmake | 2 +- eng/native/init-compiler.sh | 12 +++++++++++- eng/pipelines/common/platform-matrix.yml | 14 +++++++------- src/coreclr/pgosupport.cmake | 10 ++++++++-- src/coreclr/vm/CMakeLists.txt | 2 +- src/coreclr/vm/arm/asmhelpers.S | 9 ++++++--- src/coreclr/vm/arm/pinvokestubs.S | 15 +++++++++------ src/coreclr/vm/arm/stubs.cpp | 6 +++--- 10 files changed, 51 insertions(+), 27 deletions(-) diff --git a/eng/common/templates/jobs/source-build.yml b/eng/common/templates/jobs/source-build.yml index 00aa98eb3bfd3..b7737ffec3ef4 100644 --- a/eng/common/templates/jobs/source-build.yml +++ b/eng/common/templates/jobs/source-build.yml @@ -14,7 +14,7 @@ parameters: # This is the default platform provided by Arcade, intended for use by a managed-only repo. defaultManagedPlatform: name: 'Managed' - container: 'mcr.microsoft.com/dotnet-buildtools/prereqs:centos-7-3e800f1-20190501005343' + container: 'mcr.microsoft.com/dotnet-buildtools/prereqs:centos-7-20210714125435-9b5bbc2' # Defines the platforms on which to run build jobs. One job is created for each platform, and the # object in this array is sent to the job template as 'platform'. If no platforms are specified, diff --git a/eng/native/configuretools.cmake b/eng/native/configuretools.cmake index 37f3b4932cd22..136cd67925d0c 100644 --- a/eng/native/configuretools.cmake +++ b/eng/native/configuretools.cmake @@ -65,12 +65,14 @@ endif() if (NOT CLR_CMAKE_HOST_WIN32) # detect linker - set(ldVersion ${CMAKE_C_COMPILER};-Wl,--version) + separate_arguments(ldVersion UNIX_COMMAND "${CMAKE_C_COMPILER} ${CMAKE_SHARED_LINKER_FLAGS} -Wl,--version") execute_process(COMMAND ${ldVersion} ERROR_QUIET OUTPUT_VARIABLE ldVersionOutput) - if("${ldVersionOutput}" MATCHES "GNU ld" OR "${ldVersionOutput}" MATCHES "GNU gold" OR "${ldVersionOutput}" MATCHES "GNU linkers") + if("${ldVersionOutput}" MATCHES "LLD") + set(LD_LLVM 1) + elseif("${ldVersionOutput}" MATCHES "GNU ld" OR "${ldVersionOutput}" MATCHES "GNU gold" OR "${ldVersionOutput}" MATCHES "GNU linkers") set(LD_GNU 1) elseif("${ldVersionOutput}" MATCHES "Solaris Link") set(LD_SOLARIS 1) diff --git a/eng/native/functions.cmake b/eng/native/functions.cmake index 1ca230c3e534d..0d03cc3d2d46e 100644 --- a/eng/native/functions.cmake +++ b/eng/native/functions.cmake @@ -157,7 +157,7 @@ function(preprocess_files PreprocessedFilesList) endfunction() function(set_exports_linker_option exports_filename) - if(LD_GNU OR LD_SOLARIS) + if(LD_GNU OR LD_SOLARIS OR LD_LLVM) # Add linker exports file option if(LD_SOLARIS) set(EXPORTS_LINKER_OPTION -Wl,-M,${exports_filename} PARENT_SCOPE) diff --git a/eng/native/init-compiler.sh b/eng/native/init-compiler.sh index ca408e4d08816..567d18da4747a 100755 --- a/eng/native/init-compiler.sh +++ b/eng/native/init-compiler.sh @@ -22,6 +22,7 @@ minorVersion="$4" # clear the existing CC and CXX from environment CC= CXX= +LDFLAGS= if [[ "$compiler" == "gcc" ]]; then cxxCompiler="g++"; fi @@ -106,6 +107,15 @@ if [[ -z "$CC" ]]; then exit 1 fi +if [[ "$compiler" == "clang" ]]; then + if command -v "lld$desired_version" > /dev/null; then + # Only lld version >= 9 can be considered stable + if [[ "$majorVersion" -ge 9 ]]; then + LDFLAGS="-fuse-ld=lld" + fi + fi +fi + SCAN_BUILD_COMMAND="$(command -v "scan-build$desired_version")" -export CC CXX SCAN_BUILD_COMMAND +export CC CXX LDFLAGS SCAN_BUILD_COMMAND diff --git a/eng/pipelines/common/platform-matrix.yml b/eng/pipelines/common/platform-matrix.yml index defd34be84ae2..15fe948e92967 100644 --- a/eng/pipelines/common/platform-matrix.yml +++ b/eng/pipelines/common/platform-matrix.yml @@ -38,7 +38,7 @@ jobs: targetRid: linux-arm platform: Linux_arm container: - image: ubuntu-16.04-cross-20200413125008-09ec757 + image: ubuntu-16.04-cross-20210719121212-8a8d3be registry: mcr jobParameters: runtimeFlavor: ${{ parameters.runtimeFlavor }} @@ -64,7 +64,7 @@ jobs: targetRid: linux-arm64 platform: Linux_arm64 container: - image: ubuntu-16.04-cross-arm64-20201022204150-b2c2436 + image: ubuntu-16.04-cross-arm64-20210719121212-8a8d3be registry: mcr jobParameters: runtimeFlavor: ${{ parameters.runtimeFlavor }} @@ -91,7 +91,7 @@ jobs: targetRid: linux-musl-x64 platform: Linux_musl_x64 container: - image: alpine-3.9-WithNode-20200602002639-0fc54a3 + image: alpine-3.9-WithNode-20210714125437-9b5bbc2 registry: mcr jobParameters: runtimeFlavor: ${{ parameters.runtimeFlavor }} @@ -116,7 +116,7 @@ jobs: targetRid: linux-musl-arm platform: Linux_musl_arm container: - image: ubuntu-16.04-cross-arm-alpine-20210409142327-044d5b9 + image: ubuntu-16.04-cross-arm-alpine-20210719121212-044d5b9 registry: mcr jobParameters: runtimeFlavor: ${{ parameters.runtimeFlavor }} @@ -143,7 +143,7 @@ jobs: targetRid: linux-musl-arm64 platform: Linux_musl_arm64 container: - image: ubuntu-16.04-cross-arm64-alpine-20200413125008-406629a + image: ubuntu-16.04-cross-arm64-alpine-20210719121212-b2c2436 registry: mcr jobParameters: runtimeFlavor: ${{ parameters.runtimeFlavor }} @@ -169,7 +169,7 @@ jobs: targetRid: linux-x64 platform: Linux_x64 container: - image: centos-7-20201227183837-5fe0e50 + image: centos-7-20210714125435-9b5bbc2 registry: mcr jobParameters: runtimeFlavor: ${{ parameters.runtimeFlavor }} @@ -193,7 +193,7 @@ jobs: targetRid: linux-x64 platform: Linux_x64 container: - image: centos-7-source-build-20210408124356-5d87b80 + image: centos-7-source-build-20210714125450-5d87b80 registry: mcr jobParameters: runtimeFlavor: ${{ parameters.runtimeFlavor }} diff --git a/src/coreclr/pgosupport.cmake b/src/coreclr/pgosupport.cmake index 6f07f1cd5ea8d..7c20ca3090ae3 100644 --- a/src/coreclr/pgosupport.cmake +++ b/src/coreclr/pgosupport.cmake @@ -30,7 +30,10 @@ function(add_pgo TargetName) else(CLR_CMAKE_HOST_WIN32) if(UPPERCASE_CMAKE_BUILD_TYPE STREQUAL RELEASE OR UPPERCASE_CMAKE_BUILD_TYPE STREQUAL RELWITHDEBINFO) target_compile_options(${TargetName} PRIVATE -flto -fprofile-instr-generate) - set_property(TARGET ${TargetName} APPEND_STRING PROPERTY LINK_FLAGS " -flto -fuse-ld=gold -fprofile-instr-generate") + set_property(TARGET ${TargetName} APPEND_STRING PROPERTY LINK_FLAGS " -flto -fprofile-instr-generate") + if(NOT LD_LLVM) + set_property(TARGET ${TargetName} APPEND_STRING PROPERTY LINK_FLAGS " -fuse-ld=gold") + endif() endif(UPPERCASE_CMAKE_BUILD_TYPE STREQUAL RELEASE OR UPPERCASE_CMAKE_BUILD_TYPE STREQUAL RELWITHDEBINFO) endif(CLR_CMAKE_HOST_WIN32) elseif(CLR_CMAKE_PGO_OPTIMIZE) @@ -61,7 +64,10 @@ function(add_pgo TargetName) if((CMAKE_CXX_COMPILER_ID MATCHES "Clang") AND (NOT CMAKE_CXX_COMPILER_VERSION VERSION_LESS 3.6)) if(HAVE_LTO) target_compile_options(${TargetName} PRIVATE -flto -fprofile-instr-use=${ProfilePath} -Wno-profile-instr-out-of-date -Wno-profile-instr-unprofiled) - set_property(TARGET ${TargetName} APPEND_STRING PROPERTY LINK_FLAGS " -flto -fuse-ld=gold -fprofile-instr-use=${ProfilePath}") + set_property(TARGET ${TargetName} APPEND_STRING PROPERTY LINK_FLAGS " -flto -fprofile-instr-use=${ProfilePath}") + if(NOT LD_LLVM) + set_property(TARGET ${TargetName} APPEND_STRING PROPERTY LINK_FLAGS " -fuse-ld=gold") + endif() else(HAVE_LTO) message(WARNING "LTO is not supported, skipping profile guided optimizations") endif(HAVE_LTO) diff --git a/src/coreclr/vm/CMakeLists.txt b/src/coreclr/vm/CMakeLists.txt index f31e5a3ca12a6..d0f96523613bc 100644 --- a/src/coreclr/vm/CMakeLists.txt +++ b/src/coreclr/vm/CMakeLists.txt @@ -855,7 +855,6 @@ elseif(CLR_CMAKE_TARGET_ARCH_ARM64) set(VM_SOURCES_DAC_AND_WKS_ARCH ${ARCH_SOURCES_DIR}/stubs.cpp exceptionhandling.cpp - gcinfodecoder.cpp ) set(VM_HEADERS_DAC_AND_WKS_ARCH @@ -865,6 +864,7 @@ elseif(CLR_CMAKE_TARGET_ARCH_ARM64) set(VM_SOURCES_WKS_ARCH ${ARCH_SOURCES_DIR}/profiler.cpp + gcinfodecoder.cpp ) if(CLR_CMAKE_HOST_UNIX) diff --git a/src/coreclr/vm/arm/asmhelpers.S b/src/coreclr/vm/arm/asmhelpers.S index 3faa8fe36846e..2780f95912f17 100644 --- a/src/coreclr/vm/arm/asmhelpers.S +++ b/src/coreclr/vm/arm/asmhelpers.S @@ -928,8 +928,9 @@ LOCAL_LABEL(CallCppHelper3): .endm .macro JIT_WRITEBARRIER_DESCRIPTOR name - .word \name - .word \name\()_End +1: + .word \name-1b + .word \name\()_End-1b .word __\name\()__g_lowest_address_offset .word __\name\()__g_highest_address_offset .word __\name\()__g_ephemeral_low_offset @@ -983,7 +984,9 @@ g_rgWriteBarrierDescriptors: LEAF_ENTRY JIT_WriteBarrier_Callable // Branch to the write barrier - ldr r2, =JIT_WriteBarrier_Loc // or R3? See targetarm.h + ldr r2, =JIT_WriteBarrier_Loc-(1f+4) // or R3? See targetarm.h +1: + add r2, pc ldr pc, [r2] LEAF_END JIT_WriteBarrier_Callable diff --git a/src/coreclr/vm/arm/pinvokestubs.S b/src/coreclr/vm/arm/pinvokestubs.S index 8e7c468c36163..cd4928003b593 100644 --- a/src/coreclr/vm/arm/pinvokestubs.S +++ b/src/coreclr/vm/arm/pinvokestubs.S @@ -84,7 +84,9 @@ PROLOG_PUSH "{r4, lr}" - ldr r1, =s_gsCookie + ldr r1, =s_gsCookie-(1f+4) +1: + add r1, pc ldr r1, [r1] str r1, [r0] add r4, r0, SIZEOF__GSCookie @@ -92,7 +94,9 @@ // r4 = pFrame // set first slot to the value of InlinedCallFrame::`vftable' (checked by runtime code) - ldr r1, .L12 + ldr r1, =_ZTV16InlinedCallFrame+8-(2f+4) +2: + add r1, pc str r1, [r4] mov r1, 0 @@ -123,9 +127,6 @@ NESTED_END JIT_PInvokeBegin, _TEXT -.L12: - .word _ZTV16InlinedCallFrame+8 - // ------------------------------------------------------------------ // IN: // InlinedCallFrame (r0) = pointer to the InlinedCallFrame data, including the GS cookie slot (GS cookie right @@ -145,7 +146,9 @@ str r2, [r1, #Thread_m_fPreemptiveGCDisabled] // Check return trap - ldr r2, =g_TrapReturningThreads + ldr r2, =g_TrapReturningThreads-(1f+4) +1: + add r2, pc ldr r2, [r2] cbnz r2, LOCAL_LABEL(RarePath) diff --git a/src/coreclr/vm/arm/stubs.cpp b/src/coreclr/vm/arm/stubs.cpp index 6e62df2370338..6b4f71f245530 100644 --- a/src/coreclr/vm/arm/stubs.cpp +++ b/src/coreclr/vm/arm/stubs.cpp @@ -281,8 +281,8 @@ void StubLinkerCPU::Init(void) // value of the global into a register. struct WriteBarrierDescriptor { - BYTE * m_pFuncStart; // Pointer to the start of the barrier function - BYTE * m_pFuncEnd; // Pointer to the end of the barrier function + DWORD m_pFuncStart; // Offset to the start of the barrier function relative to this struct address + DWORD m_pFuncEnd; // Offset to the end of the barrier function relative to this struct address DWORD m_dw_g_lowest_address_offset; // Offset of the instruction reading g_lowest_address DWORD m_dw_g_highest_address_offset; // Offset of the instruction reading g_highest_address DWORD m_dw_g_ephemeral_low_offset; // Offset of the instruction reading g_ephemeral_low @@ -440,7 +440,7 @@ void UpdateGCWriteBarriers(bool postGrow = false) { // If the write barrier is being currently used (as in copied over to the patchable site) // then read the patch location from the table and use the offset to patch the target asm code - PBYTE to = FindWBMapping(pDesc->m_pFuncStart); + PBYTE to = FindWBMapping((BYTE *)pDesc + pDesc->m_pFuncStart); if(to) { to = (PBYTE)PCODEToPINSTR((PCODE)GetWriteBarrierCodeLocation(to));