Index: ELF/Arch/ARM.cpp =================================================================== --- ELF/Arch/ARM.cpp +++ ELF/Arch/ARM.cpp @@ -97,10 +97,19 @@ } 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; + // 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; + return EF_ARM_EABI_VER5 | ABIFloatType; } RelExpr ARM::getRelExpr(RelType Type, const Symbol &S, Index: ELF/Config.h =================================================================== --- ELF/Config.h +++ ELF/Config.h @@ -58,6 +58,9 @@ // For --target2 enum class Target2Policy { Abs, Rel, GotRel }; +// For tracking ARM Float Argument PCS +enum class ARMVFPArgKind { Default, Base, VFP, ToolChain }; + struct SymbolVersion { llvm::StringRef Name; bool IsExternCpp; @@ -196,6 +199,7 @@ 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; Index: ELF/InputFiles.cpp =================================================================== --- ELF/InputFiles.cpp +++ ELF/InputFiles.cpp @@ -494,6 +494,46 @@ } } +// 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)) + // 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) + // don't have the attribute so we do not consider an implicit value of 0 + // as a clash. + return; + + unsigned VFPArgs = Attributes.getAttributeValue(ARMBuildAttrs::ABI_VFP_args); + ARMVFPArgKind Arg; + switch (VFPArgs) { + case ARMBuildAttrs::BaseAAPCS: + Arg = ARMVFPArgKind::Base; + break; + case ARMBuildAttrs::HardFPAAPCS: + Arg = ARMVFPArgKind::VFP; + break; + case ARMBuildAttrs::ToolChainFPPCS: + // Tool chain specific convention that conforms to neither AAPCS variant. + 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)); + 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"); + else + Config->ARMVFPArgs = Arg; +} + // The ARM support in lld makes some use of instructions that are not available // on all ARM architectures. Namely: // - Use of BLX instruction for interworking between ARM and Thumb state. @@ -573,6 +613,8 @@ 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. Index: test/ELF/Inputs/arm-vfp-arg-base.s =================================================================== --- test/ELF/Inputs/arm-vfp-arg-base.s +++ test/ELF/Inputs/arm-vfp-arg-base.s @@ -0,0 +1,16 @@ + .arch armv7-a + .eabi_attribute 20, 1 + .eabi_attribute 21, 1 + .eabi_attribute 23, 3 + .eabi_attribute 24, 1 + .eabi_attribute 25, 1 + .eabi_attribute 26, 2 + .eabi_attribute 30, 6 + .eabi_attribute 34, 1 + .eabi_attribute 18, 4 + .eabi_attribute 28, 0 // Tag_ABI_VFP_args = 0 (AAPCS, Base variant) + + .syntax unified + .global f0 + .type f0, %function +f0: bx lr Index: test/ELF/Inputs/arm-vfp-arg-compat.s =================================================================== --- test/ELF/Inputs/arm-vfp-arg-compat.s +++ test/ELF/Inputs/arm-vfp-arg-compat.s @@ -0,0 +1,16 @@ + .arch armv7-a + .eabi_attribute 20, 1 + .eabi_attribute 21, 1 + .eabi_attribute 23, 3 + .eabi_attribute 24, 1 + .eabi_attribute 25, 1 + .eabi_attribute 26, 2 + .eabi_attribute 30, 6 + .eabi_attribute 34, 1 + .eabi_attribute 18, 4 + .eabi_attribute 28, 3 // Tag_ABI_VFP_args = 3 (Compatible with all) + + .syntax unified + .global f3 + .type f3, %function +f3: bx lr Index: test/ELF/Inputs/arm-vfp-arg-toolchain.s =================================================================== --- test/ELF/Inputs/arm-vfp-arg-toolchain.s +++ test/ELF/Inputs/arm-vfp-arg-toolchain.s @@ -0,0 +1,15 @@ + .arch armv7-a + .eabi_attribute 20, 1 + .eabi_attribute 21, 1 + .eabi_attribute 23, 3 + .eabi_attribute 24, 1 + .eabi_attribute 25, 1 + .eabi_attribute 26, 2 + .eabi_attribute 30, 6 + .eabi_attribute 34, 1 + .eabi_attribute 18, 4 + .eabi_attribute 28, 2 // Tag_ABI_VFP_args = 2 (Toolchain specific) + .syntax unified + .global f2 + .type f1, %function +f2: bx lr Index: test/ELF/Inputs/arm-vfp-arg-vfp.s =================================================================== --- test/ELF/Inputs/arm-vfp-arg-vfp.s +++ test/ELF/Inputs/arm-vfp-arg-vfp.s @@ -0,0 +1,15 @@ + .arch armv7-a + .eabi_attribute 20, 1 + .eabi_attribute 21, 1 + .eabi_attribute 23, 3 + .eabi_attribute 24, 1 + .eabi_attribute 25, 1 + .eabi_attribute 26, 2 + .eabi_attribute 30, 6 + .eabi_attribute 34, 1 + .eabi_attribute 18, 4 + .eabi_attribute 28, 1 // Tag_ABI_VFP_args = 1 (AAPCS, VFP variant) + .syntax unified + .global f1 + .type f1, %function +f1: bx lr Index: test/ELF/arm-eabi-version.s =================================================================== --- test/ELF/arm-eabi-version.s +++ test/ELF/arm-eabi-version.s @@ -9,6 +9,7 @@ bx lr // CHECK: Flags [ +// CHECK-NEXT: 0x200 // CHECK-NEXT: 0x1000000 // CHECK-NEXT: 0x4000000 // CHECK-NEXT: ] Index: test/ELF/arm-tag-vfp-args-errs.s =================================================================== --- test/ELF/arm-tag-vfp-args-errs.s +++ test/ELF/arm-tag-vfp-args-errs.s @@ -0,0 +1,29 @@ +// REQUIRES:arm +// RUN: llvm-mc -filetype=obj -triple=armv7a-none-linux-gnueabi %S/Inputs/arm-vfp-arg-base.s -o %tbase.o +// RUN: llvm-mc -filetype=obj -triple=armv7a-none-linux-gnueabi %S/Inputs/arm-vfp-arg-vfp.s -o %tvfp.o +// RUN: llvm-mc -filetype=obj -triple=armv7a-none-linux-gnueabi %S/Inputs/arm-vfp-arg-toolchain.s -o %ttoolchain.o +// RUN: llvm-mc -filetype=obj -triple=armv7a-none-linux-gnueabi %s -o %t.o +// RUN: not ld.lld %t.o %tbase.o %tvfp.o 2>&1 | FileCheck %s +// RUN: not ld.lld %t.o %tbase.o %ttoolchain.o 2>&1 | FileCheck %s +// RUN: not ld.lld %t.o %tvfp.o %tbase.o 2>&1 | FileCheck %s +// RUN: not ld.lld %t.o %tvfp.o %ttoolchain.o 2>&1 | FileCheck %s +// RUN: not ld.lld %t.o %ttoolchain.o %tbase.o 2>&1 | FileCheck %s +// RUN: not ld.lld %t.o %ttoolchain.o %tvfp.o 2>&1 | FileCheck %s + +// CHECK: incompatible Tag_ABI_VFP_args + .arch armv7-a + .eabi_attribute 20, 1 + .eabi_attribute 21, 1 + .eabi_attribute 23, 3 + .eabi_attribute 24, 1 + .eabi_attribute 25, 1 + .eabi_attribute 26, 2 + .eabi_attribute 30, 6 + .eabi_attribute 34, 1 + .eabi_attribute 18, 4 + .eabi_attribute 28, 3 // Tag_ABI_VFP_args = 3 (Compatible with all) + + .syntax unified + .globl _start + .type _start, %function +_start: bx lr Index: test/ELF/arm-tag-vfp-args-illegal.s =================================================================== --- test/ELF/arm-tag-vfp-args-illegal.s +++ test/ELF/arm-tag-vfp-args-illegal.s @@ -0,0 +1,21 @@ +// REQUIRES:arm +// RUN: llvm-mc -filetype=obj -triple=armv7a-none-linux-gnueabi %s -o %t.o +// RUN: not ld.lld %t.o -o %t 2>&1 | FileCheck %s + +// CHECK: arm-tag-vfp-args-illegal.s.tmp.o: unknown Tag_ABI_VFP_args value: 5 + .arch armv7-a + .eabi_attribute 20, 1 + .eabi_attribute 21, 1 + .eabi_attribute 23, 3 + .eabi_attribute 24, 1 + .eabi_attribute 25, 1 + .eabi_attribute 26, 2 + .eabi_attribute 30, 6 + .eabi_attribute 34, 1 + .eabi_attribute 18, 4 + .eabi_attribute 28, 5 // Tag_ABI_VFP_args = 5 (Illegal value) + + .syntax unified + .globl _start + .type _start, %function +_start: bx lr Index: test/ELF/arm-tag-vfp-args.s =================================================================== --- test/ELF/arm-tag-vfp-args.s +++ test/ELF/arm-tag-vfp-args.s @@ -0,0 +1,72 @@ +// REQUIRES:arm +// RUN: llvm-mc -filetype=obj -triple=armv7a-none-linux-gnueabi %S/Inputs/arm-vfp-arg-base.s -o %tbase.o +// RUN: llvm-mc -filetype=obj -triple=armv7a-none-linux-gnueabi %S/Inputs/arm-vfp-arg-vfp.s -o %tvfp.o +// RUN: llvm-mc -filetype=obj -triple=armv7a-none-linux-gnueabi %S/Inputs/arm-vfp-arg-toolchain.s -o %ttoolchain.o +// RUN: llvm-mc -filetype=obj -triple=armv7a-none-linux-gnueabi %S/Inputs/arm-vfp-arg-compat.s -o %tcompat.o +// RUN: llvm-mc -filetype=obj -triple=armv7a-none-linux-gnueabi %s -o %t.o + +// The default for this file is 0 (Base AAPCS) +// RUN: ld.lld %t.o -o %tdefault +// RUN: llvm-readobj -file-headers %tdefault | FileCheck -check-prefix=CHECK-BASE %s + +// Expect explicit Base AAPCS. +// RUN: ld.lld %t.o %tbase.o -o %tbase +// RUN: llvm-readobj -file-headers %tbase | FileCheck -check-prefix=CHECK-BASE %s + +// Expect explicit Base AAPCS when linking Base and Compatible. +// RUN: ld.lld %t.o %tbase.o %tcompat.o -o %tbasecompat +// RUN: llvm-readobj -file-headers %tbasecompat | FileCheck -check-prefix=CHECK-BASE %s + +// CHECK-BASE: Flags [ (0x5000200) +// CHECK-BASE-NEXT: 0x200 +// CHECK-BASE-NEXT: 0x1000000 +// CHECK-BASE-NEXT: 0x4000000 +// CHECK-BASE-NEXT: ] + +// Expect Hard float VFP AAPCS +// RUN: ld.lld %t.o %tvfp.o -o %tvfp +// RUN: llvm-readobj -file-headers %tvfp | FileCheck -check-prefix=CHECK-VFP %s + +// Expect Hard float VFP AAPCS when linking VFP and Compatible +// RUN: ld.lld %t.o %tvfp.o %tcompat.o -o %tvfpcompat +// RUN: llvm-readobj -file-headers %tvfpcompat | FileCheck -check-prefix=CHECK-VFP %s + +// CHECK-VFP: Flags [ (0x5000400) +// CHECK-VFP-NEXT: 0x400 +// CHECK-VFP-NEXT: 0x1000000 +// CHECK-VFP-NEXT: 0x4000000 +// CHECK-VFP-NEXT: ] + +// Expect Toolchain specifc to not use either Base or VFP AAPCS +// RUN: ld.lld %t.o %ttoolchain.o -o %ttoolchain +// RUN: llvm-readobj -file-headers %ttoolchain | FileCheck -check-prefix=CHECK-TOOLCHAIN %s + +// Expect Toolchain and Compatible to have same affect as Toolchain. +// RUN: ld.lld %t.o %ttoolchain.o %tcompat.o -o %ttoolchaincompat +// RUN: llvm-readobj -file-headers %ttoolchaincompat | FileCheck -check-prefix=CHECK-TOOLCHAIN %s + +// CHECK-TOOLCHAIN: Flags [ (0x5000000) +// CHECK-TOOLCHAIN-NEXT: 0x1000000 +// CHECK-TOOLCHAIN-NEXT: 0x4000000 +// CHECK-TOOLCHAIN-NEXT: ] + + .arch armv7-a + .eabi_attribute 20, 1 + .eabi_attribute 21, 1 + .eabi_attribute 23, 3 + .eabi_attribute 24, 1 + .eabi_attribute 25, 1 + .eabi_attribute 26, 2 + .eabi_attribute 30, 6 + .eabi_attribute 34, 1 + .eabi_attribute 18, 4 + // We do not specify Tag_ABI_VFP_args (.eabi_attribute 28) in this file. + // When omitted the value of the tag defaults to 0, however if there + // are other files with explicit Tag_ABI_VFP_args we use that in + // preference. + + + .syntax unified + .globl _start + .type _start, %function +_start: bx lr