Skip to content

Commit

Permalink
Revert "Merge .alpha_got with .got"
Browse files Browse the repository at this point in the history
This reverts commit 72671df.
  • Loading branch information
rui314 committed Jul 14, 2023
1 parent cb08466 commit f8b5568
Show file tree
Hide file tree
Showing 4 changed files with 118 additions and 77 deletions.
70 changes: 68 additions & 2 deletions elf/arch-alpha.cc
Original file line number Diff line number Diff line change
Expand Up @@ -110,7 +110,7 @@ void InputSection<E>::apply_reloc_alloc(Context<E> &ctx, u8 *base) {
break;
case R_ALPHA_LITERAL:
if (A)
*(ul16 *)loc = ctx.got->get_gota_addr(ctx, &sym, A) - GP;
*(ul16 *)loc = ctx.extra.got->get_addr(sym, A) - GP;
else
*(ul16 *)loc = GOT + G - GP;
break;
Expand Down Expand Up @@ -222,7 +222,7 @@ void InputSection<E>::scan_relocations(Context<E> &ctx) {
break;
case R_ALPHA_LITERAL:
if (rel.r_addend)
ctx.got->add_gota_symbol(ctx, &sym, rel.r_addend);
ctx.extra.got->add_symbol(sym, rel.r_addend);
else
sym.flags |= NEEDS_GOT;
break;
Expand Down Expand Up @@ -261,4 +261,70 @@ void InputSection<E>::scan_relocations(Context<E> &ctx) {
}
}

// An R_ALPHA_LITERAL relocation may request the linker to create a GOT
// entry for an external symbol with a non-zero addend. This is an unusual
// request which is not found in any other targets.
//
// Referring an external symbol with a non-zero addend is a bad practice
// because we need to create as many dynamic relocations as the number of
// distinctive addends for the same symbol.
//
// We don't want to mess up the implementation of the common GOT section
// for Alpha. So we create another GOT-like section, .alpha_got. Any GOT
// entry for an R_ALPHA_LITERAL reloc with a non-zero addend is created
// not in .got but in .alpha_got.
//
// Since .alpha_got entries are accessed relative to GP, .alpha_got
// needs to be close enough to .got. It's actually placed next to .got.
void AlphaGotSection::add_symbol(Symbol<E> &sym, i64 addend) {
assert(addend);
std::scoped_lock lock(mu);
entries.push_back({&sym, addend});
}

bool operator<(const AlphaGotSection::Entry &a, const AlphaGotSection::Entry &b) {
return std::tuple(a.sym->file->priority, a.sym->sym_idx, a.addend) <
std::tuple(b.sym->file->priority, b.sym->sym_idx, b.addend);
};

u64 AlphaGotSection::get_addr(Symbol<E> &sym, i64 addend) {
auto it = std::lower_bound(entries.begin(), entries.end(), Entry{&sym, addend});
assert(it != entries.end());
return this->shdr.sh_addr + (it - entries.begin()) * sizeof(Word<E>);
}

i64 AlphaGotSection::get_reldyn_size(Context<E> &ctx) const {
i64 n = 0;
for (const Entry &e : entries)
if (e.sym->is_imported || (ctx.arg.pic && !e.sym->is_absolute()))
n++;
return n;
}

void AlphaGotSection::finalize() {
sort(entries);
remove_duplicates(entries);
shdr.sh_size = entries.size() * sizeof(Word<E>);
}

void AlphaGotSection::copy_buf(Context<E> &ctx) {
ElfRel<E> *dynrel = (ElfRel<E> *)(ctx.buf + ctx.reldyn->shdr.sh_offset +
reldyn_offset);

for (i64 i = 0; i < entries.size(); i++) {
Entry &e = entries[i];
u64 P = this->shdr.sh_addr + sizeof(Word<E>) * i;
ul64 *buf = (ul64 *)(ctx.buf + this->shdr.sh_offset + sizeof(Word<E>) * i);

if (e.sym->is_imported) {
*buf = ctx.arg.apply_dynamic_relocs ? e.addend : 0;
*dynrel++ = ElfRel<E>(P, E::R_ABS, e.sym->get_dynsym_idx(ctx), e.addend);
} else {
*buf = e.sym->get_addr(ctx) + e.addend;
if (ctx.arg.pic && !e.sym->is_absolute())
*dynrel++ = ElfRel<E>(P, E::R_RELATIVE, 0, *buf);
}
}
}

} // namespace mold::elf
57 changes: 39 additions & 18 deletions elf/mold.h
Original file line number Diff line number Diff line change
Expand Up @@ -474,14 +474,6 @@ class OutputSection : public Chunk<E> {
std::unique_ptr<RelocSection<E>> reloc_sec;
};

