Replace MergeOutputSection with a synthetic section.

With a synthetic merge section we can have, for example, a single
.rodata section with stings, fixed sized constants and non merge
constants.

I can be simplified further by not setting Entsize, but that is
probably better done is a followup patch.

This should allow some cleanup in the linker script code now that
every output section command maps to just one output section.

llvm-svn: 294005
This commit is contained in:
Rafael Espindola 2017-02-03 13:06:18 +00:00
parent 43b61561b0
commit 9e9754b520
14 changed files with 273 additions and 202 deletions

View File

@ -80,7 +80,8 @@ InputSectionBase<ELFT>::InputSectionBase(elf::ObjectFile<ELFT> *File,
// If it is not a mergeable section, overwrite the flag so that the flag
// is consistent with the class. This inconsistency could occur when
// string merging is disabled using -O0 flag.
if (!Config->Relocatable && !isa<MergeInputSection<ELFT>>(this))
if (!Config->Relocatable && !isa<MergeInputSection<ELFT>>(this) &&
!isa<SyntheticSection<ELFT>>(this))
this->Flags &= ~(SHF_MERGE | SHF_STRINGS);
}
@ -118,11 +119,21 @@ typename ELFT::uint InputSectionBase<ELFT>::getOffset(uintX_t Offset) const {
// identify the start of the output .eh_frame.
return Offset;
case Merge:
return cast<MergeInputSection<ELFT>>(this)->getOffset(Offset);
const MergeInputSection<ELFT> *MS = cast<MergeInputSection<ELFT>>(this);
if (MS->MergeSec)
return MS->MergeSec->OutSecOff + MS->getOffset(Offset);
return MS->getOffset(Offset);
}
llvm_unreachable("invalid section kind");
}
template <class ELFT>
OutputSectionBase *InputSectionBase<ELFT>::getOutputSection() const {
if (auto *MS = dyn_cast<MergeInputSection<ELFT>>(this))
return MS->MergeSec ? MS->MergeSec->OutSec : nullptr;
return OutSec;
}
// Uncompress section contents. Note that this function is called
// from parallel_for_each, so it must be thread-safe.
template <class ELFT> void InputSectionBase<ELFT>::uncompress() {

View File

@ -28,6 +28,7 @@ class SymbolBody;
struct SectionPiece;
template <class ELFT> class DefinedRegular;
template <class ELFT> class MergeSyntheticSection;
template <class ELFT> class ObjectFile;
template <class ELFT> class OutputSection;
class OutputSectionBase;
@ -130,6 +131,8 @@ public:
// Returns the size of this section (even if this is a common or BSS.)
size_t getSize() const;
OutputSectionBase *getOutputSection() const;
ObjectFile<ELFT> *getFile() const { return File; }
llvm::object::ELFFile<ELFT> getObj() const { return File->getObj(); }
uintX_t getOffset(const DefinedRegular<ELFT> &Sym) const;
@ -206,6 +209,11 @@ public:
SectionPiece *getSectionPiece(uintX_t Offset);
const SectionPiece *getSectionPiece(uintX_t Offset) const;
// MergeInputSections are aggregated to a synthetic input sections,
// and then added to an OutputSection. This pointer points to a
// synthetic MergeSyntheticSection which this section belongs to.
MergeSyntheticSection<ELFT> *MergeSec = nullptr;
private:
void splitStrings(ArrayRef<uint8_t> A, size_t Size);
void splitNonStrings(ArrayRef<uint8_t> A, size_t Size);

View File

@ -478,71 +478,6 @@ template <class ELFT> void EhOutputSection<ELFT>::writeTo(uint8_t *Buf) {
}
}
template <class ELFT>
MergeOutputSection<ELFT>::MergeOutputSection(StringRef Name, uint32_t Type,
uintX_t Flags, uintX_t Alignment)
: OutputSectionBase(Name, Type, Flags),
Builder(StringTableBuilder::RAW, Alignment) {}
template <class ELFT> void MergeOutputSection<ELFT>::writeTo(uint8_t *Buf) {
Builder.write(Buf);
}
template <class ELFT>
void MergeOutputSection<ELFT>::addSection(InputSectionData *C) {
auto *Sec = cast<MergeInputSection<ELFT>>(C);
Sec->OutSec = this;
this->updateAlignment(Sec->Alignment);
this->Entsize = Sec->Entsize;
Sections.push_back(Sec);
}
template <class ELFT> bool MergeOutputSection<ELFT>::shouldTailMerge() const {
return (this->Flags & SHF_STRINGS) && Config->Optimize >= 2;
}
template <class ELFT> void MergeOutputSection<ELFT>::finalizeTailMerge() {
// Add all string pieces to the string table builder to create section
// contents.
for (MergeInputSection<ELFT> *Sec : Sections)
for (size_t I = 0, E = Sec->Pieces.size(); I != E; ++I)
if (Sec->Pieces[I].Live)
Builder.add(Sec->getData(I));
// Fix the string table content. After this, the contents will never change.
Builder.finalize();
this->Size = Builder.getSize();
// finalize() fixed tail-optimized strings, so we can now get
// offsets of strings. Get an offset for each string and save it
// to a corresponding StringPiece for easy access.
for (MergeInputSection<ELFT> *Sec : Sections)
for (size_t I = 0, E = Sec->Pieces.size(); I != E; ++I)
if (Sec->Pieces[I].Live)
Sec->Pieces[I].OutputOff = Builder.getOffset(Sec->getData(I));
}
template <class ELFT> void MergeOutputSection<ELFT>::finalizeNoTailMerge() {
// Add all string pieces to the string table builder to create section
// contents. Because we are not tail-optimizing, offsets of strings are
// fixed when they are added to the builder (string table builder contains
// a hash table from strings to offsets).
for (MergeInputSection<ELFT> *Sec : Sections)
for (size_t I = 0, E = Sec->Pieces.size(); I != E; ++I)
if (Sec->Pieces[I].Live)
Sec->Pieces[I].OutputOff = Builder.add(Sec->getData(I));
Builder.finalizeInOrder();
this->Size = Builder.getSize();
}
template <class ELFT> void MergeOutputSection<ELFT>::finalize() {
if (shouldTailMerge())
finalizeTailMerge();
else
finalizeNoTailMerge();
}
template <class ELFT>
static typename ELFT::uint getOutFlags(InputSectionBase<ELFT> *S) {
return S->Flags & ~SHF_GROUP & ~SHF_COMPRESSED;
@ -602,24 +537,15 @@ static SectionKey createKey(InputSectionBase<ELFT> *C, StringRef OutsecName) {
//
// Given the above issues, we instead merge sections by name and error on
// incompatible types and flags.
//
// The exception being SHF_MERGE, where we create different output sections
// for each alignment. This makes each output section simple. In case of
// relocatable object generation we do not try to perform merging and treat
// SHF_MERGE sections as regular ones, but also create different output
// sections for them to allow merging at final linking stage.
//
// Fortunately, creating symbols in the middle of a merge section is not
// supported by bfd or gold, so the SHF_MERGE exception should not cause
// problems with most linker scripts.
typedef typename ELFT::uint uintX_t;
uintX_t Flags = C->Flags & (SHF_MERGE | SHF_STRINGS);
uintX_t Alignment = 0;
if (isa<MergeInputSection<ELFT>>(C) ||
(Config->Relocatable && (C->Flags & SHF_MERGE)))
uintX_t Flags = 0;
if (Config->Relocatable && (C->Flags & SHF_MERGE)) {
Alignment = std::max<uintX_t>(C->Alignment, C->Entsize);
Flags = C->Flags & (SHF_MERGE | SHF_STRINGS);
}
return SectionKey{OutsecName, Flags, Alignment};
}
@ -674,17 +600,11 @@ OutputSectionFactory<ELFT>::create(const SectionKey &Key,
}
uint32_t Type = C->Type;
switch (C->kind()) {
case InputSectionBase<ELFT>::Regular:
case InputSectionBase<ELFT>::Synthetic:
Sec = make<OutputSection<ELFT>>(Key.Name, Type, Flags);
break;
case InputSectionBase<ELFT>::EHFrame:
if (C->kind() == InputSectionBase<ELFT>::EHFrame)
return {Out<ELFT>::EhFrame, false};
case InputSectionBase<ELFT>::Merge:
Sec = make<MergeOutputSection<ELFT>>(Key.Name, Type, Flags, Key.Alignment);
break;
}
Sec = make<OutputSection<ELFT>>(Key.Name, Type, Flags);
if (Flags & SHF_MERGE)
Sec->Entsize = C->Entsize;
return {Sec, true};
}
@ -724,11 +644,6 @@ template class EhOutputSection<ELF32BE>;
template class EhOutputSection<ELF64LE>;
template class EhOutputSection<ELF64BE>;
template class MergeOutputSection<ELF32LE>;
template class MergeOutputSection<ELF32BE>;
template class MergeOutputSection<ELF64LE>;
template class MergeOutputSection<ELF64BE>;
template class OutputSectionFactory<ELF32LE>;
template class OutputSectionFactory<ELF32BE>;
template class OutputSectionFactory<ELF64LE>;

