1
1
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:
Rui Ueyama 2021-10-26 16:57:20 +09:00
parent 5837fe75eb
commit 5549a005f1
5 changed files with 89 additions and 17 deletions

View File

@ -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
}
}

View File

@ -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) {

View File

@ -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
View 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
View 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