Skip to content

Commit 04e8d0b

Browse files
committed
[lld/mac] Implement support for section$start and section$ end symbols
With this, libclang_rt.profile_osx.a can be linked, that is coverage and PGO-instrumented builds should now work with lld. section$start and section$end symbols can create non-existing sections. They're also undefined symbols that are only magic if there isn't a regular symbol with their name, which means the need to be handled in treatUndefined() instead of just looping over all existing sections and adding start and end symbols like the ELF port does. To represent the actual symbols, this uses absolute symbols that get their value updated once an output section is layed out. segment$start and segment$end are still missing for now, but they produce a nicer error message after this patch. Main part of PR50760. Differential Revision: https://reviews.llvm.org/D106629
1 parent a085c23 commit 04e8d0b

File tree

5 files changed

+363
-1
lines changed

5 files changed

+363
-1
lines changed

lld/MachO/OutputSection.cpp

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -16,3 +16,10 @@ using namespace lld::macho;
1616
uint64_t OutputSection::getSegmentOffset() const {
1717
return addr - parent->addr;
1818
}
19+
20+
void OutputSection::assignAddressesToStartEndSymbols() {
21+
for (Defined *d : sectionStartSymbols)
22+
d->value = addr;
23+
for (Defined *d : sectionEndSymbols)
24+
d->value = addr + getSize();
25+
}

lld/MachO/OutputSection.h

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -9,14 +9,17 @@
99
#ifndef LLD_MACHO_OUTPUT_SECTION_H
1010
#define LLD_MACHO_OUTPUT_SECTION_H
1111

12+
#include "Symbols.h"
1213
#include "lld/Common/LLVM.h"
1314
#include "llvm/ADT/DenseMap.h"
15+
#include "llvm/ADT/TinyPtrVector.h"
1416

1517
#include <limits>
1618

1719
namespace lld {
1820
namespace macho {
1921

22+
class Defined;
2023
class InputSection;
2124
class OutputSegment;
2225

@@ -62,7 +65,11 @@ class OutputSection {
6265

6366
virtual void writeTo(uint8_t *buf) const = 0;
6467

68+
void assignAddressesToStartEndSymbols();
69+
6570
StringRef name;
71+
llvm::TinyPtrVector<Defined *> sectionStartSymbols;
72+
llvm::TinyPtrVector<Defined *> sectionEndSymbols;
6673
OutputSegment *parent = nullptr;
6774
// For output sections that don't have explicit ordering requirements, their
6875
// output order should be based on the order of the input sections they

lld/MachO/SymbolTable.cpp

Lines changed: 68 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7,9 +7,11 @@
77
//===----------------------------------------------------------------------===//
88

99
#include "SymbolTable.h"
10+
#include "ConcatOutputSection.h"
1011
#include "Config.h"
1112
#include "InputFiles.h"
1213
#include "Symbols.h"
14+
#include "SyntheticSections.h"
1315
#include "lld/Common/ErrorHandler.h"
1416
#include "lld/Common/Memory.h"
1517

@@ -196,7 +198,73 @@ Defined *SymbolTable::addSynthetic(StringRef name, InputSection *isec,
196198
return s;
197199
}
198200

201+
enum class Boundary {
202+
Start,
203+
End,
204+
};
205+
206+
static void handleSectionBoundarySymbol(const Undefined &sym, StringRef segSect,
207+
Boundary which) {
208+
StringRef segName, sectName;
209+
std::tie(segName, sectName) = segSect.split('$');
210+
211+
// Attach the symbol to any InputSection that will end up in the right
212+
// OutputSection -- it doesn't matter which one we pick.
213+
// Don't bother looking through inputSections for a matching
214+
// ConcatInputSection -- we need to create ConcatInputSection for
215+
// non-existing sections anyways, and that codepath works even if we should
216+
// already have a ConcatInputSection with the right name.
217+
218+
OutputSection *osec = nullptr;
219+
// This looks for __TEXT,__cstring etc.
220+
for (SyntheticSection *ssec : syntheticSections)
221+
if (ssec->segname == segName && ssec->name == sectName) {
222+
osec = ssec->isec->parent;
223+
break;
224+
}
225+
226+
if (!osec) {
227+
ConcatInputSection *isec = make<ConcatInputSection>(segName, sectName);
228+
229+
// This runs after markLive() and is only called for Undefineds that are
230+
// live. Marking the isec live ensures an OutputSection is created that the
231+
// start/end symbol can refer to.
232+
assert(sym.isLive());
233+
isec->live = true;
234+
235+
// This runs after gatherInputSections(), so need to explicitly set parent
236+
// and add to inputSections.
237+
osec = isec->parent = ConcatOutputSection::getOrCreateForInput(isec);
238+
inputSections.push_back(isec);
239+
}
240+
241+
Defined *boundarySym = symtab->addSynthetic(
242+
sym.getName(), /*isec=*/nullptr, /*value=*/-1, /*isPrivateExtern=*/true,
243+
/*includeInSymtab=*/false, /*referencedDynamically=*/false);
244+
if (which == Boundary::Start)
245+
osec->sectionStartSymbols.push_back(boundarySym);
246+
else
247+
osec->sectionEndSymbols.push_back(boundarySym);
248+
}
249+
250+
static void handleSegmentBoundarySymbol(const Undefined &sym, StringRef segName,
251+
Boundary which) {
252+
// FIXME
253+
error("segment$start$ and segment$end$ symbols are not yet implemented");
254+
}
255+
199256
void lld::macho::treatUndefinedSymbol(const Undefined &sym, StringRef source) {
257+
// Handle start/end symbols.
258+
StringRef name = sym.getName();
259+
if (name.consume_front("section$start$"))
260+
return handleSectionBoundarySymbol(sym, name, Boundary::Start);
261+
if (name.consume_front("section$end$"))
262+
return handleSectionBoundarySymbol(sym, name, Boundary::End);
263+
if (name.consume_front("segment$start$"))
264+
return handleSegmentBoundarySymbol(sym, name, Boundary::Start);
265+
if (name.consume_front("segment$end$"))
266+
return handleSegmentBoundarySymbol(sym, name, Boundary::End);
267+
200268
// Handle -U.
201269
if (config->explicitDynamicLookups.count(sym.getName())) {
202270
symtab->addDynamicLookup(sym.getName());

lld/MachO/Writer.cpp

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -630,7 +630,12 @@ static void prepareSymbolRelocation(Symbol *sym, const InputSection *isec,
630630

631631
void Writer::scanRelocations() {
632632
TimeTraceScope timeScope("Scan relocations");
633-
for (ConcatInputSection *isec : inputSections) {
633+
634+
// This can't use a for-each loop: It calls treatUndefinedSymbol(), which can
635+
// add to inputSections, which invalidates inputSections's iterators.
636+
for (size_t i = 0; i < inputSections.size(); ++i) {
637+
ConcatInputSection *isec = inputSections[i];
638+
634639
if (isec->shouldOmitFromOutput())
635640
continue;
636641

@@ -1029,6 +1034,7 @@ void Writer::assignAddresses(OutputSegment *seg) {
10291034
osec->addr = addr;
10301035
osec->fileOff = isZeroFill(osec->flags) ? 0 : fileOff;
10311036
osec->finalize();
1037+
osec->assignAddressesToStartEndSymbols();
10321038

10331039
addr += osec->getSize();
10341040
fileOff += osec->getFileSize();

0 commit comments

Comments
 (0)