Skip to content

Commit

Permalink
[lld/mac] Implement support for section$start and section$ end symbols
Browse files Browse the repository at this point in the history
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
  • Loading branch information
nico committed Jul 23, 2021
1 parent a085c23 commit 04e8d0b
Show file tree
Hide file tree
Showing 5 changed files with 363 additions and 1 deletion.
7 changes: 7 additions & 0 deletions lld/MachO/OutputSection.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -16,3 +16,10 @@ using namespace lld::macho;
uint64_t OutputSection::getSegmentOffset() const {
return addr - parent->addr;
}

void OutputSection::assignAddressesToStartEndSymbols() {
for (Defined *d : sectionStartSymbols)
d->value = addr;
for (Defined *d : sectionEndSymbols)
d->value = addr + getSize();
}
7 changes: 7 additions & 0 deletions lld/MachO/OutputSection.h
Original file line number Diff line number Diff line change
Expand Up @@ -9,14 +9,17 @@
#ifndef LLD_MACHO_OUTPUT_SECTION_H
#define LLD_MACHO_OUTPUT_SECTION_H

#include "Symbols.h"
#include "lld/Common/LLVM.h"
#include "llvm/ADT/DenseMap.h"
#include "llvm/ADT/TinyPtrVector.h"

#include <limits>

namespace lld {
namespace macho {

class Defined;
class InputSection;
class OutputSegment;

Expand Down Expand Up @@ -62,7 +65,11 @@ class OutputSection {

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

void assignAddressesToStartEndSymbols();

StringRef name;
llvm::TinyPtrVector<Defined *> sectionStartSymbols;
llvm::TinyPtrVector<Defined *> sectionEndSymbols;
OutputSegment *parent = nullptr;
// For output sections that don't have explicit ordering requirements, their
// output order should be based on the order of the input sections they
Expand Down
68 changes: 68 additions & 0 deletions lld/MachO/SymbolTable.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -7,9 +7,11 @@
//===----------------------------------------------------------------------===//

#include "SymbolTable.h"
#include "ConcatOutputSection.h"
#include "Config.h"
#include "InputFiles.h"
#include "Symbols.h"
#include "SyntheticSections.h"
#include "lld/Common/ErrorHandler.h"
#include "lld/Common/Memory.h"

Expand Down Expand Up @@ -196,7 +198,73 @@ Defined *SymbolTable::addSynthetic(StringRef name, InputSection *isec,
return s;
}

enum class Boundary {
Start,
End,
};

static void handleSectionBoundarySymbol(const Undefined &sym, StringRef segSect,
Boundary which) {
StringRef segName, sectName;
std::tie(segName, sectName) = segSect.split('$');

// Attach the symbol to any InputSection that will end up in the right
// OutputSection -- it doesn't matter which one we pick.
// Don't bother looking through inputSections for a matching
// ConcatInputSection -- we need to create ConcatInputSection for
// non-existing sections anyways, and that codepath works even if we should
// already have a ConcatInputSection with the right name.

OutputSection *osec = nullptr;
// This looks for __TEXT,__cstring etc.
for (SyntheticSection *ssec : syntheticSections)
if (ssec->segname == segName && ssec->name == sectName) {
osec = ssec->isec->parent;
break;
}

if (!osec) {
ConcatInputSection *isec = make<ConcatInputSection>(segName, sectName);

// This runs after markLive() and is only called for Undefineds that are
// live. Marking the isec live ensures an OutputSection is created that the
// start/end symbol can refer to.
assert(sym.isLive());
isec->live = true;

// This runs after gatherInputSections(), so need to explicitly set parent
// and add to inputSections.
osec = isec->parent = ConcatOutputSection::getOrCreateForInput(isec);
inputSections.push_back(isec);
}

Defined *boundarySym = symtab->addSynthetic(
sym.getName(), /*isec=*/nullptr, /*value=*/-1, /*isPrivateExtern=*/true,
/*includeInSymtab=*/false, /*referencedDynamically=*/false);
if (which == Boundary::Start)
osec->sectionStartSymbols.push_back(boundarySym);
else
osec->sectionEndSymbols.push_back(boundarySym);
}

static void handleSegmentBoundarySymbol(const Undefined &sym, StringRef segName,
Boundary which) {
// FIXME
error("segment$start$ and segment$end$ symbols are not yet implemented");
}

void lld::macho::treatUndefinedSymbol(const Undefined &sym, StringRef source) {
// Handle start/end symbols.
StringRef name = sym.getName();
if (name.consume_front("section$start$"))
return handleSectionBoundarySymbol(sym, name, Boundary::Start);
if (name.consume_front("section$end$"))
return handleSectionBoundarySymbol(sym, name, Boundary::End);
if (name.consume_front("segment$start$"))
return handleSegmentBoundarySymbol(sym, name, Boundary::Start);
if (name.consume_front("segment$end$"))
return handleSegmentBoundarySymbol(sym, name, Boundary::End);

// Handle -U.
if (config->explicitDynamicLookups.count(sym.getName())) {
symtab->addDynamicLookup(sym.getName());
Expand Down
8 changes: 7 additions & 1 deletion lld/MachO/Writer.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -630,7 +630,12 @@ static void prepareSymbolRelocation(Symbol *sym, const InputSection *isec,

void Writer::scanRelocations() {
TimeTraceScope timeScope("Scan relocations");
for (ConcatInputSection *isec : inputSections) {

// This can't use a for-each loop: It calls treatUndefinedSymbol(), which can
// add to inputSections, which invalidates inputSections's iterators.
for (size_t i = 0; i < inputSections.size(); ++i) {
ConcatInputSection *isec = inputSections[i];

if (isec->shouldOmitFromOutput())
continue;

Expand Down Expand Up @@ -1029,6 +1034,7 @@ void Writer::assignAddresses(OutputSegment *seg) {
osec->addr = addr;
osec->fileOff = isZeroFill(osec->flags) ? 0 : fileOff;
osec->finalize();
osec->assignAddressesToStartEndSymbols();

addr += osec->getSize();
fileOff += osec->getFileSize();
Expand Down
Loading

0 comments on commit 04e8d0b

Please sign in to comment.