[lld] r184327 - [PECOFF] Add a pass to ensure the correct ordering of grouped sections.
Rui Ueyama
ruiu at google.com
Wed Jun 19 10:46:58 PDT 2013
Author: ruiu
Date: Wed Jun 19 12:46:57 2013
New Revision: 184327
URL: http://llvm.org/viewvc/llvm-project?rev=184327&view=rev
Log:
[PECOFF] Add a pass to ensure the correct ordering of grouped sections.
Reviewers: shankarke
CC: llvm-commits
Differential Revision: http://llvm-reviews.chandlerc.com/D998
Added:
lld/trunk/lib/ReaderWriter/PECOFF/Atoms.cpp
lld/trunk/lib/ReaderWriter/PECOFF/GroupedSectionsPass.h
lld/trunk/test/pecoff/Inputs/grouped-sections.asm
lld/trunk/test/pecoff/Inputs/grouped-sections.obj
lld/trunk/test/pecoff/grouped-sections.test
Modified:
lld/trunk/lib/ReaderWriter/PECOFF/Atoms.h
lld/trunk/lib/ReaderWriter/PECOFF/CMakeLists.txt
lld/trunk/lib/ReaderWriter/PECOFF/PECOFFTargetInfo.cpp
lld/trunk/lib/ReaderWriter/PECOFF/ReaderCOFF.cpp
Added: lld/trunk/lib/ReaderWriter/PECOFF/Atoms.cpp
URL: http://llvm.org/viewvc/llvm-project/lld/trunk/lib/ReaderWriter/PECOFF/Atoms.cpp?rev=184327&view=auto
==============================================================================
--- lld/trunk/lib/ReaderWriter/PECOFF/Atoms.cpp (added)
+++ lld/trunk/lib/ReaderWriter/PECOFF/Atoms.cpp Wed Jun 19 12:46:57 2013
@@ -0,0 +1,30 @@
+//===- lib/ReaderWriter/PECOFF/Atoms.cpp ----------------------------------===//
+//
+// The LLVM Linker
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#include "Atoms.h"
+
+namespace lld {
+namespace coff {
+
+namespace {
+void addEdge(COFFDefinedAtom *a, COFFDefinedAtom *b,
+ lld::Reference::Kind kind) {
+ auto ref = new COFFReference(kind);
+ ref->setTarget(b);
+ a->addReference(std::unique_ptr<COFFReference>(ref));
+}
+}
+
+void connectAtomsWithLayoutEdge(COFFDefinedAtom *a, COFFDefinedAtom *b) {
+ addEdge(a, b, lld::Reference::kindLayoutAfter);
+ addEdge(b, a, lld::Reference::kindLayoutBefore);
+}
+
+} // namespace coff
+} // namespace lld
Modified: lld/trunk/lib/ReaderWriter/PECOFF/Atoms.h
URL: http://llvm.org/viewvc/llvm-project/lld/trunk/lib/ReaderWriter/PECOFF/Atoms.h?rev=184327&r1=184326&r2=184327&view=diff
==============================================================================
--- lld/trunk/lib/ReaderWriter/PECOFF/Atoms.h (original)
+++ lld/trunk/lib/ReaderWriter/PECOFF/Atoms.h Wed Jun 19 12:46:57 2013
@@ -15,10 +15,14 @@
namespace lld {
namespace coff {
+class COFFDefinedAtom;
+using llvm::object::COFFObjectFile;
using llvm::object::coff_section;
using llvm::object::coff_symbol;
+void connectAtomsWithLayoutEdge(COFFDefinedAtom *a, COFFDefinedAtom *b);
+
/// A COFFReference represents relocation information for an atom. For
/// example, if atom X has a reference to atom Y with offsetInAtom=8, that
/// means that the address starting at 8th byte of the content of atom X needs
@@ -93,23 +97,23 @@ private:
class COFFDefinedAtom : public DefinedAtom {
public:
COFFDefinedAtom(const File &f, llvm::StringRef n, const coff_symbol *symb,
- const coff_section *sec, llvm::ArrayRef<uint8_t> d)
- : _owningFile(f), _name(n), _symbol(symb), _section(sec), _data(d) {}
+ const coff_section *sec, llvm::ArrayRef<uint8_t> d,
+ StringRef sectionName, uint64_t ordinal)
+ : _owningFile(f), _name(n), _symbol(symb), _section(sec), _data(d),
+ _sectionName(sectionName), _ordinal(ordinal) {}
virtual const class File &file() const { return _owningFile; }
virtual llvm::StringRef name() const { return _name; }
- virtual uint64_t ordinal() const {
- return reinterpret_cast<intptr_t>(_symbol);
- }
+ virtual uint64_t ordinal() const { return _ordinal; }
virtual uint64_t size() const { return _data.size(); }
uint64_t originalOffset() const { return _symbol->Value; }
- void addReference(COFFReference *reference) {
- _references.push_back(reference);
+ void addReference(std::unique_ptr<COFFReference> reference) {
+ _references.push_back(std::move(reference));
}
virtual Scope scope() const {
@@ -163,6 +167,8 @@ public:
virtual bool isAlias() const { return false; }
+ virtual StringRef getSectionName() const { return _sectionName; }
+
virtual llvm::ArrayRef<uint8_t> rawContent() const { return _data; }
virtual reference_iterator begin() const {
@@ -177,7 +183,7 @@ public:
private:
virtual const Reference *derefIterator(const void *iter) const {
size_t index = reinterpret_cast<size_t>(iter);
- return _references[index];
+ return _references[index].get();
}
virtual void incrementIterator(const void *&iter) const {
@@ -189,8 +195,10 @@ private:
llvm::StringRef _name;
const coff_symbol *_symbol;
const coff_section *_section;
- std::vector<COFFReference *> _references;
+ std::vector<std::unique_ptr<COFFReference> > _references;
llvm::ArrayRef<uint8_t> _data;
+ StringRef _sectionName;
+ uint64_t _ordinal;
};
} // namespace coff
Modified: lld/trunk/lib/ReaderWriter/PECOFF/CMakeLists.txt
URL: http://llvm.org/viewvc/llvm-project/lld/trunk/lib/ReaderWriter/PECOFF/CMakeLists.txt?rev=184327&r1=184326&r2=184327&view=diff
==============================================================================
--- lld/trunk/lib/ReaderWriter/PECOFF/CMakeLists.txt (original)
+++ lld/trunk/lib/ReaderWriter/PECOFF/CMakeLists.txt Wed Jun 19 12:46:57 2013
@@ -1,4 +1,5 @@
add_lld_library(lldPECOFF
+ Atoms.cpp
PECOFFTargetInfo.cpp
ReaderCOFF.cpp
ReaderImportHeader.cpp
Added: lld/trunk/lib/ReaderWriter/PECOFF/GroupedSectionsPass.h
URL: http://llvm.org/viewvc/llvm-project/lld/trunk/lib/ReaderWriter/PECOFF/GroupedSectionsPass.h?rev=184327&view=auto
==============================================================================
--- lld/trunk/lib/ReaderWriter/PECOFF/GroupedSectionsPass.h (added)
+++ lld/trunk/lib/ReaderWriter/PECOFF/GroupedSectionsPass.h Wed Jun 19 12:46:57 2013
@@ -0,0 +1,122 @@
+//===- lib/ReaderWriter/PECOFF/GroupedSectionsPass.h-----------------------===//
+//
+// The LLVM Linker
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+///
+/// \file \brief This pass adds layout-{before,after} references to atoms in
+/// grouped sections, so that they will appear in the correct order in the
+/// output.
+///
+/// In COFF, sections will be merged into one section by the linker if their
+/// names are the same after discarding the "$" character and all characters
+/// follow it from their names. The characters following the "$" character
+/// determines the merge order. Assume there's an object file containing four
+/// data sections in the following order.
+///
+/// - .data$2
+/// - .data$3
+/// - .data$1
+/// - .data
+///
+/// In this case, the resulting binary should have ".data" section with the
+/// contents of ".data", ".data$1", ".data$2" and ".data$3" in that order.
+///
+/// In lld, this contraint is modeled by the atom model using
+/// layout-{before,after} references. Atoms in the same (unmerged-)section have
+/// already been connected with layout-{before,after} edges each other when the
+/// control reaches to this pass. We pick the head atom from each section that
+/// needs to merged, and connects them with layout-{before,after} edges in the
+/// right order, so that they'll be sorted correctly in the layout pass.
+///
+//===----------------------------------------------------------------------===//
+
+#ifndef LLD_READER_WRITER_PE_COFF_GROUPED_SECTIONS_PASS_H_
+#define LLD_READER_WRITER_PE_COFF_GROUPED_SECTIONS_PASS_H_
+
+#include "Atoms.h"
+#include "lld/Core/Pass.h"
+#include "lld/Core/Pass.h"
+#include "llvm/Support/Debug.h"
+
+#include <algorithm>
+#include <map>
+
+using lld::coff::COFFDefinedAtom;
+
+namespace lld {
+namespace pecoff {
+
+namespace {
+bool compareByFileOrdinal(const DefinedAtom *a, const DefinedAtom *b) {
+ return a->file().ordinal() > b->file().ordinal();
+}
+}
+
+class GroupedSectionsPass : public lld::Pass {
+public:
+ GroupedSectionsPass() {}
+
+ virtual void perform(MutableFile &mergedFile) {
+ std::map<StringRef, std::vector<COFFDefinedAtom *>> sectionToHeadAtoms(
+ filterHeadAtoms(mergedFile));
+ std::vector<std::vector<COFFDefinedAtom *>> groupedAtomsList(
+ groupBySectionName(sectionToHeadAtoms));
+ for (auto &groupedAtoms : groupedAtomsList)
+ connectAtoms(groupedAtoms);
+ }
+
+private:
+ typedef std::map<StringRef, std::vector<COFFDefinedAtom *>> SectionToAtomsT;
+
+ /// Returns the list of atoms that appeared at the beginning of sections.
+ SectionToAtomsT filterHeadAtoms(MutableFile &mutableFile) const {
+ SectionToAtomsT result;
+ for (const DefinedAtom *atom : mutableFile.defined()) {
+ auto *coffAtom = (COFFDefinedAtom *)atom;
+ if (coffAtom->ordinal() == 0)
+ result[coffAtom->getSectionName()].push_back(coffAtom);
+ }
+ return std::move(result);
+ }
+
+ /// Group atoms that needs to be merged. Returned atoms are sorted by section
+ /// name and file ordinal.
+ std::vector<std::vector<COFFDefinedAtom *>>
+ groupBySectionName(SectionToAtomsT sectionToHeadAtoms) const {
+ SectionToAtomsT res;
+ // Note that the atoms are already sorted by section name because std::map
+ // is a sorted map.
+ for (auto &i : sectionToHeadAtoms) {
+ StringRef sectionName = i.first;
+ std::vector<COFFDefinedAtom*> &atoms = i.second;
+ // Sections with the same name could exist if they are from different
+ // files. If that's the case, the sections needs to be sorted in the same
+ // order as they appeared in the command line.
+ std::stable_sort(atoms.begin(), atoms.end(), compareByFileOrdinal);
+ for (COFFDefinedAtom *atom : atoms) {
+ StringRef baseName = sectionName.split('$').first;
+ res[baseName].push_back(atom);
+ }
+ }
+ std::vector<std::vector<COFFDefinedAtom *>> vec;
+ for (auto &i : res)
+ vec.push_back(std::move(i.second));
+ return std::move(vec);
+ }
+
+ void connectAtoms(std::vector<COFFDefinedAtom *> atoms) const {
+ if (atoms.size() < 2)
+ return;
+ for (auto it = atoms.begin(), e = atoms.end(); it + 1 != e; ++it)
+ connectAtomsWithLayoutEdge(*it, *(it + 1));
+ }
+};
+
+} // namespace pecoff
+} // namespace lld
+
+#endif
Modified: lld/trunk/lib/ReaderWriter/PECOFF/PECOFFTargetInfo.cpp
URL: http://llvm.org/viewvc/llvm-project/lld/trunk/lib/ReaderWriter/PECOFF/PECOFFTargetInfo.cpp?rev=184327&r1=184326&r2=184327&view=diff
==============================================================================
--- lld/trunk/lib/ReaderWriter/PECOFF/PECOFFTargetInfo.cpp (original)
+++ lld/trunk/lib/ReaderWriter/PECOFF/PECOFFTargetInfo.cpp Wed Jun 19 12:46:57 2013
@@ -7,15 +7,14 @@
//
//===----------------------------------------------------------------------===//
-#include "lld/ReaderWriter/PECOFFTargetInfo.h"
+#include "GroupedSectionsPass.h"
#include "lld/Core/PassManager.h"
#include "lld/Passes/LayoutPass.h"
+#include "lld/ReaderWriter/PECOFFTargetInfo.h"
#include "lld/ReaderWriter/Reader.h"
#include "lld/ReaderWriter/Writer.h"
-#include "llvm/Support/Debug.h"
-
namespace lld {
error_code PECOFFTargetInfo::parseFile(
@@ -59,6 +58,7 @@ PECOFFTargetInfo::stringFromRelocKind(Re
}
void PECOFFTargetInfo::addPasses(PassManager &pm) const {
+ pm.add(std::unique_ptr<Pass>(new pecoff::GroupedSectionsPass()));
pm.add(std::unique_ptr<Pass>(new LayoutPass()));
}
Modified: lld/trunk/lib/ReaderWriter/PECOFF/ReaderCOFF.cpp
URL: http://llvm.org/viewvc/llvm-project/lld/trunk/lib/ReaderWriter/PECOFF/ReaderCOFF.cpp?rev=184327&r1=184326&r2=184327&view=diff
==============================================================================
--- lld/trunk/lib/ReaderWriter/PECOFF/ReaderCOFF.cpp (original)
+++ lld/trunk/lib/ReaderWriter/PECOFF/ReaderCOFF.cpp Wed Jun 19 12:46:57 2013
@@ -184,14 +184,19 @@ private:
}));
llvm::ArrayRef<uint8_t> SecData;
+ StringRef sectionName;
if (error_code ec = Obj->getSectionContents(section, SecData))
return ec;
+ if (error_code ec = Obj->getSectionName(section, sectionName))
+ return ec;
+ uint64_t ordinal = 0;
// Create an atom for the entire section.
if (symbols.empty()) {
llvm::ArrayRef<uint8_t> Data(SecData.data(), SecData.size());
atoms.push_back(new (AtomStorage.Allocate<COFFDefinedAtom>())
- COFFDefinedAtom(*this, "", nullptr, section, Data));
+ COFFDefinedAtom(*this, "", nullptr, section, Data,
+ sectionName, ordinal++));
return error_code::success();
}
@@ -201,7 +206,8 @@ private:
uint64_t Size = symbols[0]->Value;
llvm::ArrayRef<uint8_t> Data(SecData.data(), Size);
atoms.push_back(new (AtomStorage.Allocate<COFFDefinedAtom>())
- COFFDefinedAtom(*this, "", nullptr, section, Data));
+ COFFDefinedAtom(*this, "", nullptr, section, Data,
+ sectionName, ordinal++));
}
for (auto si = symbols.begin(), se = symbols.end(); si != se; ++si) {
@@ -215,24 +221,12 @@ private:
if (error_code ec = Obj->getSymbolName(*si, name))
return ec;
atoms.push_back(new (AtomStorage.Allocate<COFFDefinedAtom>())
- COFFDefinedAtom(*this, name, *si, section, Data));
+ COFFDefinedAtom(*this, name, *si, section, Data,
+ sectionName, ordinal++));
}
return error_code::success();
}
- void addEdge(COFFDefinedAtom *a, COFFDefinedAtom *b,
- lld::Reference::Kind kind) const {
- auto ref = new (AtomStorage.Allocate<COFFReference>()) COFFReference(kind);
- ref->setTarget(b);
- a->addReference(ref);
- }
-
- void connectAtomsWithLayoutEdge(COFFDefinedAtom *a,
- COFFDefinedAtom *b) const {
- addEdge(a, b, lld::Reference::kindLayoutAfter);
- addEdge(b, a, lld::Reference::kindLayoutBefore);
- }
-
/// Connect atoms appeared in the same section with layout-{before,after}
/// edges. It has two purposes.
///
@@ -335,9 +329,8 @@ private:
COFFDefinedAtom *atom = findAtomAt(rel->VirtualAddress, section, atoms);
uint32_t offsetInAtom = itemAddress - atom->originalOffset();
assert(offsetInAtom < atom->size());
- COFFReference *ref = new (AtomStorage.Allocate<COFFReference>())
- COFFReference(targetAtom, offsetInAtom, rel->Type);
- atom->addReference(ref);
+ atom->addReference(std::unique_ptr<COFFReference>(
+ new COFFReference(targetAtom, offsetInAtom, rel->Type)));
return error_code::success();
}
Added: lld/trunk/test/pecoff/Inputs/grouped-sections.asm
URL: http://llvm.org/viewvc/llvm-project/lld/trunk/test/pecoff/Inputs/grouped-sections.asm?rev=184327&view=auto
==============================================================================
--- lld/trunk/test/pecoff/Inputs/grouped-sections.asm (added)
+++ lld/trunk/test/pecoff/Inputs/grouped-sections.asm Wed Jun 19 12:46:57 2013
@@ -0,0 +1,17 @@
+.386
+.model flat, c
+
+_data$2 SEGMENT BYTE alias(".data$2")
+ db "orld", 0
+_data$2 ends
+
+_data$1 SEGMENT BYTE alias(".data$1")
+ db "o, w"
+_data$1 ends
+
+.data
+ db "Hell"
+
+.code
+main:
+end main
Added: lld/trunk/test/pecoff/Inputs/grouped-sections.obj
URL: http://llvm.org/viewvc/llvm-project/lld/trunk/test/pecoff/Inputs/grouped-sections.obj?rev=184327&view=auto
==============================================================================
Binary files lld/trunk/test/pecoff/Inputs/grouped-sections.obj (added) and lld/trunk/test/pecoff/Inputs/grouped-sections.obj Wed Jun 19 12:46:57 2013 differ
Added: lld/trunk/test/pecoff/grouped-sections.test
URL: http://llvm.org/viewvc/llvm-project/lld/trunk/test/pecoff/grouped-sections.test?rev=184327&view=auto
==============================================================================
--- lld/trunk/test/pecoff/grouped-sections.test (added)
+++ lld/trunk/test/pecoff/grouped-sections.test Wed Jun 19 12:46:57 2013
@@ -0,0 +1,15 @@
+# RUN: lld -flavor link -out %t1 -subsystem console -force \
+# RUN: -- %p/Inputs/grouped-sections.obj && llvm-objdump -s %t1 | FileCheck %s
+#
+# The file "grouped-sections.obj" has three data sections in the following
+# order:
+#
+# .data$2
+# .data$1
+# .data
+#
+# If all the sections will be merged correctly, the resulting ".data"
+# section will have the string "Hello, world".
+
+CHECK: Contents of section .rdata:
+CHECK-NEXT: Hello, world
More information about the llvm-commits
mailing list