mirror of
https://github.com/rui314/mold.git
synced 2024-09-21 09:57:18 +03:00
[Mach-O] Create GOT entries for external references
This commit is contained in:
parent
5837fe75eb
commit
5549a005f1
@ -43,8 +43,11 @@ static Relocation read_reloc(Context &ctx, ObjectFile &file,
|
||||
else
|
||||
unreachable();
|
||||
|
||||
bool is_gotref = (r.type == X86_64_RELOC_GOT_LOAD || r.type == X86_64_RELOC_GOT);
|
||||
|
||||
if (r.is_extern)
|
||||
return {r.offset, (bool)r.is_pcrel, addend, file.syms[r.idx], nullptr};
|
||||
return {r.offset, (bool)r.is_pcrel, is_gotref, addend, file.syms[r.idx],
|
||||
nullptr};
|
||||
|
||||
u32 addr;
|
||||
if (r.is_pcrel) {
|
||||
@ -58,7 +61,9 @@ static Relocation read_reloc(Context &ctx, ObjectFile &file,
|
||||
Subsection *target = file.sections[r.idx - 1]->find_subsection(ctx, addr);
|
||||
if (!target)
|
||||
Fatal(ctx) << file << ": bad relocation: " << r.offset;
|
||||
return {r.offset, (bool)r.is_pcrel, addr - target->input_addr, nullptr, target};
|
||||
|
||||
return {r.offset, (bool)r.is_pcrel, is_gotref, addr - target->input_addr,
|
||||
nullptr, target};
|
||||
}
|
||||
|
||||
void InputSection::parse_relocations(Context &ctx) {
|
||||
@ -88,8 +93,12 @@ void InputSection::parse_relocations(Context &ctx) {
|
||||
void InputSection::scan_relocations(Context &ctx) {
|
||||
for (Relocation &rel : rels) {
|
||||
Symbol *sym = rel.sym;
|
||||
if (sym && sym->file && sym->file->is_dylib)
|
||||
sym->needs_stub = true;
|
||||
if (sym && sym->file && sym->file->is_dylib) {
|
||||
if (rel.is_gotref)
|
||||
sym->flags |= NEEDS_GOT;
|
||||
else
|
||||
sym->flags |= NEEDS_STUB;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@ -97,15 +106,23 @@ void Subsection::apply_reloc(Context &ctx, u8 *buf) {
|
||||
for (const Relocation &rel : std::span(isec.rels).subspan(rel_offset, nrels)) {
|
||||
u32 *loc = (u32 *)(buf + rel.offset);
|
||||
|
||||
if (rel.sym) {
|
||||
*loc = rel.sym->get_addr(ctx) + rel.addend;
|
||||
} else {
|
||||
*loc = rel.subsec->isec.osec->hdr.addr + rel.subsec->output_offset +
|
||||
rel.addend;
|
||||
}
|
||||
#define S (rel.sym ? rel.sym->get_addr(ctx) : \
|
||||
rel.subsec->isec.osec->hdr.addr + rel.subsec->output_offset)
|
||||
#define A rel.addend
|
||||
#define P (isec.osec->hdr.addr + output_offset + rel.offset)
|
||||
#define G rel.sym->get_got_addr(ctx)
|
||||
|
||||
if (rel.is_pcrel)
|
||||
*loc = *loc - isec.osec->hdr.addr - output_offset - rel.offset - 4;
|
||||
if (rel.is_gotref)
|
||||
*loc = G - P - 4;
|
||||
else if (rel.is_pcrel)
|
||||
*loc = S + A - P - 4;
|
||||
else
|
||||
*loc = S + A;
|
||||
|
||||
#undef S
|
||||
#undef A
|
||||
#undef P
|
||||
#undef G
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -90,10 +90,15 @@ static void create_synthetic_chunks(Context &ctx) {
|
||||
static void export_symbols(Context &ctx) {
|
||||
ctx.got.add(ctx, intern(ctx, "dyld_stub_binder"));
|
||||
|
||||
for (DylibFile *dylib : ctx.dylibs)
|
||||
for (Symbol *sym : dylib->syms)
|
||||
if (sym->file == dylib && sym->needs_stub)
|
||||
ctx.stubs.add(ctx, sym);
|
||||
for (DylibFile *dylib : ctx.dylibs) {
|
||||
for (Symbol *sym : dylib->syms) {
|
||||
if (sym->file == dylib)
|
||||
if (sym->flags & NEEDS_STUB)
|
||||
ctx.stubs.add(ctx, sym);
|
||||
if (sym->flags & NEEDS_GOT)
|
||||
ctx.got.add(ctx, sym);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static i64 assign_offsets(Context &ctx) {
|
||||
|
@ -29,6 +29,7 @@ struct Symbol;
|
||||
struct Relocation {
|
||||
u32 offset = 0;
|
||||
bool is_pcrel = false;
|
||||
bool is_gotref = false;
|
||||
i64 addend = 0;
|
||||
Symbol *sym = nullptr;
|
||||
Subsection *subsec = nullptr;
|
||||
@ -141,6 +142,11 @@ public:
|
||||
// Symbol
|
||||
//
|
||||
|
||||
enum {
|
||||
NEEDS_GOT = 1 << 0,
|
||||
NEEDS_STUB = 1 << 1,
|
||||
};
|
||||
|
||||
struct Symbol {
|
||||
Symbol() = default;
|
||||
Symbol(std::string_view name) : name(name) {}
|
||||
@ -154,7 +160,7 @@ struct Symbol {
|
||||
i32 stub_idx = -1;
|
||||
i32 got_idx = -1;
|
||||
tbb::spin_mutex mu;
|
||||
std::atomic_bool needs_stub = false;
|
||||
std::atomic_uint8_t flags = 0;
|
||||
u8 is_extern : 1 = false;
|
||||
u8 referenced_dynamically : 1 = false;
|
||||
|
||||
|
21
test/macho/hello3.sh
Executable file
21
test/macho/hello3.sh
Executable file
@ -0,0 +1,21 @@
|
||||
#!/bin/bash
|
||||
set -e
|
||||
cd $(dirname $0)
|
||||
mold=`pwd`/../../ld64.mold
|
||||
echo -n "Testing $(basename -s .sh $0) ... "
|
||||
t=$(pwd)/../../out/test/macho/$(basename -s .sh $0)
|
||||
mkdir -p $t
|
||||
|
||||
cat <<EOF | cc -o $t/a.o -c -xc -
|
||||
#include <stdio.h>
|
||||
|
||||
int main() {
|
||||
printf("Hello");
|
||||
fprintf(stdout, " world\n");
|
||||
}
|
||||
EOF
|
||||
|
||||
clang -fuse-ld=$mold -o $t/exe $t/a.o
|
||||
$t/exe | grep -q 'Hello world'
|
||||
|
||||
echo OK
|
23
test/macho/hello4.sh
Executable file
23
test/macho/hello4.sh
Executable file
@ -0,0 +1,23 @@
|
||||
#!/bin/bash
|
||||
set -e
|
||||
cd $(dirname $0)
|
||||
mold=`pwd`/../../ld64.mold
|
||||
echo -n "Testing $(basename -s .sh $0) ... "
|
||||
t=$(pwd)/../../out/test/macho/$(basename -s .sh $0)
|
||||
mkdir -p $t
|
||||
|
||||
cat <<EOF | cc -o $t/a.o -c -xc -
|
||||
#include <stdio.h>
|
||||
|
||||
int main() {
|
||||
printf("Hello");
|
||||
fprintf(stdout, " world\n");
|
||||
fprintf(stderr, "Hello stderr\n");
|
||||
}
|
||||
EOF
|
||||
|
||||
clang -fuse-ld=$mold -o $t/exe $t/a.o
|
||||
$t/exe 2> /dev/null | grep -q 'Hello world'
|
||||
$t/exe 2>&1 > /dev/null | grep -q 'Hello stderr'
|
||||
|
||||
echo OK
|
Loading…
Reference in New Issue
Block a user