[llvm-dev] Do I need to modify the AddrLoc of LLD for ARC target?
Leslie Zhai via llvm-dev
llvm-dev at lists.llvm.org
Thu Sep 14 01:20:20 PDT 2017
The *debug* patch to verify the AddrLoc of LLD for ARC target:
Index: ELF/Arch/ARC.cpp
===================================================================
--- ELF/Arch/ARC.cpp (nonexistent)
+++ ELF/Arch/ARC.cpp (working copy)
@@ -0,0 +1,109 @@
+//===- ARC.cpp
------------------------------------------------------------===//
+//
+// The LLVM Linker
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+//
+// Note that the current ARC support is very preliminary so you can't
+// link any useful program yet, though.
+//
+//===----------------------------------------------------------------------===//
+
+#include "Error.h"
+#include "InputFiles.h"
+#include "Symbols.h"
+#include "Target.h"
+#include "llvm/Object/ELF.h"
+#include "llvm/Support/Endian.h"
+
+using namespace llvm;
+using namespace llvm::object;
+using namespace llvm::support::endian;
+using namespace llvm::ELF;
+using namespace lld;
+using namespace lld::elf;
+
+namespace {
+uint32_t middleEndianConvert(uint32_t Insn) {
+ return ((Insn & 0xffff0000) >> 16) | ((Insn & 0xffff) << 16);
+}
+
+uint32_t replaceDisp25w(uint32_t Insn, int Val) {
+ Insn = Insn & ~0x7fcffcf;
+ Insn |= ((Val >> 0) & 0x01ff) << 18;
+ Insn |= ((Val >> 9) & 0x03ff) << 6;
+ Insn |= ((Val >> 19) & 0x000f) << 0;
+ return Insn;
+}
+
+uint32_t replaceWord32(uint32_t Insn, int Val) {
+ Insn = Insn & ~0xffffffff;
+ Insn |= ((Val >> 0) & 0xffffffff) << 0;
+ return Insn;
+}
+
+class ARC final : public TargetInfo {
+public:
+ RelExpr getRelExpr(uint32_t Type, const SymbolBody &S, const
InputFile &File,
+ const uint8_t *Loc) const override;
+ void relocateOne(uint8_t *Loc, uint32_t Type, uint64_t Val) const
override;
+};
+} // namespace
+
+RelExpr ARC::getRelExpr(uint32_t Type, const SymbolBody &S,
+ const InputFile &File, const uint8_t *Loc) const {
+ switch (Type) {
+ case R_ARC_S25W_PCREL:
+ case R_ARC_S25H_PCREL:
+ case R_ARC_S21W_PCREL:
+ case R_ARC_PC32:
+ return R_PC;
+ case R_ARC_32_ME:
+ case R_ARC_SDA16_LD2:
+ case R_ARC_SDA_LDST2:
+ case R_ARC_32:
+ case R_ARC_SDA32_ME:
+ return R_ABS;
+ default:
+ error(toString(&File) + ": unknown relocation type: " +
toString(Type));
+ return R_HINT;
+ }
+}
+
+void ARC::relocateOne(uint8_t *Loc, uint32_t Type, uint64_t Val) const {
+ int Rel = Val;
+ uint32_t Insn = read32le(Loc);
+ switch (Type) {
+ case R_ARC_S25W_PCREL:
+ Rel >>= 2;
+ Insn = middleEndianConvert(Insn);
+ Insn = replaceDisp25w(Insn, Rel);
+ Insn = middleEndianConvert(Insn);
+ errs() << "DEBUG: lld: R_ARC_S25W_PCREL: Insn: " << Insn << "\n";
+ write32le(Loc, Insn);
+ break;
+ case R_ARC_32_ME:
+ case R_ARC_SDA16_LD2:
+ case R_ARC_SDA_LDST2:
+ case R_ARC_32:
+ Insn = replaceWord32(Insn, Rel);
+ errs() << "DEBUG: lld: R_ARC_32: Insn: " << Insn << "\n";
+ write32le(Loc, Insn);
+ break;
+ case R_ARC_S25H_PCREL:
+ case R_ARC_SDA32_ME:
+ case R_ARC_S21W_PCREL:
+ case R_ARC_PC32:
+ break;
+ default:
+ error(getErrorLocation(Loc) + "unrecognized reloc " + toString(Type));
+ }
+}
+
+TargetInfo *elf::getARCTargetInfo() {
+ static ARC Target;
+ return &Target;
+}
Index: ELF/CMakeLists.txt
===================================================================
--- ELF/CMakeLists.txt (revision 313230)
+++ ELF/CMakeLists.txt (working copy)
@@ -9,6 +9,7 @@
add_lld_library(lldELF
Arch/AArch64.cpp
Arch/AMDGPU.cpp
+ Arch/ARC.cpp
Arch/ARM.cpp
Arch/AVR.cpp
Arch/Mips.cpp
Index: ELF/InputFiles.cpp
===================================================================
--- ELF/InputFiles.cpp (revision 313230)
+++ ELF/InputFiles.cpp (working copy)
@@ -796,6 +796,8 @@
switch (T.getArch()) {
case Triple::aarch64:
return EM_AARCH64;
+ case Triple::arc:
+ return EM_ARC_COMPACT;
case Triple::arm:
case Triple::thumb:
return EM_ARM;
Index: ELF/InputSection.cpp
===================================================================
--- ELF/InputSection.cpp (revision 313230)
+++ ELF/InputSection.cpp (working copy)
@@ -677,6 +677,8 @@
if (!Sym.isTls() || Out::TlsPhdr)
SymVA = SignExtend64<sizeof(typename ELFT::uint) * 8>(
getRelocTargetVA(Type, Addend, AddrLoc, Sym, R_ABS));
+ errs() << "DEBUG: lld: " << toString(Type) << " SymVA: " << SymVA
<< " A: "
+ << Addend << " P: " << AddrLoc << "\n";
Target->relocateOne(BufLoc, Type, SymVA);
}
}
@@ -716,6 +718,17 @@
uint64_t AddrLoc = getOutputSection()->Addr + Offset;
RelExpr Expr = Rel.Expr;
+ if ((Expr == R_PC || Expr == R_GOT_PC) &&
+ (Config->EMachine == EM_ARC_COMPACT ||
+ Config->EMachine == EM_ARC_COMPACT2)) {
+ uint64_t M = 0;
+ if (Type == R_ARC_32_PCREL || Type == R_ARC_PC32 ||
+ Type == R_ARC_GOTPC32 || Type == R_ARC_GOTPC)
+ M = 4; // bitsize >= 32 ? 4 : 0
+ AddrLoc = (getOutputSection()->Addr /* output_section->vma */ +
+ cast<InputSection>(this)->OutSecOff /* output_offset */ +
+ Offset /* reloc_offset */ - M) & ~0x3;
+ }
uint64_t TargetVA = SignExtend64(
getRelocTargetVA(Type, Rel.Addend, AddrLoc, *Rel.Sym, Expr),
Bits);
@@ -746,6 +759,11 @@
write32be(BufLoc + 4, 0xe8410028); // ld %r2, 40(%r1)
LLVM_FALLTHROUGH;
default:
+ errs() << "DEBUG: lld: " << toString(Type) << " TargetVA: " <<
TargetVA
+ << " A: " << Rel.Addend << " P: " << AddrLoc << " VMA: "
+ << getOutputSection()->Addr << " Output Offset: "
+ << cast<InputSection>(this)->OutSecOff << " Reloc Offset: "
+ << Offset << "\n";
Target->relocateOne(BufLoc, Type, TargetVA);
break;
}
Index: ELF/Target.cpp
===================================================================
--- ELF/Target.cpp (revision 313230)
+++ ELF/Target.cpp (working copy)
@@ -56,6 +56,9 @@
return getAArch64TargetInfo();
case EM_AMDGPU:
return getAMDGPUTargetInfo();
+ case EM_ARC_COMPACT:
+ case EM_ARC_COMPACT2:
+ return getARCTargetInfo();
case EM_ARM:
return getARMTargetInfo();
case EM_AVR:
Index: ELF/Target.h
===================================================================
--- ELF/Target.h (revision 313230)
+++ ELF/Target.h (working copy)
@@ -112,6 +112,7 @@
TargetInfo *getAArch64TargetInfo();
TargetInfo *getAMDGPUTargetInfo();
+TargetInfo *getARCTargetInfo();
TargetInfo *getARMTargetInfo();
TargetInfo *getAVRTargetInfo();
TargetInfo *getPPC64TargetInfo();
Index: test/lit.cfg
===================================================================
--- test/lit.cfg (revision 313230)
+++ test/lit.cfg (working copy)
@@ -247,6 +247,8 @@
config.available_features.add('aarch64')
if re.search(r'AMDGPU', archs):
config.available_features.add('amdgpu')
+if re.search(r'ARC', archs):
+ config.available_features.add('arc')
if re.search(r'ARM', archs):
config.available_features.add('arm')
if re.search(r'AVR', archs):
Index: test/ELF/basic-arc.s
===================================================================
--- test/ELF/basic-arc.s (nonexistent)
+++ test/ELF/basic-arc.s (working copy)
@@ -0,0 +1,10 @@
+# REQUIRES: arc
+# RUN: llvm-mc -filetype=obj -triple=arc-unknown-linux -mcpu=arc600 %s
-o %t.o
+# RUN: ld.lld %t.o -o %t.exe -Ttext=0
+# RUN: llvm-objdump -d %t.exe | FileCheck %s
+
+main:
+ bl memset
+
+# CHECK: main:
+# CHECK-NEXT: 0: 08 06 00 00 <unknown>
I modified the AddrLoc in InputSectionBase::relocateAlloc based on the
ARC ld's P
https://github.com/foss-for-synopsys-dwc-arc-processors/binutils-gdb/blob/arc-2017.09/bfd/elf32-arc.c#L1178
DEBUG: arc-ld: R_ARC_S25W_PCREL relocation: 2 S: 12 A: 0 P: 4 = (vma: 6
+ output_offset: 0 + reloc_offset: 0 - 0) & ~0x3
DEBUG: arc-ld: type: R_ARC_S25W_PCREL insn: 2058
DEBUG: lld: R_ARC_S25W_PCREL TargetVA: 4 A: 0 P: 8 VMA: 8 Output Offset:
0 Reloc Offset: 0
DEBUG: lld: R_ARC_S25W_PCREL: Insn: 2054
What is the equivalent of *vma* in LLD? please give me some hints,
thanks a lot!
在 2017年09月14日 14:16, Leslie Zhai 写道:
> Hi LLVM developers,
>
> basic-arc.s:
>
> main:
> bl memset
>
> $ arc-elf32-gcc -mcpu=arc600 -o basic-arc.o -c
>
> $ arc-elf32-readelf -r basic-arc.o
>
> Relocation section '.rela.text' at offset 0xd4 contains 1 entries:
> Offset Info Type Sym.Value Sym. Name + Addend
> 00000000 00000611 R_ARC_S25W_PCREL 00000000 memset + 0
>
> High address: 0x0
>
> $ arc-elf32-ld -o basic-arc basic-arc.o
> -L/opt/arc-gnu/lib/gcc/arc-elf32/7.1.1/arc600
> -L/opt/arc-gnu/lib/gcc/arc-elf32/7.1.1/../../../../arc-elf32/lib/arc600
> -L/opt/arc-gnu/lib/gcc/arc-elf32/7.1.1
> -L/opt/arc-gnu/lib/gcc/arc-elf32/7.1.1/../../../../arc-elf32/lib
> --start-group -lgcc -lc -lnosys --end-group -Ttext=0
>
> DEBUG: arc-ld: R_ARC_S25W_PCREL relocation: 1 S: 4 A: 0 P: 0 = (vma: 0
> + output_offset: 0 + reloc_offset: 0 - 0) & ~0x3
> DEBUG: arc-ld: type: R_ARC_S25W_PCREL insn: 2054
>
> $ ld.lld -o basic-arc-lld basic-arc.o $ARC_LINKER_LIB -Ttext=0
>
> DEBUG: lld: R_ARC_S25W_PCREL TargetVA: 4 A: 0 P: 0 <-- same P as arc-ld
> DEBUG: lld: R_ARC_S25W_PCREL: Insn: 2050 Rel: 1
> DEBUG: lld: R_ARC_S25W_PCREL: Insn: 2054 <-- same relocation value as
> arc-ld
>
> But with several different high address *not* 0x0, such as 0x6:
>
> DEBUG: arc-ld: R_ARC_S25W_PCREL relocation: 2 S: 12 A: 0 P: 4 = (vma:
> 6 + output_offset: 0 + reloc_offset: 0 - 0) & ~0x3
> DEBUG: arc-ld: type: R_ARC_S25W_PCREL insn: 2058
>
> DEBUG: lld: R_ARC_S25W_PCREL TargetVA: 4 A: 0 P: 8 <-- different P?
> DEBUG: lld: R_ARC_S25W_PCREL: Insn: 2050 Rel: 1
> DEBUG: lld: R_ARC_S25W_PCREL: Insn: 2054 <-- different relocation value
>
> How arc-ld calculates P?
>
> P = ((reloc_data.input_section->output_section ?
> reloc_data.input_section->output_section->vma : 0) +
> reloc_data.input_section->output_offset + (reloc_data.reloc_offset -
> (reloc_data.bitsize >= 32 ? 4 : 0))) & ~0x3;
>
> for example, R_ARC_S25W_PCREL's bitsize < 32, P = (6 + 0 + 0 - 0) &
> ~0x3 = 4, when vma is 6, output and reloc offset is 0.
>
> How LLD calculates P (AddrLoc)?
>
> P = getOutputSection()->Addr + getOffset(Rel.Offset);
>
> for example, the same high address 0x6, LLD's P is 8, different with
> arc-ld? so do I need to modify the value of P for R_PC case in the
> getRelocTargetVA? please give me some hints, thanks a lot!
>
>
> PS: arc-ld R_ARC_S25W_PCREL's FORMULA is: ( S + A ) - P ) >> 2, and it
> needs middle endian convert, so:
>
> Insn = middleEndianConvert (insn, TRUE);
>
> Insn = replaceDisp25w(Insn, ( S + A ) - P ) >> 2);
>
> Insn = middleEndianConvert (insn, TRUE);
>
> write32le(Loc, Insn);
>
--
Regards,
Leslie Zhai - https://reviews.llvm.org/p/xiangzhai/
More information about the llvm-dev
mailing list