template <typename E>
struct SymbolAddend {
bool operator==(const SymbolAddend &) const = default;
bool operator<(const SymbolAddend &) const;
Symbol<E> *sym;
i64 addend;
};

template <typename E>
class GotSection : public Chunk<E> {
public:
Expand All @@ -490,17 +482,19 @@ class GotSection : public Chunk<E> {
this->shdr.sh_type = SHT_PROGBITS;
this->shdr.sh_flags = SHF_ALLOC | SHF_WRITE;
this->shdr.sh_addralign = sizeof(Word<E>);
this->shdr.sh_size = NUM_RESERVED * sizeof(Word<E>);

// We always create a .got so that _GLOBAL_OFFSET_TABLE_ has
// something to point to. s390x psABI defines GOT[1] as a
// reserved slot, so we allocate one more on s390x.
this->shdr.sh_size = (is_s390x<E> ? 2 : 1) * sizeof(Word<E>);
}

void add_got_symbol(Context<E> &ctx, Symbol<E> *sym);
void add_gota_symbol(Context<E> &ctx, Symbol<E> *sym, i64 addend);
void add_gottp_symbol(Context<E> &ctx, Symbol<E> *sym);
void add_tlsgd_symbol(Context<E> &ctx, Symbol<E> *sym);
void add_tlsdesc_symbol(Context<E> &ctx, Symbol<E> *sym);
void add_tlsld(Context<E> &ctx);

u64 get_gota_addr(Context<E> &ctx, Symbol<E> *sym, i64 addend) const;
u64 get_tlsld_addr(Context<E> &ctx) const;
bool has_tlsld(Context<E> &ctx) const { return tlsld_idx != -1; }
i64 get_reldyn_size(Context<E> &ctx) const override;
Expand All @@ -510,20 +504,13 @@ class GotSection : public Chunk<E> {
void populate_symtab(Context<E> &ctx) override;

std::vector<Symbol<E> *> got_syms;
std::vector<SymbolAddend<E>> gota_syms;
std::vector<Symbol<E> *> gottp_syms;
std::vector<Symbol<E> *> tlsgd_syms;
std::vector<Symbol<E> *> tlsdesc_syms;
u32 tlsld_idx = -1;
std::mutex mu;

void construct_relr(Context<E> &ctx);
std::vector<u64> relr;

// We always create a .got so that _GLOBAL_OFFSET_TABLE_ has
// something to point to. s390x psABI defines GOT[1] as a
// reserved slot, so we allocate one more on s390x.
static constexpr i64 NUM_RESERVED = is_s390x<E> ? 2 : 1;
};

template <typename E>
Expand Down Expand Up @@ -1512,6 +1499,36 @@ class SparcTlsGetAddrSection : public Chunk<SPARC64> {
void copy_buf(Context<SPARC64> &ctx) override;
};

//
// arch-alpha.cc
//

class AlphaGotSection : public Chunk<ALPHA> {
public:
AlphaGotSection() {
this->name = ".alpha_got";
this->shdr.sh_type = SHT_PROGBITS;
this->shdr.sh_flags = SHF_ALLOC | SHF_WRITE;
this->shdr.sh_addralign = 8;
}

void add_symbol(Symbol<ALPHA> &sym, i64 addend);
void finalize();
u64 get_addr(Symbol<ALPHA> &sym, i64 addend);
i64 get_reldyn_size(Context<ALPHA> &ctx) const override;
void copy_buf(Context<ALPHA> &ctx) override;

struct Entry {
bool operator==(const Entry &) const = default;
Symbol<ALPHA> *sym;
i64 addend;
};

private:
std::vector<Entry> entries;
std::mutex mu;
};

//
// main.cc
//
Expand Down Expand Up @@ -1586,6 +1603,10 @@ template <> struct ContextExtras<SPARC64> {
Symbol<SPARC64> *tls_get_addr_sym = nullptr;
};

template <> struct ContextExtras<ALPHA> {
AlphaGotSection *got = nullptr;
};

// Context represents a context object for each invocation of the linker.
// It contains command line flags, pointers to singleton objects
// (such as linker-synthesized output sections), unique_ptrs for
Expand Down
53 changes: 2 additions & 51 deletions elf/output-chunks.cc
Original file line number Diff line number Diff line change
Expand Up @@ -200,7 +200,8 @@ bool is_relro(Context<E> &ctx, Chunk<E> *chunk) {
chunk == ctx.got || chunk == ctx.dynamic ||
chunk == ctx.relro_padding ||
(ctx.arg.z_now && ctx.gotplt && chunk == ctx.gotplt) ||
chunk->name == ".toc" || chunk->name.ends_with(".rel.ro");
chunk->name == ".alpha_got" || chunk->name == ".toc" ||
chunk->name.ends_with(".rel.ro");
return false;
}

Expand Down Expand Up @@ -1061,26 +1062,13 @@ void OutputSection<E>::populate_symtab(Context<E> &ctx) {
}
}

