[lld] r273532 - Fix a bug that MIPS thunks can overwrite other section contents.
Rui Ueyama via llvm-commits
llvm-commits at lists.llvm.org
Wed Jun 22 21:33:43 PDT 2016
Author: ruiu
Date: Wed Jun 22 23:33:42 2016
New Revision: 273532
URL: http://llvm.org/viewvc/llvm-project?rev=273532&view=rev
Log:
Fix a bug that MIPS thunks can overwrite other section contents.
Peter Smith found while trying to support thunk creation for ARM that
LLD sometimes creates broken thunks for MIPS. The cause of the bug is
that we assign file offsets to input sections too early. We need to
create all sections and then assign section offsets because appending
thunks changes file offsets for all following sections.
This patch separates the pass to assign file offsets from thunk
creation pass. This effectively reverts r265673.
Differential Revision: http://reviews.llvm.org/D21598
Modified:
lld/trunk/ELF/InputSection.cpp
lld/trunk/ELF/InputSection.h
lld/trunk/ELF/OutputSections.cpp
lld/trunk/ELF/OutputSections.h
lld/trunk/ELF/Relocations.cpp
lld/trunk/ELF/Relocations.h
lld/trunk/ELF/Writer.cpp
lld/trunk/test/ELF/mips-npic-call-pic.s
Modified: lld/trunk/ELF/InputSection.cpp
URL: http://llvm.org/viewvc/llvm-project/lld/trunk/ELF/InputSection.cpp?rev=273532&r1=273531&r2=273532&view=diff
==============================================================================
--- lld/trunk/ELF/InputSection.cpp (original)
+++ lld/trunk/ELF/InputSection.cpp Wed Jun 22 23:33:42 2016
@@ -56,7 +56,7 @@ ArrayRef<uint8_t> InputSectionBase<ELFT>
}
template <class ELFT>
-typename ELFT::uint InputSectionBase<ELFT>::getOffset(uintX_t Offset) {
+typename ELFT::uint InputSectionBase<ELFT>::getOffset(uintX_t Offset) const {
switch (SectionKind) {
case Regular:
return cast<InputSection<ELFT>>(this)->OutSecOff + Offset;
@@ -80,7 +80,7 @@ typename ELFT::uint InputSectionBase<ELF
template <class ELFT>
typename ELFT::uint
-InputSectionBase<ELFT>::getOffset(const DefinedRegular<ELFT> &Sym) {
+InputSectionBase<ELFT>::getOffset(const DefinedRegular<ELFT> &Sym) const {
return getOffset(Sym.Value);
}
@@ -297,8 +297,8 @@ void InputSectionBase<ELFT>::relocate(ui
}
const unsigned Bits = sizeof(uintX_t) * 8;
- for (const Relocation &Rel : Relocations) {
- uintX_t Offset = Rel.Offset;
+ for (const Relocation<ELFT> &Rel : Relocations) {
+ uintX_t Offset = Rel.InputSec->getOffset(Rel.Offset);
uint8_t *BufLoc = Buf + Offset;
uint32_t Type = Rel.Type;
uintX_t A = Rel.Addend;
@@ -422,13 +422,13 @@ void EhInputSection<ELFT>::split() {
}
template <class ELFT>
-typename ELFT::uint EhInputSection<ELFT>::getOffset(uintX_t Offset) {
+typename ELFT::uint EhInputSection<ELFT>::getOffset(uintX_t Offset) const {
// The file crtbeginT.o has relocations pointing to the start of an empty
// .eh_frame that is known to be the first in the link. It does that to
// identify the start of the output .eh_frame. Handle this special case.
if (this->getSectionHdr()->sh_size == 0)
return Offset;
- SectionPiece *Piece = this->getSectionPiece(Offset);
+ const SectionPiece *Piece = this->getSectionPiece(Offset);
if (Piece->OutputOff == size_t(-1))
return -1; // Not in the output
@@ -506,6 +506,13 @@ bool MergeInputSection<ELFT>::classof(co
// Do binary search to get a section piece at a given input offset.
template <class ELFT>
SectionPiece *SplitInputSection<ELFT>::getSectionPiece(uintX_t Offset) {
+ auto *This = static_cast<const SplitInputSection<ELFT> *>(this);
+ return const_cast<SectionPiece *>(This->getSectionPiece(Offset));
+}
+
+template <class ELFT>
+const SectionPiece *
+SplitInputSection<ELFT>::getSectionPiece(uintX_t Offset) const {
ArrayRef<uint8_t> D = this->getSectionData();
StringRef Data((const char *)D.data(), D.size());
uintX_t Size = Data.size();
@@ -524,14 +531,14 @@ SectionPiece *SplitInputSection<ELFT>::g
// Because contents of a mergeable section is not contiguous in output,
// it is not just an addition to a base output offset.
template <class ELFT>
-typename ELFT::uint MergeInputSection<ELFT>::getOffset(uintX_t Offset) {
+typename ELFT::uint MergeInputSection<ELFT>::getOffset(uintX_t Offset) const {
auto It = OffsetMap.find(Offset);
if (It != OffsetMap.end())
return It->second;
// If Offset is not at beginning of a section piece, it is not in the map.
// In that case we need to search from the original section piece vector.
- SectionPiece &Piece = *this->getSectionPiece(Offset);
+ const SectionPiece &Piece = *this->getSectionPiece(Offset);
assert(Piece.Live);
uintX_t Addend = Offset - Piece.InputOff;
return Piece.OutputOff + Addend;
Modified: lld/trunk/ELF/InputSection.h
URL: http://llvm.org/viewvc/llvm-project/lld/trunk/ELF/InputSection.h?rev=273532&r1=273531&r2=273532&view=diff
==============================================================================
--- lld/trunk/ELF/InputSection.h (original)
+++ lld/trunk/ELF/InputSection.h Wed Jun 22 23:33:42 2016
@@ -70,16 +70,16 @@ public:
StringRef getSectionName() const;
const Elf_Shdr *getSectionHdr() const { return Header; }
ObjectFile<ELFT> *getFile() const { return File; }
- uintX_t getOffset(const DefinedRegular<ELFT> &Sym);
+ uintX_t getOffset(const DefinedRegular<ELFT> &Sym) const;
// Translate an offset in the input section to an offset in the output
// section.
- uintX_t getOffset(uintX_t Offset);
+ uintX_t getOffset(uintX_t Offset) const;
ArrayRef<uint8_t> getSectionData() const;
void relocate(uint8_t *Buf, uint8_t *BufEnd);
- std::vector<Relocation> Relocations;
+ std::vector<Relocation<ELFT>> Relocations;
};
template <class ELFT> InputSectionBase<ELFT> InputSectionBase<ELFT>::Discarded;
@@ -125,6 +125,7 @@ public:
// Returns the SectionPiece at a given input section offset.
SectionPiece *getSectionPiece(uintX_t Offset);
+ const SectionPiece *getSectionPiece(uintX_t Offset) const;
};
// This corresponds to a SHF_MERGE section of an input file.
@@ -143,7 +144,7 @@ public:
// Translate an offset in the input section to an offset
// in the output section.
- uintX_t getOffset(uintX_t Offset);
+ uintX_t getOffset(uintX_t Offset) const;
void finalizePieces();
@@ -163,7 +164,7 @@ public:
// Translate an offset in the input section to an offset in the output
// section.
- uintX_t getOffset(uintX_t Offset);
+ uintX_t getOffset(uintX_t Offset) const;
// Relocation section that refer to this one.
const Elf_Shdr *RelocSection = nullptr;
Modified: lld/trunk/ELF/OutputSections.cpp
URL: http://llvm.org/viewvc/llvm-project/lld/trunk/ELF/OutputSections.cpp?rev=273532&r1=273531&r2=273532&view=diff
==============================================================================
--- lld/trunk/ELF/OutputSections.cpp (original)
+++ lld/trunk/ELF/OutputSections.cpp Wed Jun 22 23:33:42 2016
@@ -351,13 +351,11 @@ template <class ELFT> void RelocationSec
for (const DynamicReloc<ELFT> &Rel : Relocs) {
auto *P = reinterpret_cast<Elf_Rela *>(Buf);
Buf += Config->Rela ? sizeof(Elf_Rela) : sizeof(Elf_Rel);
- SymbolBody *Sym = Rel.Sym;
if (Config->Rela)
- P->r_addend = Rel.UseSymVA ? Sym->getVA<ELFT>(Rel.Addend) : Rel.Addend;
- P->r_offset = Rel.OffsetInSec + Rel.OffsetSec->getVA();
- uint32_t SymIdx = (!Rel.UseSymVA && Sym) ? Sym->DynsymIndex : 0;
- P->setSymbolAndType(SymIdx, Rel.Type, Config->Mips64EL);
+ P->r_addend = Rel.getAddend();
+ P->r_offset = Rel.getOffset();
+ P->setSymbolAndType(Rel.getSymIndex(), Rel.Type, Config->Mips64EL);
}
if (Sort) {
@@ -836,11 +834,16 @@ static int getPriority(StringRef S) {
return V;
}
-template <class ELFT>
-void OutputSection<ELFT>::forEachInputSection(
- std::function<void(InputSectionBase<ELFT> *)> F) {
- for (InputSection<ELFT> *S : Sections)
- F(S);
+// This function is called after we sort input sections
+// and scan relocations to setup sections' offsets.
+template <class ELFT> void OutputSection<ELFT>::assignOffsets() {
+ uintX_t Off = this->Header.sh_size;
+ for (InputSection<ELFT> *S : Sections) {
+ Off = alignTo(Off, S->Alignment);
+ S->OutSecOff = Off;
+ Off += S->getSize();
+ }
+ this->Header.sh_size = Off;
}
// Sorts input sections by section name suffixes, so that .foo.N comes
@@ -947,13 +950,6 @@ template <class ELFT>
EhOutputSection<ELFT>::EhOutputSection()
: OutputSectionBase<ELFT>(".eh_frame", SHT_PROGBITS, SHF_ALLOC) {}
-template <class ELFT>
-void EhOutputSection<ELFT>::forEachInputSection(
- std::function<void(InputSectionBase<ELFT> *)> F) {
- for (EhInputSection<ELFT> *S : Sections)
- F(S);
-}
-
// Returns the first relocation that points to a region
// between Begin and Begin+Size.
template <class IntTy, class RelTy>
@@ -1269,6 +1265,26 @@ template <class ELFT> void StringTableSe
}
template <class ELFT>
+typename ELFT::uint DynamicReloc<ELFT>::getOffset() const {
+ if (OutputSec)
+ return OutputSec->getVA() + OffsetInSec;
+ return InputSec->OutSec->getVA() + InputSec->getOffset(OffsetInSec);
+}
+
+template <class ELFT>
+typename ELFT::uint DynamicReloc<ELFT>::getAddend() const {
+ if (UseSymVA)
+ return Sym->getVA<ELFT>(Addend);
+ return Addend;
+}
+
+template <class ELFT> uint32_t DynamicReloc<ELFT>::getSymIndex() const {
+ if (Sym && !UseSymVA)
+ return Sym->DynsymIndex;
+ return 0;
+}
+
+template <class ELFT>
SymbolTableSection<ELFT>::SymbolTableSection(
StringTableSection<ELFT> &StrTabSec)
: OutputSectionBase<ELFT>(StrTabSec.isDynamic() ? ".dynsym" : ".symtab",
Modified: lld/trunk/ELF/OutputSections.h
URL: http://llvm.org/viewvc/llvm-project/lld/trunk/ELF/OutputSections.h?rev=273532&r1=273531&r2=273532&view=diff
==============================================================================
--- lld/trunk/ELF/OutputSections.h (original)
+++ lld/trunk/ELF/OutputSections.h Wed Jun 22 23:33:42 2016
@@ -96,8 +96,7 @@ public:
virtual void finalize() {}
virtual void finalizePieces() {}
- virtual void
- forEachInputSection(std::function<void(InputSectionBase<ELFT> *)> F) {}
+ virtual void assignOffsets() {}
virtual void writeTo(uint8_t *Buf) {}
virtual ~OutputSectionBase() = default;
@@ -197,21 +196,35 @@ private:
std::vector<std::pair<const SymbolBody *, unsigned>> Entries;
};
-template <class ELFT> struct DynamicReloc {
+template <class ELFT> class DynamicReloc {
typedef typename ELFT::uint uintX_t;
+
+public:
+ DynamicReloc(uint32_t Type, const InputSectionBase<ELFT> *InputSec,
+ uintX_t OffsetInSec, bool UseSymVA, SymbolBody *Sym,
+ uintX_t Addend)
+ : Type(Type), Sym(Sym), InputSec(InputSec), OffsetInSec(OffsetInSec),
+ UseSymVA(UseSymVA), Addend(Addend) {}
+
+ DynamicReloc(uint32_t Type, const OutputSectionBase<ELFT> *OutputSec,
+ uintX_t OffsetInSec, bool UseSymVA, SymbolBody *Sym,
+ uintX_t Addend)
+ : Type(Type), Sym(Sym), OutputSec(OutputSec), OffsetInSec(OffsetInSec),
+ UseSymVA(UseSymVA), Addend(Addend) {}
+
+ uintX_t getOffset() const;
+ uintX_t getAddend() const;
+ uint32_t getSymIndex() const;
+
uint32_t Type;
+private:
SymbolBody *Sym;
- const OutputSectionBase<ELFT> *OffsetSec;
+ const InputSectionBase<ELFT> *InputSec = nullptr;
+ const OutputSectionBase<ELFT> *OutputSec = nullptr;
uintX_t OffsetInSec;
bool UseSymVA;
uintX_t Addend;
-
- DynamicReloc(uint32_t Type, const OutputSectionBase<ELFT> *OffsetSec,
- uintX_t OffsetInSec, bool UseSymVA, SymbolBody *Sym,
- uintX_t Addend)
- : Type(Type), Sym(Sym), OffsetSec(OffsetSec), OffsetInSec(OffsetInSec),
- UseSymVA(UseSymVA), Addend(Addend) {}
};
template <class ELFT>
@@ -343,8 +356,7 @@ public:
void sortCtorsDtors();
void writeTo(uint8_t *Buf) override;
void finalize() override;
- void
- forEachInputSection(std::function<void(InputSectionBase<ELFT> *)> F) override;
+ void assignOffsets() override;
std::vector<InputSection<ELFT> *> Sections;
};
@@ -385,8 +397,6 @@ public:
void writeTo(uint8_t *Buf) override;
void finalize() override;
bool empty() const { return Sections.empty(); }
- void
- forEachInputSection(std::function<void(InputSectionBase<ELFT> *)> F) override;
void addSection(InputSectionBase<ELFT> *S) override;
Modified: lld/trunk/ELF/Relocations.cpp
URL: http://llvm.org/viewvc/llvm-project/lld/trunk/ELF/Relocations.cpp?rev=273532&r1=273531&r2=273532&view=diff
==============================================================================
--- lld/trunk/ELF/Relocations.cpp (original)
+++ lld/trunk/ELF/Relocations.cpp Wed Jun 22 23:33:42 2016
@@ -103,7 +103,7 @@ static unsigned handleTlsRelocation(uint
{Target->TlsDescRel, Out<ELFT>::Got, Off, false, &Body, 0});
}
if (Expr != R_HINT)
- C.Relocations.push_back({Expr, Type, Offset, Addend, &Body});
+ C.Relocations.push_back({Expr, Type, &C, Offset, Addend, &Body});
return 1;
}
@@ -111,21 +111,21 @@ static unsigned handleTlsRelocation(uint
// Local-Dynamic relocs can be relaxed to Local-Exec.
if (!Config->Shared) {
C.Relocations.push_back(
- {R_RELAX_TLS_LD_TO_LE, Type, Offset, Addend, &Body});
+ {R_RELAX_TLS_LD_TO_LE, Type, &C, Offset, Addend, &Body});
return 2;
}
if (Out<ELFT>::Got->addTlsIndex())
Out<ELFT>::RelaDyn->addReloc({Target->TlsModuleIndexRel, Out<ELFT>::Got,
Out<ELFT>::Got->getTlsIndexOff(), false,
nullptr, 0});
- C.Relocations.push_back({Expr, Type, Offset, Addend, &Body});
+ C.Relocations.push_back({Expr, Type, &C, Offset, Addend, &Body});
return 1;
}
// Local-Dynamic relocs can be relaxed to Local-Exec.
if (Target->isTlsLocalDynamicRel(Type) && !Config->Shared) {
C.Relocations.push_back(
- {R_RELAX_TLS_LD_TO_LE, Type, Offset, Addend, &Body});
+ {R_RELAX_TLS_LD_TO_LE, Type, &C, Offset, Addend, &Body});
return 1;
}
@@ -144,7 +144,7 @@ static unsigned handleTlsRelocation(uint
Off + (uintX_t)sizeof(uintX_t), false,
&Body, 0});
}
- C.Relocations.push_back({Expr, Type, Offset, Addend, &Body});
+ C.Relocations.push_back({Expr, Type, &C, Offset, Addend, &Body});
return 1;
}
@@ -153,7 +153,7 @@ static unsigned handleTlsRelocation(uint
if (isPreemptible(Body, Type)) {
C.Relocations.push_back(
{Target->adjustRelaxExpr(Type, nullptr, R_RELAX_TLS_GD_TO_IE), Type,
- Offset, Addend, &Body});
+ &C, Offset, Addend, &Body});
if (!Body.isInGot()) {
Out<ELFT>::Got->addEntry(Body);
Out<ELFT>::RelaDyn->addReloc({Target->TlsGotRel, Out<ELFT>::Got,
@@ -163,7 +163,7 @@ static unsigned handleTlsRelocation(uint
return Target->TlsGdRelaxSkip;
}
C.Relocations.push_back(
- {Target->adjustRelaxExpr(Type, nullptr, R_RELAX_TLS_GD_TO_LE), Type,
+ {Target->adjustRelaxExpr(Type, nullptr, R_RELAX_TLS_GD_TO_LE), Type, &C,
Offset, Addend, &Body});
return Target->TlsGdRelaxSkip;
}
@@ -173,7 +173,7 @@ static unsigned handleTlsRelocation(uint
if (Target->isTlsInitialExecRel(Type) && !Config->Shared &&
!isPreemptible(Body, Type)) {
C.Relocations.push_back(
- {R_RELAX_TLS_IE_TO_LE, Type, Offset, Addend, &Body});
+ {R_RELAX_TLS_IE_TO_LE, Type, &C, Offset, Addend, &Body});
return 1;
}
return 0;
@@ -497,8 +497,9 @@ static void scanRelocs(InputSectionBase<
if (HasError)
continue;
- uintX_t Offset = C.getOffset(RI.r_offset);
- if (Offset == (uintX_t)-1)
+ // Skip a relocation that points to a dead piece
+ // in a mergeable section.
+ if (C.getOffset(RI.r_offset) == (uintX_t)-1)
continue;
// This relocation does not require got entry, but it is relative to got and
@@ -508,8 +509,8 @@ static void scanRelocs(InputSectionBase<
uintX_t Addend = computeAddend(File, Buf, E, RI, Expr, Body);
- if (unsigned Processed =
- handleTlsRelocation<ELFT>(Type, Body, C, Offset, Addend, Expr)) {
+ if (unsigned Processed = handleTlsRelocation<ELFT>(
+ Type, Body, C, RI.r_offset, Addend, Expr)) {
I += (Processed - 1);
continue;
}
@@ -529,17 +530,17 @@ static void scanRelocs(InputSectionBase<
// relocation. We can process some of it and and just ask the dynamic
// linker to add the load address.
if (!Constant)
- AddDyn({Target->RelativeRel, C.OutSec, Offset, true, &Body, Addend});
+ AddDyn({Target->RelativeRel, &C, RI.r_offset, true, &Body, Addend});
// If the produced value is a constant, we just remember to write it
// when outputting this section. We also have to do it if the format
// uses Elf_Rel, since in that case the written value is the addend.
if (Constant || !RelTy::IsRela)
- C.Relocations.push_back({Expr, Type, Offset, Addend, &Body});
+ C.Relocations.push_back({Expr, Type, &C, RI.r_offset, Addend, &Body});
} else {
// We don't know anything about the finaly symbol. Just ask the dynamic
// linker to handle the relocation for us.
- AddDyn({Target->getDynRel(Type), C.OutSec, Offset, false, &Body, Addend});
+ AddDyn({Target->getDynRel(Type), &C, RI.r_offset, false, &Body, Addend});
// MIPS ABI turns using of GOT and dynamic relocations inside out.
// While regular ABI uses dynamic relocations to fill up GOT entries
// MIPS ABI requires dynamic linker to fills up GOT entries using
Modified: lld/trunk/ELF/Relocations.h
URL: http://llvm.org/viewvc/llvm-project/lld/trunk/ELF/Relocations.h?rev=273532&r1=273531&r2=273532&view=diff
==============================================================================
--- lld/trunk/ELF/Relocations.h (original)
+++ lld/trunk/ELF/Relocations.h Wed Jun 22 23:33:42 2016
@@ -60,9 +60,10 @@ enum RelExpr {
R_TLSLD_PC
};
-struct Relocation {
+template <class ELFT> struct Relocation {
RelExpr Expr;
uint32_t Type;
+ InputSectionBase<ELFT> *InputSec;
uint64_t Offset;
uint64_t Addend;
SymbolBody *Sym;
Modified: lld/trunk/ELF/Writer.cpp
URL: http://llvm.org/viewvc/llvm-project/lld/trunk/ELF/Writer.cpp?rev=273532&r1=273531&r2=273532&view=diff
==============================================================================
--- lld/trunk/ELF/Writer.cpp (original)
+++ lld/trunk/ELF/Writer.cpp Wed Jun 22 23:33:42 2016
@@ -793,24 +793,24 @@ template <class ELFT> void Writer<ELFT>:
// Scan relocations. This must be done after every symbol is declared so that
// we can correctly decide if a dynamic relocation is needed.
- for (OutputSectionBase<ELFT> *Sec : OutputSections) {
- Sec->forEachInputSection([&](InputSectionBase<ELFT> *S) {
- if (auto *IS = dyn_cast<InputSection<ELFT>>(S)) {
- // Set OutSecOff so that scanRelocations can use it.
- uintX_t Off = alignTo(Sec->getSize(), S->Alignment);
- IS->OutSecOff = Off;
-
- scanRelocations(*IS);
-
- // Now that scan relocs possibly changed the size, update the offset.
- Sec->setSize(Off + S->getSize());
- } else if (auto *EH = dyn_cast<EhInputSection<ELFT>>(S)) {
- if (EH->RelocSection)
- scanRelocations(*EH, *EH->RelocSection);
+ for (const std::unique_ptr<elf::ObjectFile<ELFT>> &F :
+ Symtab.getObjectFiles()) {
+ for (InputSectionBase<ELFT> *C : F->getSections()) {
+ if (isDiscarded(C))
+ continue;
+ if (auto *S = dyn_cast<InputSection<ELFT>>(C)) {
+ scanRelocations(*S);
+ continue;
}
- });
+ if (auto *S = dyn_cast<EhInputSection<ELFT>>(C))
+ if (S->RelocSection)
+ scanRelocations(*S, *S->RelocSection);
+ }
}
+ for (OutputSectionBase<ELFT> *Sec : OutputSections)
+ Sec->assignOffsets();
+
// Now that we have defined all possible symbols including linker-
// synthesized ones. Visit all symbols to give the finishing touches.
std::vector<DefinedCommon *> CommonSymbols;
Modified: lld/trunk/test/ELF/mips-npic-call-pic.s
URL: http://llvm.org/viewvc/llvm-project/lld/trunk/test/ELF/mips-npic-call-pic.s?rev=273532&r1=273531&r2=273532&view=diff
==============================================================================
--- lld/trunk/test/ELF/mips-npic-call-pic.s (original)
+++ lld/trunk/test/ELF/mips-npic-call-pic.s Wed Jun 22 23:33:42 2016
@@ -1,3 +1,4 @@
+# REQUIRES: mips
# Check LA25 stubs creation. This stub code is necessary when
# non-PIC code calls PIC function.
@@ -7,8 +8,6 @@
# RUN: ld.lld %t-npic.o %t-pic.o %p/Inputs/mips-sto-pic.o -o %t.exe
# RUN: llvm-objdump -d %t.exe | FileCheck %s
-# REQUIRES: mips
-
# CHECK: Disassembly of section .text:
# CHECK-NEXT: __start:
# CHECK-NEXT: 20000: 0c 00 80 0e jal 131128 <foo1b+0x4>
@@ -72,6 +71,68 @@
# CHECK-NEXT: 200a4: 08 00 80 20 j 131200 <fpic>
# CHECK-NEXT: 200a8: 27 39 00 80 addiu $25, $25, 128
+# Make sure tha thunks are created properly no matter how
+# objects are laid out.
+#
+# RUN: ld.lld %t-pic.o %t-npic.o %p/Inputs/mips-sto-pic.o -o %t.exe
+# RUN: llvm-objdump -d %t.exe | FileCheck -check-prefix=REVERSE %s
+
+# REVERSE: foo1a:
+# REVERSE-NEXT: 20000: 00 00 00 00 nop
+#
+# REVERSE: foo1b:
+# REVERSE-NEXT: 20004: 00 00 00 00 nop
+# REVERSE-NEXT: 20008: 3c 19 00 02 lui $25, 2
+# REVERSE-NEXT: 2000c: 08 00 80 00 j 131072 <foo1a>
+# REVERSE-NEXT: 20010: 27 39 00 00 addiu $25, $25, 0
+# REVERSE-NEXT: 20014: 00 00 00 00 nop
+# REVERSE-NEXT: 20018: 3c 19 00 02 lui $25, 2
+# REVERSE-NEXT: 2001c: 08 00 80 01 j 131076 <foo1b>
+# REVERSE-NEXT: 20020: 27 39 00 04 addiu $25, $25, 4
+# REVERSE-NEXT: 20024: 00 00 00 00 nop
+# REVERSE-NEXT: 20028: 00 00 00 00 nop
+# REVERSE-NEXT: 2002c: 00 00 00 00 nop
+#
+# REVERSE: foo2:
+# REVERSE-NEXT: 20030: 00 00 00 00 nop
+# REVERSE-NEXT: 20034: 3c 19 00 02 lui $25, 2
+# REVERSE-NEXT: 20038: 08 00 80 0c j 131120 <foo2>
+# REVERSE-NEXT: 2003c: 27 39 00 30 addiu $25, $25, 48
+# REVERSE-NEXT: 20040: 00 00 00 00 nop
+# REVERSE-NEXT: 20044: 00 00 00 00 nop
+# REVERSE-NEXT: 20048: 00 00 00 00 nop
+# REVERSE-NEXT: 2004c: 00 00 00 00 nop
+#
+# REVERSE: __start:
+# REVERSE-NEXT: 20050: 0c 00 80 02 jal 131080 <foo1b+0x4>
+# REVERSE-NEXT: 20054: 00 00 00 00 nop
+# REVERSE-NEXT: 20058: 0c 00 80 0d jal 131124 <foo2+0x4>
+# REVERSE-NEXT: 2005c: 00 00 00 00 nop
+# REVERSE-NEXT: 20060: 0c 00 80 06 jal 131096 <foo1b+0x14>
+# REVERSE-NEXT: 20064: 00 00 00 00 nop
+# REVERSE-NEXT: 20068: 0c 00 80 0d jal 131124 <foo2+0x4>
+# REVERSE-NEXT: 2006c: 00 00 00 00 nop
+# REVERSE-NEXT: 20070: 0c 00 80 28 jal 131232 <fnpic+0x10>
+# REVERSE-NEXT: 20074: 00 00 00 00 nop
+# REVERSE-NEXT: 20078: 0c 00 80 24 jal 131216 <fnpic>
+# REVERSE-NEXT: 2007c: 00 00 00 00 nop
+#
+# REVERSE: fpic:
+# REVERSE-NEXT: 20080: 00 00 00 00 nop
+# REVERSE-NEXT: 20084: 00 00 00 00 nop
+# REVERSE-NEXT: 20088: 00 00 00 00 nop
+# REVERSE-NEXT: 2008c: 00 00 00 00 nop
+#
+# REVERSE: fnpic:
+# REVERSE-NEXT: 20090: 00 00 00 00 nop
+# REVERSE-NEXT: 20094: 00 00 00 00 nop
+# REVERSE-NEXT: 20098: 00 00 00 00 nop
+# REVERSE-NEXT: 2009c: 00 00 00 00 nop
+# REVERSE-NEXT: 200a0: 3c 19 00 02 lui $25, 2
+# REVERSE-NEXT: 200a4: 08 00 80 20 j 131200 <fpic>
+# REVERSE-NEXT: 200a8: 27 39 00 80 addiu $25, $25, 128
+# REVERSE-NEXT: 200ac: 00 00 00 00 nop
+
.text
.globl __start
__start:
More information about the llvm-commits
mailing list