From 953a2a3dee46bebd70b129fd62709710f5f2b033 Mon Sep 17 00:00:00 2001 From: Jason W Kim Date: Mon, 7 Feb 2011 01:11:15 +0000 Subject: [PATCH] Teach ARM/MC/ELF about gcc compatible reloc output to get past odd linkage failures with relocations. The code committed is a first cut at compatibility for emitted relocations in ELF .o. Why do this? because existing ARM tools like emitting relocs symbols as explicit relocations, not as section-offset relocs. Result is that with these changes, 1) relocs are now substantially identical what to gcc outputs. 2) larger apps (including many spec2k tests) compile, cross-link, and pass Added reminder fixme to tests for future conversion to .s form. git-svn-id: https://llvm.org/svn/llvm-project/llvm/trunk@124996 91177308-0d34-0410-b5e6-96231b3b80d8 --- lib/MC/ELFObjectWriter.cpp | 48 ++++++++++++++++++++-- test/MC/ARM/elf-reloc-01.ll | 71 ++++++++++++++++++++++++++++++++ test/MC/ARM/elf-reloc-02.ll | 51 +++++++++++++++++++++++ test/MC/ARM/elf-reloc-03.ll | 98 +++++++++++++++++++++++++++++++++++++++++++++ 4 files changed, 265 insertions(+), 3 deletions(-) create mode 100644 test/MC/ARM/elf-reloc-01.ll create mode 100644 test/MC/ARM/elf-reloc-02.ll create mode 100644 test/MC/ARM/elf-reloc-03.ll diff --git a/lib/MC/ELFObjectWriter.cpp b/lib/MC/ELFObjectWriter.cpp index bd5d048f269..0db54b5d48f 100644 --- a/lib/MC/ELFObjectWriter.cpp +++ b/lib/MC/ELFObjectWriter.cpp @@ -30,6 +30,7 @@ #include "llvm/Support/ErrorHandling.h" #include "llvm/Support/ELF.h" #include "llvm/Target/TargetAsmBackend.h" +#include "llvm/ADT/StringSwitch.h" #include "../Target/X86/X86FixupKinds.h" #include "../Target/ARM/ARMFixupKinds.h" @@ -189,6 +190,14 @@ namespace { const MCValue &Target, const MCFragment &F) const; + // For arch-specific emission of explicit reloc symbol + virtual const MCSymbol *ExplicitRelSym(const MCAssembler &Asm, + const MCValue &Target, + const MCFragment &F, + bool IsBSS) const { + return NULL; + } + bool is64Bit() const { return TargetObjectWriter->is64Bit(); } bool hasRelocationAddend() const { return TargetObjectWriter->hasRelocationAddend(); @@ -401,6 +410,11 @@ namespace { virtual void WriteEFlags(); protected: + virtual const MCSymbol *ExplicitRelSym(const MCAssembler &Asm, + const MCValue &Target, + const MCFragment &F, + bool IsBSS) const; + virtual unsigned GetRelocType(const MCValue &Target, const MCFixup &Fixup, bool IsPCRel, bool IsRelocWithSymbol, int64_t Addend); @@ -704,7 +718,7 @@ const MCSymbol *ELFObjectWriter::SymbolToReloc(const MCAssembler &Asm, const SectionKind secKind = Section.getKind(); if (secKind.isBSS()) - return NULL; + return ExplicitRelSym(Asm, Target, F, true); if (secKind.isThreadLocal()) { if (Renamed) @@ -733,7 +747,7 @@ const MCSymbol *ELFObjectWriter::SymbolToReloc(const MCAssembler &Asm, return &Symbol; } - return NULL; + return ExplicitRelSym(Asm, Target, F, false); } @@ -1490,6 +1504,34 @@ void ARMELFObjectWriter::WriteEFlags() { Write32(ELF::EF_ARM_EABIMASK & DefaultEABIVersion); } +// In ARM, _MergedGlobals and other most symbols get emitted directly. +// I.e. not as an offset to a section symbol. +// This code is a first-cut approximation of what ARM/gcc does. + +const MCSymbol *ARMELFObjectWriter::ExplicitRelSym(const MCAssembler &Asm, + const MCValue &Target, + const MCFragment &F, + bool IsBSS) const { + const MCSymbol &Symbol = Target.getSymA()->getSymbol(); + bool EmitThisSym = false; + + if (IsBSS) { + EmitThisSym = StringSwitch(Symbol.getName()) + .Case("_MergedGlobals", true) + .Default(false); + } else { + EmitThisSym = StringSwitch(Symbol.getName()) + .Case("_MergedGlobals", true) + .StartsWith(".L.str", true) + .Default(false); + } + if (EmitThisSym) + return &Symbol; + if (! Symbol.isTemporary()) + return &Symbol; + return NULL; +} + unsigned ARMELFObjectWriter::GetRelocType(const MCValue &Target, const MCFixup &Fixup, bool IsPCRel, @@ -1604,7 +1646,7 @@ unsigned ARMELFObjectWriter::GetRelocType(const MCValue &Target, if (RelocNeedsGOT(Modifier)) NeedsGOT = true; - + return Type; } diff --git a/test/MC/ARM/elf-reloc-01.ll b/test/MC/ARM/elf-reloc-01.ll new file mode 100644 index 00000000000..6b83c95032c --- /dev/null +++ b/test/MC/ARM/elf-reloc-01.ll @@ -0,0 +1,71 @@ +;; RUN: llc -mtriple=armv7-linux-gnueabi -O3 \ +;; RUN: -mcpu=cortex-a8 -mattr=-neon -mattr=+vfp2 -arm-reserve-r9 \ +;; RUN: -filetype=obj %s -o - | \ +;; RUN: elf-dump --dump-section-data | FileCheck -check-prefix=OBJ %s + +;; FIXME: This file needs to be in .s form! +;; The args to llc are there to constrain the codegen only. +;; +;; Ensure no regression on ARM/gcc compatibility for +;; emitting explicit symbol relocs for nonexternal symbols +;; versus section symbol relocs (with offset) - +;; +;; Default llvm behavior is to emit as section symbol relocs nearly +;; everything that is not an undefined external. Unfortunately, this +;; diverges from what codesourcery ARM/gcc does! +;; +;; Tests that reloc to _MergedGlobals show up as explicit symbol reloc + + +target triple = "armv7-none-linux-gnueabi" + +@var_tls = thread_local global i32 1 +@var_tls_double = thread_local global double 1.000000e+00 +@var_static = internal global i32 1 +@var_static_double = internal global double 1.000000e+00 +@var_global = global i32 1 +@var_global_double = global double 1.000000e+00 + +declare i32 @mystrlen(i8* nocapture %s) nounwind + +declare void @myhextochar(i32 %n, i8* nocapture %buffer) + +declare void @__aeabi_read_tp() nounwind + +declare void @__nacl_read_tp() nounwind + +define i32 @main(i32 %argc, i8** nocapture %argv) nounwind { +entry: + switch i32 %argc, label %bb3 [ + i32 555, label %bb + i32 6666, label %bb2 + ] + +bb: ; preds = %entry + volatile store i32 11, i32* @var_tls, align 4 + volatile store double 2.200000e+01, double* @var_tls_double, align 8 + volatile store i32 33, i32* @var_static, align 4 + volatile store double 4.400000e+01, double* @var_static_double, align 8 + volatile store i32 55, i32* @var_global, align 4 + volatile store double 6.600000e+01, double* @var_global_double, align 8 + br label %bb3 + +bb2: ; preds = %entry + ret i32 add (i32 add (i32 add (i32 ptrtoint (i32* @var_tls to i32), i32 add (i32 ptrtoint (i32* @var_static to i32), i32 ptrtoint (i32* @var_global to i32))), i32 ptrtoint (double* @var_tls_double to i32)), i32 add (i32 ptrtoint (double* @var_static_double to i32), i32 ptrtoint (double* @var_global_double to i32))) + +bb3: ; preds = %bb, %entry + tail call void @exit(i32 55) noreturn nounwind + unreachable +} + +declare void @exit(i32) noreturn nounwind + + +;; OBJ: Symbol 0x00000002 +;; OBJ-NEXT: '_MergedGlobals' +;; OBJ-NEXT: 'st_value', 0x00000010 + +;; OBJ: Relocation 0x00000001 +;; OBJ-NEXT: 'r_offset', +;; OBJ-NEXT: 'r_sym', 0x00000002 +;; OBJ-NEXT: 'r_type', 0x0000002b diff --git a/test/MC/ARM/elf-reloc-02.ll b/test/MC/ARM/elf-reloc-02.ll new file mode 100644 index 00000000000..132a47758da --- /dev/null +++ b/test/MC/ARM/elf-reloc-02.ll @@ -0,0 +1,51 @@ +;; RUN: llc -mtriple=armv7-linux-gnueabi -O3 \ +;; RUN: -mcpu=cortex-a8 -mattr=-neon -mattr=+vfp2 -arm-reserve-r9 \ +;; RUN: -filetype=obj %s -o - | \ +;; RUN: elf-dump --dump-section-data | FileCheck -check-prefix=OBJ %s + +;; FIXME: This file needs to be in .s form! +;; The args to llc are there to constrain the codegen only. +;; +;; Ensure no regression on ARM/gcc compatibility for +;; emitting explicit symbol relocs for nonexternal symbols +;; versus section symbol relocs (with offset) - +;; +;; Default llvm behavior is to emit as section symbol relocs nearly +;; everything that is not an undefined external. Unfortunately, this +;; diverges from what codesourcery ARM/gcc does! +;; +;; Tests that reloc to .L.str* show up as explicit symbols + +target triple = "armv7-none-linux-gnueabi" + +@.str = private constant [7 x i8] c"@null\0A\00", align 4 +@.str1 = private constant [8 x i8] c"@write\0A\00", align 4 +@.str2 = private constant [13 x i8] c"hello worldn\00", align 4 +@.str3 = private constant [7 x i8] c"@exit\0A\00", align 4 + +declare i32 @mystrlen(i8* nocapture %s) nounwind readonly + +declare void @myhextochar(i32 %n, i8* nocapture %buffer) nounwind + +define i32 @main() nounwind { +entry: + %0 = tail call i32 (...)* @write(i32 1, i8* getelementptr inbounds ([7 x i8]* @.str, i32 0, i32 0), i32 6) nounwind + %1 = tail call i32 (...)* @write(i32 1, i8* getelementptr inbounds ([8 x i8]* @.str1, i32 0, i32 0), i32 7) nounwind + %2 = tail call i32 (...)* @write(i32 1, i8* getelementptr inbounds ([13 x i8]* @.str2, i32 0, i32 0), i32 12) nounwind + %3 = tail call i32 (...)* @write(i32 1, i8* getelementptr inbounds ([7 x i8]* @.str3, i32 0, i32 0), i32 6) nounwind + tail call void @exit(i32 55) noreturn nounwind + unreachable +} + +declare i32 @write(...) + +declare void @exit(i32) noreturn nounwind + + +;; OBJ: Symbol 0x00000002 +;; OBJ-NEXT: '.L.str' + +;; OBJ: Relocation 0x00000000 +;; OBJ-NEXT: 'r_offset', +;; OBJ-NEXT: 'r_sym', 0x00000002 +;; OBJ-NEXT: 'r_type', 0x0000002b diff --git a/test/MC/ARM/elf-reloc-03.ll b/test/MC/ARM/elf-reloc-03.ll new file mode 100644 index 00000000000..e052f39a615 --- /dev/null +++ b/test/MC/ARM/elf-reloc-03.ll @@ -0,0 +1,98 @@ +;; RUN: llc -mtriple=armv7-linux-gnueabi -O3 \ +;; RUN: -mcpu=cortex-a8 -mattr=-neon -mattr=+vfp2 -arm-reserve-r9 \ +;; RUN: -filetype=obj %s -o - | \ +;; RUN: elf-dump --dump-section-data | FileCheck -check-prefix=OBJ %s + +;; FIXME: This file needs to be in .s form! +;; The args to llc are there to constrain the codegen only. +;; +;; Ensure no regression on ARM/gcc compatibility for +;; emitting explicit symbol relocs for nonexternal symbols +;; versus section symbol relocs (with offset) - +;; +;; Default llvm behavior is to emit as section symbol relocs nearly +;; everything that is not an undefined external. Unfortunately, this +;; diverges from what codesourcery ARM/gcc does! +;; +;; Verifies that internal constants appear as explict symbol relocs + + +target triple = "armv7-none-linux-gnueabi" + +@startval = global i32 5 +@vtable = internal constant [10 x i32 (...)*] [i32 (...)* bitcast (i32 ()* @foo0 to i32 (...)*), i32 (...)* bitcast (i32 ()* @foo1 to i32 (...)*), i32 (...)* bitcast (i32 ()* @foo2 to i32 (...)*), i32 (...)* bitcast (i32 ()* @foo3 to i32 (...)*), i32 (...)* bitcast (i32 ()* @foo4 to i32 (...)*), i32 (...)* bitcast (i32 ()* @foo5 to i32 (...)*), i32 (...)* bitcast (i32 ()* @foo6 to i32 (...)*), i32 (...)* bitcast (i32 ()* @foo7 to i32 (...)*), i32 (...)* bitcast (i32 ()* @foo8 to i32 (...)*), i32 (...)* bitcast (i32 ()* @foo9 to i32 (...)*)] + +declare i32 @mystrlen(i8* nocapture %s) nounwind readonly + +declare void @myhextochar(i32 %n, i8* nocapture %buffer) nounwind + +define internal i32 @foo0() nounwind readnone { +entry: + ret i32 0 +} + +define internal i32 @foo1() nounwind readnone { +entry: + ret i32 1 +} + +define internal i32 @foo2() nounwind readnone { +entry: + ret i32 2 +} + +define internal i32 @foo3() nounwind readnone { +entry: + ret i32 3 +} + +define internal i32 @foo4() nounwind readnone { +entry: + ret i32 4 +} + +define internal i32 @foo5() nounwind readnone { +entry: + ret i32 55 +} + +define internal i32 @foo6() nounwind readnone { +entry: + ret i32 6 +} + +define internal i32 @foo7() nounwind readnone { +entry: + ret i32 7 +} + +define internal i32 @foo8() nounwind readnone { +entry: + ret i32 8 +} + +define internal i32 @foo9() nounwind readnone { +entry: + ret i32 9 +} + +define i32 @main() nounwind { +entry: + %0 = load i32* @startval, align 4 + %1 = getelementptr inbounds [10 x i32 (...)*]* @vtable, i32 0, i32 %0 + %2 = load i32 (...)** %1, align 4 + %3 = tail call i32 (...)* %2() nounwind + tail call void @exit(i32 %3) noreturn nounwind + unreachable +} + +declare void @exit(i32) noreturn nounwind + + +;; OBJ: Symbol 0x0000000c +;; OBJ-NEXT: 'vtable' + +;; OBJ: Relocation 0x00000001 +;; OBJ-NEXT: 'r_offset', +;; OBJ-NEXT: 'r_sym', 0x0000000c +;; OBJ-NEXT: 'r_type', 0x0000002b -- 2.11.0