forked from OSchip/llvm-project
[lld-macho] Define __mh_*_header synthetic symbols.
Bug: https://bugs.llvm.org/show_bug.cgi?id=49290 Differential Revision: https://reviews.llvm.org/D97007
This commit is contained in:
parent
6c52d4fd4c
commit
66f340051a
|
@ -1043,14 +1043,7 @@ bool macho::link(ArrayRef<const char *> argsArr, bool canExitEarly,
|
||||||
}
|
}
|
||||||
|
|
||||||
createSyntheticSections();
|
createSyntheticSections();
|
||||||
|
createSyntheticSymbols();
|
||||||
// The Itanium C++ ABI requires dylibs to pass a pointer to __cxa_atexit
|
|
||||||
// which does e.g. cleanup of static global variables. The ABI document says
|
|
||||||
// that the pointer can point to any address in one of the dylib's segments,
|
|
||||||
// but in practice ld64 seems to set it to point to the header, so that's
|
|
||||||
// what's implemented here.
|
|
||||||
symtab->addSynthetic("___dso_handle", in.header->isec, 0,
|
|
||||||
/*privateExtern=*/true, /*linkerInternal=*/true);
|
|
||||||
|
|
||||||
for (const Arg *arg : args.filtered(OPT_sectcreate)) {
|
for (const Arg *arg : args.filtered(OPT_sectcreate)) {
|
||||||
StringRef segName = arg->getValue(0);
|
StringRef segName = arg->getValue(0);
|
||||||
|
|
|
@ -159,10 +159,10 @@ Symbol *SymbolTable::addLazy(StringRef name, ArchiveFile *file,
|
||||||
|
|
||||||
Defined *SymbolTable::addSynthetic(StringRef name, InputSection *isec,
|
Defined *SymbolTable::addSynthetic(StringRef name, InputSection *isec,
|
||||||
uint32_t value, bool isPrivateExtern,
|
uint32_t value, bool isPrivateExtern,
|
||||||
bool isLinkerInternal) {
|
bool includeInSymtab) {
|
||||||
Defined *s = addDefined(name, nullptr, isec, value, /*isWeakDef=*/false,
|
Defined *s = addDefined(name, nullptr, isec, value,
|
||||||
isPrivateExtern);
|
/*isWeakDef=*/false, isPrivateExtern);
|
||||||
s->linkerInternal = isLinkerInternal;
|
s->includeInSymtab = includeInSymtab;
|
||||||
return s;
|
return s;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -9,6 +9,8 @@
|
||||||
#ifndef LLD_MACHO_SYMBOL_TABLE_H
|
#ifndef LLD_MACHO_SYMBOL_TABLE_H
|
||||||
#define LLD_MACHO_SYMBOL_TABLE_H
|
#define LLD_MACHO_SYMBOL_TABLE_H
|
||||||
|
|
||||||
|
#include "Symbols.h"
|
||||||
|
|
||||||
#include "lld/Common/LLVM.h"
|
#include "lld/Common/LLVM.h"
|
||||||
#include "llvm/ADT/CachedHashString.h"
|
#include "llvm/ADT/CachedHashString.h"
|
||||||
#include "llvm/ADT/DenseMap.h"
|
#include "llvm/ADT/DenseMap.h"
|
||||||
|
@ -50,7 +52,7 @@ public:
|
||||||
const llvm::object::Archive::Symbol &sym);
|
const llvm::object::Archive::Symbol &sym);
|
||||||
|
|
||||||
Defined *addSynthetic(StringRef name, InputSection *, uint32_t value,
|
Defined *addSynthetic(StringRef name, InputSection *, uint32_t value,
|
||||||
bool isPrivateExtern, bool isLinkerInternal);
|
bool isPrivateExtern, bool includeInSymtab);
|
||||||
|
|
||||||
ArrayRef<Symbol *> getSymbols() const { return symVector; }
|
ArrayRef<Symbol *> getSymbols() const { return symVector; }
|
||||||
Symbol *find(llvm::CachedHashStringRef name);
|
Symbol *find(llvm::CachedHashStringRef name);
|
||||||
|
|
|
@ -99,7 +99,7 @@ public:
|
||||||
bool isWeakDef, bool isExternal, bool isPrivateExtern)
|
bool isWeakDef, bool isExternal, bool isPrivateExtern)
|
||||||
: Symbol(DefinedKind, name, file), isec(isec), value(value),
|
: Symbol(DefinedKind, name, file), isec(isec), value(value),
|
||||||
overridesWeakDef(false), privateExtern(isPrivateExtern),
|
overridesWeakDef(false), privateExtern(isPrivateExtern),
|
||||||
linkerInternal(false), weakDef(isWeakDef), external(isExternal) {}
|
includeInSymtab(true), weakDef(isWeakDef), external(isExternal) {}
|
||||||
|
|
||||||
bool isWeakDef() const override { return weakDef; }
|
bool isWeakDef() const override { return weakDef; }
|
||||||
bool isExternalWeakDef() const {
|
bool isExternalWeakDef() const {
|
||||||
|
@ -124,8 +124,8 @@ public:
|
||||||
bool overridesWeakDef : 1;
|
bool overridesWeakDef : 1;
|
||||||
// Whether this symbol should appear in the output binary's export trie.
|
// Whether this symbol should appear in the output binary's export trie.
|
||||||
bool privateExtern : 1;
|
bool privateExtern : 1;
|
||||||
// Whether this symbol should appear in the output binary's symbol table.
|
// Whether this symbol should appear in the output symbol table.
|
||||||
bool linkerInternal : 1;
|
bool includeInSymtab : 1;
|
||||||
|
|
||||||
private:
|
private:
|
||||||
const bool weakDef : 1;
|
const bool weakDef : 1;
|
||||||
|
|
|
@ -53,7 +53,12 @@ SyntheticSection::SyntheticSection(const char *segname, const char *name)
|
||||||
// dyld3's MachOLoaded::getSlide() assumes that the __TEXT segment starts
|
// dyld3's MachOLoaded::getSlide() assumes that the __TEXT segment starts
|
||||||
// from the beginning of the file (i.e. the header).
|
// from the beginning of the file (i.e. the header).
|
||||||
MachHeaderSection::MachHeaderSection()
|
MachHeaderSection::MachHeaderSection()
|
||||||
: SyntheticSection(segment_names::text, section_names::header) {}
|
: SyntheticSection(segment_names::text, section_names::header) {
|
||||||
|
// XXX: This is a hack. (See D97007)
|
||||||
|
// Setting the index to 1 to pretend that this section is the text
|
||||||
|
// section.
|
||||||
|
index = 1;
|
||||||
|
}
|
||||||
|
|
||||||
void MachHeaderSection::addLoadCommand(LoadCommand *lc) {
|
void MachHeaderSection::addLoadCommand(LoadCommand *lc) {
|
||||||
loadCommands.push_back(lc);
|
loadCommands.push_back(lc);
|
||||||
|
@ -754,7 +759,7 @@ void SymtabSection::finalizeContents() {
|
||||||
|
|
||||||
for (Symbol *sym : symtab->getSymbols()) {
|
for (Symbol *sym : symtab->getSymbols()) {
|
||||||
if (auto *defined = dyn_cast<Defined>(sym)) {
|
if (auto *defined = dyn_cast<Defined>(sym)) {
|
||||||
if (defined->linkerInternal)
|
if (!defined->includeInSymtab)
|
||||||
continue;
|
continue;
|
||||||
assert(defined->isExternal());
|
assert(defined->isExternal());
|
||||||
addSymbol(externalSymbols, defined);
|
addSymbol(externalSymbols, defined);
|
||||||
|
@ -993,3 +998,56 @@ void CodeSignatureSection::writeTo(uint8_t *buf) const {
|
||||||
memcpy(id, fileName.begin(), fileName.size());
|
memcpy(id, fileName.begin(), fileName.size());
|
||||||
memset(id + fileName.size(), 0, fileNamePad);
|
memset(id + fileName.size(), 0, fileNamePad);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void macho::createSyntheticSymbols() {
|
||||||
|
auto addHeaderSymbol = [](const char *name) {
|
||||||
|
symtab->addSynthetic(name, in.header->isec, 0,
|
||||||
|
/*privateExtern=*/true,
|
||||||
|
/*includeInSymtab*/ false);
|
||||||
|
};
|
||||||
|
|
||||||
|
switch (config->outputType) {
|
||||||
|
// FIXME: Assign the right addresse value for these symbols
|
||||||
|
// (rather than 0). But we need to do that after assignAddresses().
|
||||||
|
case MH_EXECUTE:
|
||||||
|
// If linking PIE, __mh_execute_header is a defined symbol in
|
||||||
|
// __TEXT, __text)
|
||||||
|
// Otherwise, it's an absolute symbol.
|
||||||
|
if (config->isPic)
|
||||||
|
symtab->addSynthetic("__mh_execute_header", in.header->isec, 0,
|
||||||
|
/*privateExtern*/ false,
|
||||||
|
/*includeInSymbtab*/ true);
|
||||||
|
else
|
||||||
|
symtab->addSynthetic("__mh_execute_header",
|
||||||
|
/*isec*/ nullptr, 0,
|
||||||
|
/*privateExtern*/ false,
|
||||||
|
/*includeInSymbtab*/ true);
|
||||||
|
break;
|
||||||
|
|
||||||
|
// The following symbols are N_SECT symbols, even though the header is not
|
||||||
|
// part of any section and that they are private to the bundle/dylib/object
|
||||||
|
// they are part of.
|
||||||
|
case MH_BUNDLE:
|
||||||
|
addHeaderSymbol("__mh_bundle_header");
|
||||||
|
break;
|
||||||
|
case MH_DYLIB:
|
||||||
|
addHeaderSymbol("__mh_dylib_header");
|
||||||
|
break;
|
||||||
|
case MH_DYLINKER:
|
||||||
|
addHeaderSymbol("__mh_dylinker_header");
|
||||||
|
break;
|
||||||
|
case MH_OBJECT:
|
||||||
|
addHeaderSymbol("__mh_object_header");
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
llvm_unreachable("unexpected outputType");
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
// The Itanium C++ ABI requires dylibs to pass a pointer to __cxa_atexit
|
||||||
|
// which does e.g. cleanup of static global variables. The ABI document
|
||||||
|
// says that the pointer can point to any address in one of the dylib's
|
||||||
|
// segments, but in practice ld64 seems to set it to point to the header,
|
||||||
|
// so that's what's implemented here.
|
||||||
|
addHeaderSymbol("___dso_handle");
|
||||||
|
}
|
||||||
|
|
|
@ -500,6 +500,8 @@ struct InStruct {
|
||||||
extern InStruct in;
|
extern InStruct in;
|
||||||
extern std::vector<SyntheticSection *> syntheticSections;
|
extern std::vector<SyntheticSection *> syntheticSections;
|
||||||
|
|
||||||
|
void createSyntheticSymbols();
|
||||||
|
|
||||||
} // namespace macho
|
} // namespace macho
|
||||||
} // namespace lld
|
} // namespace lld
|
||||||
|
|
||||||
|
|
|
@ -751,7 +751,6 @@ static void sortSegmentsAndSections() {
|
||||||
// output section indices.
|
// output section indices.
|
||||||
if (!osec->isHidden())
|
if (!osec->isHidden())
|
||||||
osec->index = ++sectionIndex;
|
osec->index = ++sectionIndex;
|
||||||
|
|
||||||
if (!firstTLVDataSection && isThreadLocalData(osec->flags))
|
if (!firstTLVDataSection && isThreadLocalData(osec->flags))
|
||||||
firstTLVDataSection = osec;
|
firstTLVDataSection = osec;
|
||||||
|
|
||||||
|
|
|
@ -15,7 +15,9 @@
|
||||||
# EXPORTS-DAG: [[#%x, HELLO_WORLD_ADDR:]] {{.*}} _hello_world
|
# EXPORTS-DAG: [[#%x, HELLO_WORLD_ADDR:]] {{.*}} _hello_world
|
||||||
# EXPORTS-DAG: [[#%x, HELLO_ITS_ME_ADDR:]] {{.*}} _hello_its_me
|
# EXPORTS-DAG: [[#%x, HELLO_ITS_ME_ADDR:]] {{.*}} _hello_its_me
|
||||||
# EXPORTS-DAG: [[#%x, HELLO_ITS_YOU_ADDR:]] {{.*}} _hello_its_you
|
# EXPORTS-DAG: [[#%x, HELLO_ITS_YOU_ADDR:]] {{.*}} _hello_its_you
|
||||||
|
# EXPORTS-DAG: {{0+}} g *ABS* __mh_execute_header
|
||||||
# EXPORTS-LABEL: Exports trie:
|
# EXPORTS-LABEL: Exports trie:
|
||||||
|
# EXPORTS-DAG: 0x{{0+}} __mh_execute_header [absolute]
|
||||||
# EXPORTS-DAG: 0x{{0*}}[[#%X, MAIN_ADDR]] _main
|
# EXPORTS-DAG: 0x{{0*}}[[#%X, MAIN_ADDR]] _main
|
||||||
# EXPORTS-DAG: 0x{{0*}}[[#%X, HELLO_ADDR]] _hello
|
# EXPORTS-DAG: 0x{{0*}}[[#%X, HELLO_ADDR]] _hello
|
||||||
# EXPORTS-DAG: 0x{{0*}}[[#%X, HELLO_WORLD_ADDR]] _hello_world
|
# EXPORTS-DAG: 0x{{0*}}[[#%X, HELLO_WORLD_ADDR]] _hello_world
|
||||||
|
@ -27,13 +29,16 @@
|
||||||
# CHECK-LABEL: ExportTrie:
|
# CHECK-LABEL: ExportTrie:
|
||||||
# CHECK: Name: ''
|
# CHECK: Name: ''
|
||||||
# CHECK: Name: _
|
# CHECK: Name: _
|
||||||
# CHECK: Name: main
|
# CHECK-DAG: Name: _mh_execute_header
|
||||||
# CHECK: Name: hello
|
# CHECK-DAG: Name: main
|
||||||
|
# CHECK-DAG: Name: hello
|
||||||
# CHECK: Name: _
|
# CHECK: Name: _
|
||||||
# CHECK: Name: world
|
# CHECK: Name: world
|
||||||
# CHECK: Name: its_
|
# CHECK: Name: its_
|
||||||
# CHECK: Name: you
|
# CHECK-DAG: Name: you
|
||||||
# CHECK: Name: me
|
# CHECK-DAG: Name: me
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
.section __TEXT,__cstring
|
.section __TEXT,__cstring
|
||||||
.globl _hello, _hello_world, _hello_its_me, _hello_its_you, _main
|
.globl _hello, _hello_world, _hello_its_me, _hello_its_you, _main
|
||||||
|
|
|
@ -29,6 +29,7 @@ _main:
|
||||||
# CHECK-NEXT: [[#%x,MAIN:]] g F __TEXT,__text _main
|
# CHECK-NEXT: [[#%x,MAIN:]] g F __TEXT,__text _main
|
||||||
# CHECK-NEXT: [[#%x,NUMBER:]] g O __DATA,__common _number
|
# CHECK-NEXT: [[#%x,NUMBER:]] g O __DATA,__common _number
|
||||||
# CHECK-NEXT: [[#%x,FOO:]] g O __TEXT,obj _foo
|
# CHECK-NEXT: [[#%x,FOO:]] g O __TEXT,obj _foo
|
||||||
|
# CHECK-NEXT: {{0+}} g *ABS* __mh_execute_header
|
||||||
|
|
||||||
# CHECK-NEXT: # Path: {{.*}}{{/|\\}}map-file.s.tmp/test-map
|
# CHECK-NEXT: # Path: {{.*}}{{/|\\}}map-file.s.tmp/test-map
|
||||||
# CHECK-NEXT: # Arch: x86_64
|
# CHECK-NEXT: # Arch: x86_64
|
||||||
|
|
|
@ -0,0 +1,16 @@
|
||||||
|
# REQUIRES: x86
|
||||||
|
# RUN: rm -rf %t; mkdir %t
|
||||||
|
# RUN: llvm-mc -filetype=obj -triple=x86_64-apple-darwin %s -o %t/test.o
|
||||||
|
# RUN: %lld -o %t/test.pie %t/test.o -pie
|
||||||
|
# RUN: llvm-objdump --macho --syms %t/test.pie | FileCheck %s --check-prefix=PIE
|
||||||
|
|
||||||
|
# RUN: %lld -o %t/test.no_pie %t/test.o -no_pie
|
||||||
|
# RUN: llvm-objdump --macho --syms %t/test.no_pie | FileCheck %s --check-prefix=NO-PIE
|
||||||
|
|
||||||
|
# PIE: 0000000100000000 g F __TEXT,__text __mh_execute_header
|
||||||
|
# NO-PIE: 0000000000000000 g *ABS* __mh_execute_header
|
||||||
|
|
||||||
|
.text
|
||||||
|
.global _main
|
||||||
|
_main:
|
||||||
|
ret
|
|
@ -0,0 +1,43 @@
|
||||||
|
# REQUIRES: x86
|
||||||
|
|
||||||
|
## This tests that we can link against these synthetic symbols even
|
||||||
|
## if they are not in the symbol table.
|
||||||
|
|
||||||
|
# RUN: rm -rf %t; split-file %s %t
|
||||||
|
|
||||||
|
## Test that in a dylib, we can link against __mh_dylib_header
|
||||||
|
## (but not in other types of files)
|
||||||
|
|
||||||
|
# RUN: llvm-mc %t/dylib.s -triple=x86_64-apple-macos11.0 -filetype=obj -o %t/dylib.o
|
||||||
|
# RUN: %lld -pie -dylib %t/dylib.o -o %t/dylib.out
|
||||||
|
# RUN: llvm-objdump -m --syms %t/dylib.out | FileCheck %s --check-prefix DYLIB
|
||||||
|
|
||||||
|
# RUN: not %lld -pie -o /dev/null %t/dylib.o 2>&1 | FileCheck %s --check-prefix ERR-DYLIB
|
||||||
|
|
||||||
|
# DYLIB: SYMBOL TABLE:
|
||||||
|
# DYLIB-NEXT: {{[0-9a-f]+}} g F __TEXT,__text _main
|
||||||
|
# DYLIB-NEXT-EMPTY:
|
||||||
|
# ERR-DYLIB: error: undefined symbol: __mh_dylib_header
|
||||||
|
|
||||||
|
## Test that in an executable, we can link against __mh_execute_header
|
||||||
|
# RUN: llvm-mc %t/main.s -triple=x86_64-apple-macos11.0 -filetype=obj -o %t/exec.o
|
||||||
|
# RUN: %lld -pie %t/exec.o -o %t/exec.out
|
||||||
|
|
||||||
|
## But it would be an error trying to reference __mh_execute_header in a dylib
|
||||||
|
# RUN: not %lld -pie -o /dev/null -dylib %t/exec.o 2>&1 | FileCheck %s --check-prefix ERR-EXEC
|
||||||
|
|
||||||
|
# ERR-EXEC: error: undefined symbol: __mh_execute_header
|
||||||
|
|
||||||
|
#--- main.s
|
||||||
|
.text
|
||||||
|
.globl _main
|
||||||
|
_main:
|
||||||
|
mov __mh_execute_header@GOTPCREL(%rip), %rax
|
||||||
|
ret
|
||||||
|
|
||||||
|
#--- dylib.s
|
||||||
|
.text
|
||||||
|
.globl _main
|
||||||
|
_main:
|
||||||
|
mov __mh_dylib_header@GOTPCREL(%rip), %rax
|
||||||
|
ret
|
|
@ -32,7 +32,7 @@
|
||||||
# NO-OBJC-EMPTY:
|
# NO-OBJC-EMPTY:
|
||||||
# NO-OBJC-NEXT: SYMBOL TABLE:
|
# NO-OBJC-NEXT: SYMBOL TABLE:
|
||||||
# NO-OBJC-NEXT: g F __TEXT,__text _main
|
# NO-OBJC-NEXT: g F __TEXT,__text _main
|
||||||
# NO-OBJC-EMPTY:
|
# NO_OBJC-NEXT: g *ABS* __mh_execute_header
|
||||||
|
|
||||||
#--- has-objc-symbol.s
|
#--- has-objc-symbol.s
|
||||||
.globl _OBJC_CLASS_$_MyObject
|
.globl _OBJC_CLASS_$_MyObject
|
||||||
|
|
|
@ -60,6 +60,7 @@
|
||||||
# CHECK-NEXT: [[#ZERO]] S _zero
|
# CHECK-NEXT: [[#ZERO]] S _zero
|
||||||
# CHECK-NEXT: [[#FOO]] T _foo
|
# CHECK-NEXT: [[#FOO]] T _foo
|
||||||
# CHECK-NEXT: {{[0-9af]+}} T _no_debug
|
# CHECK-NEXT: {{[0-9af]+}} T _no_debug
|
||||||
|
# CHECK-NEXT: {{0+}} A __mh_execute_header
|
||||||
# CHECK-EMPTY:
|
# CHECK-EMPTY:
|
||||||
|
|
||||||
## Check that we don't attempt to emit rebase opcodes for the debug sections
|
## Check that we don't attempt to emit rebase opcodes for the debug sections
|
||||||
|
|
|
@ -56,6 +56,16 @@
|
||||||
# CHECK-NEXT: ]
|
# CHECK-NEXT: ]
|
||||||
# CHECK-NEXT: Value: 0x1{{[0-9a-f]*}}
|
# CHECK-NEXT: Value: 0x1{{[0-9a-f]*}}
|
||||||
# CHECK-NEXT: }
|
# CHECK-NEXT: }
|
||||||
|
# CHECK-NEXT: Symbol {
|
||||||
|
# CHECK-NEXT: Name: __mh_execute_header (81)
|
||||||
|
# CHECK-NEXT: Extern
|
||||||
|
# CHECK-NEXT: Type: Abs (0x2)
|
||||||
|
# CHECK-NEXT: Section: (0x0)
|
||||||
|
# CHECK-NEXT: RefType: UndefinedNonLazy (0x0)
|
||||||
|
# CHECK-NEXT: Flags [ (0x0)
|
||||||
|
# CHECK-NEXT: ]
|
||||||
|
# CHECK-NEXT: Value: 0x0
|
||||||
|
# CHECK-NEXT: }
|
||||||
# CHECK-NEXT: Symbol {
|
# CHECK-NEXT: Symbol {
|
||||||
# CHECK-NEXT: Name: dyld_stub_binder
|
# CHECK-NEXT: Name: dyld_stub_binder
|
||||||
# CHECK-NEXT: Extern
|
# CHECK-NEXT: Extern
|
||||||
|
@ -82,8 +92,8 @@
|
||||||
# CHECK-NEXT: ilocalsym: 0
|
# CHECK-NEXT: ilocalsym: 0
|
||||||
# CHECK-NEXT: nlocalsym: 2
|
# CHECK-NEXT: nlocalsym: 2
|
||||||
# CHECK-NEXT: iextdefsym: 2
|
# CHECK-NEXT: iextdefsym: 2
|
||||||
# CHECK-NEXT: nextdefsym: 3
|
# CHECK-NEXT: nextdefsym: 4
|
||||||
# CHECK-NEXT: iundefsym: 5
|
# CHECK-NEXT: iundefsym: 6
|
||||||
# CHECK-NEXT: nundefsym: 2
|
# CHECK-NEXT: nundefsym: 2
|
||||||
|
|
||||||
## Verify that the first entry in the StringTable is a space, and that
|
## Verify that the first entry in the StringTable is a space, and that
|
||||||
|
|
Loading…
Reference in New Issue