template <typename E>
bool SymbolAddend<E>::operator<(const SymbolAddend<E> &other) const {
return std::tuple(sym->file->priority, sym->sym_idx, addend) <
std::tuple(other.sym->file->priority, other.sym->sym_idx, other.addend);
}

template <typename E>
void GotSection<E>::add_got_symbol(Context<E> &ctx, Symbol<E> *sym) {
sym->set_got_idx(ctx, this->shdr.sh_size / sizeof(Word<E>));
this->shdr.sh_size += sizeof(Word<E>);
got_syms.push_back(sym);
}

template <typename E>
void GotSection<E>::add_gota_symbol(Context<E> &ctx, Symbol<E> *sym, i64 addend) {
assert(addend != 0);
std::scoped_lock lock(mu);
gota_syms.push_back({sym, addend});
}

template <typename E>
void GotSection<E>::add_gottp_symbol(Context<E> &ctx, Symbol<E> *sym) {
sym->set_gottp_idx(ctx, this->shdr.sh_size / sizeof(Word<E>));
Expand Down Expand Up @@ -1114,16 +1102,6 @@ void GotSection<E>::add_tlsld(Context<E> &ctx) {
this->shdr.sh_size += sizeof(Word<E>) * 2;
}

template <typename E>
u64 GotSection<E>::get_gota_addr(Context<E> &ctx, Symbol<E> *sym,
i64 addend) const {
auto it = std::lower_bound(gota_syms.begin(), gota_syms.end(),
SymbolAddend<E>{sym, addend});
assert(it != gota_syms.end());
i64 idx = it - gota_syms.begin() + NUM_RESERVED;
return this->shdr.sh_addr + idx * sizeof(Word<E>);
}

template <typename E>
u64 GotSection<E>::get_tlsld_addr(Context<E> &ctx) const {
assert(tlsld_idx != -1);
Expand Down Expand Up @@ -1161,32 +1139,6 @@ template <typename E>
static std::vector<GotEntry<E>> get_got_entries(Context<E> &ctx) {
std::vector<GotEntry<E>> entries;

// Create GOT entries for symbols with addends
for (i64 i = 0; i < ctx.got->gota_syms.size(); i++) {
SymbolAddend<E> &ent = ctx.got->gota_syms[i];
Symbol<E> *sym = ent.sym;
u64 addend = ent.addend;
i64 idx = GotSection<E>::NUM_RESERVED + i;

// If a symbol is imported, let the dynamic linker to resolve it.
if (sym->is_imported) {
entries.push_back({idx, addend, E::R_GLOB_DAT, sym});
continue;
}

// We do not allow IFUNC with addend because referring to a middle of
// a function doesn't make sense.
if constexpr (supports_ifunc<E>)
assert(!sym->is_ifunc());

// If we know an address at link-time, fill that GOT entry now.
// It may need a base relocation, though.
if (ctx.arg.pic && sym->is_relative())
entries.push_back({idx, sym->get_addr(ctx, NO_PLT) + addend, E::R_RELATIVE});
else
entries.push_back({idx, sym->get_addr(ctx, NO_PLT) + addend});
}

// Create GOT entries for ordinary symbols
for (Symbol<E> *sym : ctx.got->got_syms) {
i64 idx = sym->get_got_idx(ctx);
Expand Down Expand Up @@ -3156,7 +3108,6 @@ template class OutputShdr<E>;
template class OutputPhdr<E>;
template class InterpSection<E>;
template class OutputSection<E>;
template class SymbolAddend<E>;
template class GotSection<E>;
template class GotPltSection<E>;
template class PltSection<E>;
Expand Down
15 changes: 9 additions & 6 deletions elf/passes.cc
Original file line number Diff line number Diff line change
Expand Up @@ -123,6 +123,9 @@ void create_synthetic_sections(Context<E> &ctx) {
ctx.extra.tls_get_addr_sym = get_symbol(ctx, "__tls_get_addr");
}

if constexpr (is_alpha<E>)
ctx.extra.got = push(new AlphaGotSection);

// If .dynamic exists, .dynsym and .dynstr must exist as well
// since .dynamic refers them.
if (ctx.dynamic) {
Expand Down Expand Up @@ -1340,12 +1343,6 @@ void scan_relocations(Context<E> &ctx) {
vec[i].push_back(sym);
});

// Handle GOT-generating relocations with addends
sort(ctx.got->gota_syms);
remove_duplicates(ctx.got->gota_syms);
ctx.got->shdr.sh_size += ctx.got->gota_syms.size() * sizeof(Word<E>);

// Handle GOT-generating relocations without addends
std::vector<Symbol<E> *> syms = flatten(vec);
ctx.symbol_aux.reserve(syms.size());

Expand Down Expand Up @@ -1402,6 +1399,9 @@ void scan_relocations(Context<E> &ctx) {
if (ctx.needs_tlsld)
ctx.got->add_tlsld(ctx);

if constexpr (is_alpha<E>)
ctx.extra.got->finalize();

if (ctx.has_textrel && ctx.arg.warn_textrel)
Warn(ctx) << "creating a DT_TEXTREL in an output file";
}
Expand Down Expand Up @@ -1744,6 +1744,7 @@ void clear_padding(Context<E> &ctx) {
// <writable RELRO data>
// .got
// .toc
// .alpha_got
// <writable RELRO bss>
// .relro_padding
// <writable non-RELRO data>
Expand Down Expand Up @@ -1827,6 +1828,8 @@ void sort_output_sections_regular(Context<E> &ctx) {
return 1;
if (chunk->name == ".toc")
return 2;
if (chunk->name == ".alpha_got")
return 3;
if (chunk == ctx.relro_padding)
return INT_MAX;
return 0;
Expand Down

0 comments on commit f8b5568

Please sign in to comment.