View File

@ -129,30 +129,6 @@ public:
uint8_t *Loc = nullptr;
};
template <class ELFT>
class MergeOutputSection final : public OutputSectionBase {
typedef typename ELFT::uint uintX_t;
public:
MergeOutputSection(StringRef Name, uint32_t Type, uintX_t Flags,
uintX_t Alignment);
void addSection(InputSectionData *S) override;
void writeTo(uint8_t *Buf) override;
void finalize() override;
bool shouldTailMerge() const;
Kind getKind() const override { return Merge; }
static bool classof(const OutputSectionBase *B) {
return B->getKind() == Merge;
}
private:
void finalizeTailMerge();
void finalizeNoTailMerge();
llvm::StringTableBuilder Builder;
std::vector<MergeInputSection<ELFT> *> Sections;
};
struct CieRecord {
EhSectionPiece *Piece = nullptr;
std::vector<EhSectionPiece *> FdePieces;

View File

@ -63,7 +63,8 @@ static typename ELFT::uint getSymVA(const SymbolBody &Body,
Offset += Addend;
Addend = 0;
}
uintX_t VA = (IS->OutSec ? IS->OutSec->Addr : 0) + IS->getOffset(Offset);
const OutputSectionBase *OutSec = IS->getOutputSection();
uintX_t VA = (OutSec ? OutSec->Addr : 0) + IS->getOffset(Offset);
if (D.isTls() && !Config->Relocatable) {
if (!Out<ELFT>::TlsPhdr)
fatal(toString(D.File) +

View File

@ -1152,7 +1152,7 @@ void SymbolTableSection<ELFT>::writeLocalSymbols(uint8_t *&Buf) {
ESym->st_shndx = SHN_ABS;
ESym->st_value = Body.Value;
} else {
const OutputSectionBase *OutSec = Section->OutSec;
const OutputSectionBase *OutSec = Section->getOutputSection();
ESym->st_shndx = OutSec->SectionIndex;
ESym->st_value = OutSec->Addr + Section->getOffset(Body);
}
@ -1218,7 +1218,7 @@ SymbolTableSection<ELFT>::getOutputSection(SymbolBody *Sym) {
case SymbolBody::DefinedRegularKind: {
auto &D = cast<DefinedRegular<ELFT>>(*Sym);
if (D.Section)
return D.Section->OutSec;
return D.Section->getOutputSection();
break;
}
case SymbolBody::DefinedCommonKind:
@ -1871,6 +1871,81 @@ template <class ELFT> bool VersionNeedSection<ELFT>::empty() const {
return getNeedNum() == 0;
}
template <class ELFT>
MergeSyntheticSection<ELFT>::MergeSyntheticSection(StringRef Name,
uint32_t Type, uintX_t Flags,
uintX_t Alignment)
: SyntheticSection<ELFT>(Flags, Type, Alignment, Name),
Builder(StringTableBuilder::RAW, Alignment) {
this->Entsize = Alignment;
}
template <class ELFT>
void MergeSyntheticSection<ELFT>::addSection(MergeInputSection<ELFT> *MS) {
assert(!Finalized);
MS->MergeSec = this;
Sections.push_back(MS);
this->Entsize = MS->Entsize;
}
template <class ELFT> void MergeSyntheticSection<ELFT>::writeTo(uint8_t *Buf) {
Builder.write(Buf);
}
template <class ELFT>
bool MergeSyntheticSection<ELFT>::shouldTailMerge() const {
return (this->Flags & SHF_STRINGS) && Config->Optimize >= 2;
}
template <class ELFT> void MergeSyntheticSection<ELFT>::finalizeTailMerge() {
// Add all string pieces to the string table builder to create section
// contents.
for (MergeInputSection<ELFT> *Sec : Sections)
for (size_t I = 0, E = Sec->Pieces.size(); I != E; ++I)
if (Sec->Pieces[I].Live)
Builder.add(Sec->getData(I));
// Fix the string table content. After this, the contents will never change.
Builder.finalize();
// finalize() fixed tail-optimized strings, so we can now get
// offsets of strings. Get an offset for each string and save it
// to a corresponding StringPiece for easy access.
for (MergeInputSection<ELFT> *Sec : Sections)
for (size_t I = 0, E = Sec->Pieces.size(); I != E; ++I)
if (Sec->Pieces[I].Live)
Sec->Pieces[I].OutputOff = Builder.getOffset(Sec->getData(I));
}
template <class ELFT> void MergeSyntheticSection<ELFT>::finalizeNoTailMerge() {
// Add all string pieces to the string table builder to create section
// contents. Because we are not tail-optimizing, offsets of strings are
// fixed when they are added to the builder (string table builder contains
// a hash table from strings to offsets).
for (MergeInputSection<ELFT> *Sec : Sections)
for (size_t I = 0, E = Sec->Pieces.size(); I != E; ++I)
if (Sec->Pieces[I].Live)
Sec->Pieces[I].OutputOff = Builder.add(Sec->getData(I));
Builder.finalizeInOrder();
}
template <class ELFT> void MergeSyntheticSection<ELFT>::finalize() {
if (Finalized)
return;
Finalized = true;
if (shouldTailMerge())
finalizeTailMerge();
else
finalizeNoTailMerge();
}
template <class ELFT> size_t MergeSyntheticSection<ELFT>::getSize() const {
// We should finalize string builder to know the size.
const_cast<MergeSyntheticSection<ELFT> *>(this)->finalize();
return Builder.getSize();
}
template <class ELFT>
MipsRldMapSection<ELFT>::MipsRldMapSection()
: SyntheticSection<ELFT>(SHF_ALLOC | SHF_WRITE, SHT_PROGBITS,
@ -2064,6 +2139,11 @@ template class elf::VersionDefinitionSection<ELF32BE>;
template class elf::VersionDefinitionSection<ELF64LE>;
template class elf::VersionDefinitionSection<ELF64BE>;
template class elf::MergeSyntheticSection<ELF32LE>;
template class elf::MergeSyntheticSection<ELF32BE>;
template class elf::MergeSyntheticSection<ELF64LE>;
template class elf::MergeSyntheticSection<ELF64BE>;
template class elf::MipsRldMapSection<ELF32LE>;
template class elf::MipsRldMapSection<ELF32BE>;
template class elf::MipsRldMapSection<ELF64LE>;

View File

@ -39,7 +39,7 @@ template <class ELFT> class SyntheticSection : public InputSection<ELFT> {
public:
SyntheticSection(uintX_t Flags, uint32_t Type, uintX_t Addralign,
StringRef Name)
: InputSection<ELFT>(Flags, Type, Addralign, ArrayRef<uint8_t>(), Name,
: InputSection<ELFT>(Flags, Type, Addralign, {}, Name,
InputSectionData::Synthetic) {
this->Live = true;
}
@ -629,6 +629,32 @@ public:
bool empty() const override;
};
// MergeSyntheticSection is a class that allows us to put mergeable sections
// with different attributes in a single output sections. To do that
// we put them into MergeSyntheticSection synthetic input sections which are
// attached to regular output sections.
template <class ELFT>
class MergeSyntheticSection final : public SyntheticSection<ELFT> {
typedef typename ELFT::uint uintX_t;
public:
MergeSyntheticSection(StringRef Name, uint32_t Type, uintX_t Flags,
uintX_t Alignment);
void addSection(MergeInputSection<ELFT> *MS);
void writeTo(uint8_t *Buf) override;
void finalize() override;
bool shouldTailMerge() const;
size_t getSize() const override;
private:
void finalizeTailMerge();
void finalizeNoTailMerge();
bool Finalized = false;
llvm::StringTableBuilder Builder;
std::vector<MergeInputSection<ELFT> *> Sections;
};
// .MIPS.abiflags section.
template <class ELFT>
class MipsAbiFlagsSection final : public SyntheticSection<ELFT> {

View File

@ -148,11 +148,60 @@ template <class ELFT> void Writer<ELFT>::removeEmptyPTLoad() {
Phdrs.erase(I, Phdrs.end());
}
template <class ELFT>
static typename ELFT::uint getOutFlags(InputSectionBase<ELFT> *S) {
return S->Flags & ~(typename ELFT::uint)(SHF_GROUP | SHF_COMPRESSED);
}
// This function scans over the input sections and creates mergeable
// synthetic sections. It removes MergeInputSections from array and
// adds new synthetic ones. Each synthetic section is added to the
// location of the first input section it replaces.
template <class ELFT> static void combineMergableSections() {
typedef typename ELFT::uint uintX_t;
std::vector<MergeSyntheticSection<ELFT> *> MergeSections;
for (InputSectionBase<ELFT> *&S : Symtab<ELFT>::X->Sections) {
MergeInputSection<ELFT> *MS = dyn_cast<MergeInputSection<ELFT>>(S);
if (!MS)
continue;
// We do not want to handle sections that are not alive, so just remove
// them instead of trying to merge.
if (!MS->Live)
continue;
StringRef OutsecName = getOutputSectionName(MS->Name);
uintX_t Flags = getOutFlags(MS);
uintX_t Alignment = std::max<uintX_t>(MS->Alignment, MS->Entsize);
auto I =
llvm::find_if(MergeSections, [=](MergeSyntheticSection<ELFT> *Sec) {
return Sec->Name == OutsecName && Sec->Flags == Flags &&
Sec->Alignment == Alignment;
});
if (I == MergeSections.end()) {
MergeSyntheticSection<ELFT> *Syn = make<MergeSyntheticSection<ELFT>>(
OutsecName, MS->Type, Flags, Alignment);
MergeSections.push_back(Syn);
I = std::prev(MergeSections.end());
S = Syn;
} else {
S = nullptr;
}
(*I)->addSection(MS);
}
std::vector<InputSectionBase<ELFT> *> &V = Symtab<ELFT>::X->Sections;
V.erase(std::remove(V.begin(), V.end(), nullptr), V.end());
}
// The main function of the writer.
template <class ELFT> void Writer<ELFT>::run() {
// Create linker-synthesized sections such as .got or .plt.
// Such sections are of type input section.
createSyntheticSections();
combineMergableSections<ELFT>();
// We need to create some reserved symbols such as _end. Create them.
if (!Config->Relocatable)
@ -973,8 +1022,9 @@ finalizeSynthetic(const std::vector<SyntheticSection<ELFT> *> &Sections) {
// sometimes. This function filters out such unused sections from output.
template <class ELFT>
static void removeUnusedSyntheticSections(std::vector<OutputSectionBase *> &V) {
// Input synthetic sections are placed after all regular ones. We iterate over
// them all and exit at first non-synthetic.
// All input synthetic sections that can be empty are placed after
// all regular ones. We iterate over them all and exit at first
// non-synthetic.
for (InputSectionBase<ELFT> *S : llvm::reverse(Symtab<ELFT>::X->Sections)) {
SyntheticSection<ELFT> *SS = dyn_cast<SyntheticSection<ELFT>>(S);
if (!SS)

View File

@ -4,25 +4,27 @@
# RUN: ld.lld -o %t --script %t.script %t.o -shared
# RUN: llvm-readobj -s -section-data %t | FileCheck %s
# This test shows an oddity in lld. When a linker script alternates among
# different types of output section in the same command, the sections are
# reordered.
# In this test we go from regular, to merge and back to regular. The reason
# for the reordering is that we need two create two output sections and
# one cannot be in the middle of another.
# If this ever becomes a problem, some options would be:
# * Adding an extra layer in between input section and output sections (Chunk).
# With that this example would have 3 chunks, but only one output section.
# This would unfortunately complicate the non-script case too.
# * Just create three output sections.
# * If having three output sections causes problem, have linkerscript specific
# code to write the section table and section indexes. That way we could
# keep 3 sections internally but not expose that.
# CHECK: Name: abc
# CHECK: 0000: 01000000 00000000 02000000 00000000 |
# CHECK: Name: abc
# CHECK: 0000: 61626331 323300 |abc123.|
# CHECK: Section {
# CHECK: Index:
# CHECK: Name: abc
# CHECK-NEXT: Type: SHT_PROGBIT
# CHECK-NEXT: Flags [
# CHECK-NEXT: SHF_ALLOC
# CHECK-NEXT: SHF_MERGE
# CHECK-NEXT: SHF_STRINGS
# CHECK-NEXT: ]
# CHECK-NEXT: Address:
# CHECK-NEXT: Offset:
# CHECK-NEXT: Size:
# CHECK-NEXT: Link:
# CHECK-NEXT: Info:
# CHECK-NEXT: AddressAlignment:
# CHECK-NEXT: EntrySize:
# CHECK-NEXT: SectionData (
# CHECK-NEXT: 0000: 01000000 00000000 61626331 32330002 |........abc123..|
# CHECK-NEXT: 0010: 00000000 000000 |.......|
# CHECK-NEXT: )
# CHECK-NEXT: }
.section foo, "a"
.quad 1

View File

@ -0,0 +1,49 @@
# REQUIRES: x86
# RUN: llvm-mc -filetype=obj -triple=x86_64-pc-linux %s -o %t.o
# RUN: echo "SECTIONS { \
# RUN: . = SIZEOF_HEADERS; \
# RUN: .rodata : { *(.aaa) *(.bbb) A = .; *(.ccc) B = .; } \
# RUN: }" > %t.script
# RUN: ld.lld -o %t.so --script %t.script %t.o -shared
# RUN: llvm-readobj --dyn-symbols %t.so | FileCheck %s
# CHECK: DynamicSymbols [
# CHECK-NEXT: Symbol {
# CHECK-NEXT: Name:
# CHECK-NEXT: Value:
# CHECK-NEXT: Size:
# CHECK-NEXT: Binding:
# CHECK-NEXT: Type:
# CHECK-NEXT: Other:
# CHECK-NEXT: Section:
# CHECK-NEXT: }
# CHECK-NEXT: Symbol {
# CHECK-NEXT: Name: A
# CHECK-NEXT: Value: 0x195
# CHECK-NEXT: Size:
# CHECK-NEXT: Binding:
# CHECK-NEXT: Type:
# CHECK-NEXT: Other:
# CHECK-NEXT: Section:
# CHECK-NEXT: }
# CHECK-NEXT: Symbol {
# CHECK-NEXT: Name: B
# CHECK-NEXT: Value: 0x196
# CHECK-NEXT: Size:
# CHECK-NEXT: Binding:
# CHECK-NEXT: Type:
# CHECK-NEXT: Other:
# CHECK-NEXT: Section:
# CHECK-NEXT: }
# CHECK-NEXT: ]
.section .aaa,"a"
.byte 11
.section .bbb,"aMS",@progbits,1
.asciz "foo"
.section .ccc,"a"
.byte 33

View File

@ -17,61 +17,19 @@
# CHECK-NEXT: ]
# CHECK-NEXT: Address: 0x[[ADDR1:.*]]
# CHECK-NEXT: Offset: 0x[[ADDR1]]
# CHECK-NEXT: Size: 4
# CHECK-NEXT: Link: 0
# CHECK-NEXT: Info: 0
# CHECK-NEXT: AddressAlignment: 1
# CHECK-NEXT: EntrySize: 1
# CHECK-NEXT: }
# CHECK-NEXT: Section {
# CHECK-NEXT: Index:
# CHECK-NEXT: Name: .foo
# CHECK-NEXT: Type: SHT_PROGBITS
# CHECK-NEXT: Flags [
# CHECK-NEXT: SHF_ALLOC
# CHECK-NEXT: SHF_MERGE
# CHECK-NEXT: ]
# CHECK-NEXT: Address: 0x
# CHECK-NEXT: Offset: 0x
# CHECK-NEXT: Size: 1
# CHECK-NEXT: Link: 0
# CHECK-NEXT: Info: 0
# CHECK-NEXT: AddressAlignment: 1
# CHECK-NEXT: EntrySize: 1
# CHECK-NEXT: }
# CHECK-NEXT: Section {
# CHECK-NEXT: Index:
# CHECK-NEXT: Name: .foo
# CHECK-NEXT: Type: SHT_PROGBITS
# CHECK-NEXT: Flags [
# CHECK-NEXT: SHF_ALLOC
# CHECK-NEXT: SHF_MERGE
# CHECK-NEXT: ]
# CHECK-NEXT: Address: 0x
# CHECK-NEXT: Offset: 0x
# CHECK-NEXT: Size: 2
# CHECK-NEXT: Size: 14
# CHECK-NEXT: Link: 0
# CHECK-NEXT: Info: 0
# CHECK-NEXT: AddressAlignment: 2
# CHECK-NEXT: EntrySize: 2
# CHECK-NEXT: EntrySize: 1
# CHECK-NEXT: }
# CHECK-NEXT: Section {
# CHECK-NEXT: Index:
# CHECK-NEXT: Name:
# CHECK-NEXT: Type:
# CHECK-NEXT: Flags [
# CHECK-NEXT: SHF_ALLOC
# CHECK-NEXT: SHF_EXECINSTR
# CHECK-NEXT: ]
# CHECK-NEXT: Address: 0x[[ADDR2:.*]]
# CHECK-NEXT: Offset: 0x[[ADDR2]]
# CHECK: Name: begin
# CHECK-NEXT: Value: 0x[[ADDR1]]
# CHECK: Name: end
# CHECK-NEXT: Value: 0x[[ADDR2]]
# 0x19E = begin + sizeof(.foo) = 0x190 + 0xE
# CHECK-NEXT: Value: 0x19E
.section .foo.1a,"aMS",@progbits,1
.asciz "foo"

View File

@ -48,6 +48,7 @@ local:
// CHECK-NEXT: 0000000000202000 0000000000000004 16 .bss
// CHECK-NEXT: 0000000000202000 0000000000000004 16 COMMON
// CHECK-NEXT: 0000000000000000 0000000000000008 1 .comment
// CHECK-NEXT: 0000000000000000 0000000000000008 1 .comment
// CHECK-NEXT: 0000000000000000 00000000000000f0 8 .symtab
// CHECK-NEXT: 0000000000000000 00000000000000f0 8 .symtab
// CHECK-NEXT: 0000000000000000 0000000000000039 1 .shstrtab

View File

@ -34,10 +34,10 @@
// CHECK-NEXT: 0010: 62617200 |bar.|
// CHECK-NEXT: )
.section .rodata.str1.1,"aMS",@progbits,1
.section .rodata2,"aMS",@progbits,1
.asciz "foo"
// CHECK: Name: .rodata
// CHECK: Name: .rodata2
// CHECK-NEXT: Type: SHT_PROGBITS
// CHECK-NEXT: Flags [
// CHECK-NEXT: SHF_ALLOC

View File

@ -2,18 +2,12 @@
# RUN: llvm-mc -filetype=obj -triple=x86_64-unknown-linux %s -o %t.o
# RUN: echo "SECTIONS { .data : {*(.data.*)} }" > %t0.script
# RUN: ld.lld %t.o -o %t0.out --script %t0.script
# RUN: llvm-objdump -s %t0.out | FileCheck %s --check-prefix=OPT
# OPT: Contents of section .data:
# OPT-NEXT: 0000 01
# OPT-NEXT: Contents of section .data:
# OPT-NEXT: 0001 6100
# OPT-NEXT: Contents of section .data:
# OPT-NEXT: 0003 03
# RUN: llvm-objdump -s %t0.out | FileCheck %s
# RUN: ld.lld -O0 %t.o -o %t1.out --script %t0.script
# RUN: llvm-objdump -s %t1.out | FileCheck %s --check-prefix=NOOPT
# NOOPT: Contents of section .data:
# NOOPT-NEXT: 0000 01610003
# RUN: llvm-objdump -s %t1.out | FileCheck %s
# CHECK: Contents of section .data:
# CHECK-NEXT: 0000 01610003
.section .data.aw,"aw",@progbits
.byte 1