Leslie Zhai via llvm-dev
2017-Sep-14 06:16 UTC
[llvm-dev] Do I need to modify the AddrLoc of LLD for ARC target?
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/
Leslie Zhai via llvm-dev
2017-Sep-14 08:20 UTC
[llvm-dev] Do I need to modify the AddrLoc of LLD for ARC target?
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/