Skip to content

Commit

Permalink
[PPC64V2] Emit _savegpr0_*, _restgpr0_*, _savegpr1_* and _restgpr1_* …
Browse files Browse the repository at this point in the history
…symbols

Fixes #1203
  • Loading branch information
rui314 committed Feb 27, 2024
1 parent 21f2554 commit d4ff48a
Show file tree
Hide file tree
Showing 4 changed files with 149 additions and 0 deletions.
100 changes: 100 additions & 0 deletions elf/arch-ppc64v2.cc
Original file line number Diff line number Diff line change
Expand Up @@ -568,6 +568,106 @@ void Thunk<E>::copy_buf(Context<E> &ctx) {
}
}

// GCC may emit references to the following functions in function prologue
// and epiilogue if -Os is specified. For some reason, these functions are
// not in libgcc.a and expected to be synthesized by the linker.
const std::vector<std::pair<std::string_view, u32>>
ppc64_save_restore_insns = {
{ "_savegpr0_14", 0xf9c1ff70 }, // std r14,-144(r1)
{ "_savegpr0_15", 0xf9e1ff78 }, // std r15,-136(r1)
{ "_savegpr0_16", 0xfa01ff80 }, // std r16,-128(r1)
{ "_savegpr0_17", 0xfa21ff88 }, // std r17,-120(r1)
{ "_savegpr0_18", 0xfa41ff90 }, // std r18,-112(r1)
{ "_savegpr0_19", 0xfa61ff98 }, // std r19,-104(r1)
{ "_savegpr0_20", 0xfa81ffa0 }, // std r20,-96(r1)
{ "_savegpr0_21", 0xfaa1ffa8 }, // std r21,-88(r1)
{ "_savegpr0_22", 0xfac1ffb0 }, // std r22,-80(r1)
{ "_savegpr0_23", 0xfae1ffb8 }, // std r23,-72(r1)
{ "_savegpr0_24", 0xfb01ffc0 }, // std r24,-64(r1)
{ "_savegpr0_25", 0xfb21ffc8 }, // std r25,-56(r1)
{ "_savegpr0_26", 0xfb41ffd0 }, // std r26,-48(r1)
{ "_savegpr0_27", 0xfb61ffd8 }, // std r27,-40(r1)
{ "_savegpr0_28", 0xfb81ffe0 }, // std r28,-32(r1)
{ "_savegpr0_29", 0xfba1ffe8 }, // std r29,-24(r1)
{ "_savegpr0_30", 0xfbc1fff0 }, // std r30,-16(r1)
{ "_savegpr0_31", 0xfbe1fff8 }, // std r31,-8(r1)
{ "", 0xf8010010 }, // std r0,16(r1)
{ "", 0x4e800020 }, // blr

{ "_restgpr0_14", 0xe9c1ff70 }, // ld r14,-144(r1)
{ "_restgpr0_15", 0xe9e1ff78 }, // ld r15,-136(r1)
{ "_restgpr0_16", 0xea01ff80 }, // ld r16,-128(r1)
{ "_restgpr0_17", 0xea21ff88 }, // ld r17,-120(r1)
{ "_restgpr0_18", 0xea41ff90 }, // ld r18,-112(r1)
{ "_restgpr0_19", 0xea61ff98 }, // ld r19,-104(r1)
{ "_restgpr0_20", 0xea81ffa0 }, // ld r20,-96(r1)
{ "_restgpr0_21", 0xeaa1ffa8 }, // ld r21,-88(r1)
{ "_restgpr0_22", 0xeac1ffb0 }, // ld r22,-80(r1)
{ "_restgpr0_23", 0xeae1ffb8 }, // ld r23,-72(r1)
{ "_restgpr0_24", 0xeb01ffc0 }, // ld r24,-64(r1)
{ "_restgpr0_25", 0xeb21ffc8 }, // ld r25,-56(r1)
{ "_restgpr0_26", 0xeb41ffd0 }, // ld r26,-48(r1)
{ "_restgpr0_27", 0xeb61ffd8 }, // ld r27,-40(r1)
{ "_restgpr0_28", 0xeb81ffe0 }, // ld r28,-32(r1)
{ "_restgpr0_29", 0xe8010010 }, // ld r0,16(r1)
{ "", 0xeba1ffe8 }, // ld r29,-24(r1)
{ "", 0x7c0803a6 }, // mtlr r0
{ "", 0xebc1fff0 }, // ld r30,-16(r1)
{ "", 0xebe1fff8 }, // ld r31,-8(r1)
{ "", 0x4e800020 }, // blr
{ "_restgpr0_30", 0xebc1fff0 }, // ld r30,-16(r1)
{ "_restgpr0_31", 0xe8010010 }, // ld r0,16(r1)
{ "", 0xebe1fff8 }, // ld r31,-8(r1)
{ "", 0x7c0803a6 }, // mtlr r0
{ "", 0x4e800020 }, // blr

{ "_savegpr1_14", 0xf9ccff70 }, // std r14,-144(r12)
{ "_savegpr1_15", 0xf9ecff78 }, // std r15,-136(r12)
{ "_savegpr1_16", 0xfa0cff80 }, // std r16,-128(r12)
{ "_savegpr1_17", 0xfa2cff88 }, // std r17,-120(r12)
{ "_savegpr1_18", 0xfa4cff90 }, // std r18,-112(r12)
{ "_savegpr1_19", 0xfa6cff98 }, // std r19,-104(r12)
{ "_savegpr1_20", 0xfa8cffa0 }, // std r20,-96(r12)
{ "_savegpr1_21", 0xfaacffa8 }, // std r21,-88(r12)
{ "_savegpr1_22", 0xfaccffb0 }, // std r22,-80(r12)
{ "_savegpr1_23", 0xfaecffb8 }, // std r23,-72(r12)
{ "_savegpr1_24", 0xfb0cffc0 }, // std r24,-64(r12)
{ "_savegpr1_25", 0xfb2cffc8 }, // std r25,-56(r12)
{ "_savegpr1_26", 0xfb4cffd0 }, // std r26,-48(r12)
{ "_savegpr1_27", 0xfb6cffd8 }, // std r27,-40(r12)
{ "_savegpr1_28", 0xfb8cffe0 }, // std r28,-32(r12)
{ "_savegpr1_29", 0xfbacffe8 }, // std r29,-24(r12)
{ "_savegpr1_30", 0xfbccfff0 }, // std r30,-16(r12)
{ "_savegpr1_31", 0xfbecfff8 }, // std r31,-8(r12)
{ "", 0x4e800020 }, // blr

{ "_restgpr1_14", 0xe9ccff70 }, // ld r14,-144(r12)
{ "_restgpr1_15", 0xe9ecff78 }, // ld r15,-136(r12)
{ "_restgpr1_16", 0xea0cff80 }, // ld r16,-128(r12)
{ "_restgpr1_17", 0xea2cff88 }, // ld r17,-120(r12)
{ "_restgpr1_18", 0xea4cff90 }, // ld r18,-112(r12)
{ "_restgpr1_19", 0xea6cff98 }, // ld r19,-104(r12)
{ "_restgpr1_20", 0xea8cffa0 }, // ld r20,-96(r12)
{ "_restgpr1_21", 0xeaacffa8 }, // ld r21,-88(r12)
{ "_restgpr1_22", 0xeaccffb0 }, // ld r22,-80(r12)
{ "_restgpr1_23", 0xeaecffb8 }, // ld r23,-72(r12)
{ "_restgpr1_24", 0xeb0cffc0 }, // ld r24,-64(r12)
{ "_restgpr1_25", 0xeb2cffc8 }, // ld r25,-56(r12)
{ "_restgpr1_26", 0xeb4cffd0 }, // ld r26,-48(r12)
{ "_restgpr1_27", 0xeb6cffd8 }, // ld r27,-40(r12)
{ "_restgpr1_28", 0xeb8cffe0 }, // ld r28,-32(r12)
{ "_restgpr1_29", 0xebacffe8 }, // ld r29,-24(r12)
{ "_restgpr1_30", 0xebccfff0 }, // ld r30,-16(r12)
{ "_restgpr1_31", 0xebecfff8 }, // ld r31,-8(r12)
{ "", 0x4e800020 }, // blr
};

void PPC64SaveRestoreSection::copy_buf(Context<E> &ctx) {
ul32 *buf = (ul32 *)(ctx.buf + this->shdr.sh_offset);
for (auto [label, insn] : ppc64_save_restore_insns)
*buf++ = insn;
}

template <>
u64 get_eflags(Context<E> &ctx) {
return 2;
Expand Down
17 changes: 17 additions & 0 deletions elf/mold.h
Original file line number Diff line number Diff line change
Expand Up @@ -1470,6 +1470,22 @@ class PPC64OpdSection : public Chunk<PPC64V1> {
// arch-ppc64v2.cc
//

extern const std::vector<std::pair<std::string_view, u32>>
ppc64_save_restore_insns;

class PPC64SaveRestoreSection : public Chunk<PPC64V2> {
public:
PPC64SaveRestoreSection() {
this->name = ".save_restore_gprs";
this->shdr.sh_type = SHT_PROGBITS;
this->shdr.sh_flags = SHF_ALLOC | SHF_EXECINSTR;
this->shdr.sh_addralign = 16;
this->shdr.sh_size = ppc64_save_restore_insns.size() * 4;
}

void copy_buf(Context<PPC64V2> &ctx) override;
};

template <> u64 get_eflags(Context<PPC64V2> &ctx);

//
Expand Down Expand Up @@ -1594,6 +1610,7 @@ struct ContextExtras<PPC64V1> {

template <>
struct ContextExtras<PPC64V2> {
PPC64SaveRestoreSection *save_restore = nullptr;
Symbol<PPC64V2> *TOC = nullptr;
Atomic<bool> is_power10 = false;
};
Expand Down
20 changes: 20 additions & 0 deletions elf/passes.cc
Original file line number Diff line number Diff line change
Expand Up @@ -177,6 +177,9 @@ void create_synthetic_sections(Context<E> &ctx) {
if constexpr (is_ppc64v1<E>)
ctx.extra.opd = push(new PPC64OpdSection);

if constexpr (is_ppc64v2<E>)
ctx.extra.save_restore = push(new PPC64SaveRestoreSection);

if constexpr (is_sparc<E>) {
if (ctx.arg.is_static)
ctx.extra.tls_get_addr_sec = push(new SparcTlsGetAddrSection);
Expand Down Expand Up @@ -824,6 +827,11 @@ void add_synthetic_symbols(Context<E> &ctx) {
}
}

if constexpr (is_ppc64v2<E>)
for (auto [label, insn] : ppc64_save_restore_insns)
if (!label.empty())
add(label);

obj.elf_syms = ctx.internal_esyms;
obj.has_symver.resize(ctx.internal_esyms.size() - 1);

Expand Down Expand Up @@ -2766,6 +2774,18 @@ void fix_synthetic_symbols(Context<E> &ctx) {
}
}

// PPC64's _{save,rest}gpr{0,1}_{14,15,16,...,31} symbols
if constexpr (is_ppc64v2<E>) {
i64 offset = 0;
for (auto [label, insn] : ppc64_save_restore_insns) {
if (!label.empty())
if (Symbol<E> *sym = get_symbol(ctx, label);
sym->file == ctx.internal_obj)
start(sym, ctx.extra.save_restore, offset);
offset += 4;
}
}

// __start_ and __stop_ symbols
for (Chunk<E> *chunk : sections) {
if (std::optional<std::string> name = get_start_stop_name(ctx, *chunk)) {
Expand Down
12 changes: 12 additions & 0 deletions test/elf/ppc64le_save_restore_gprs.sh
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
#!/bin/bash
. $(dirname $0)/common.inc

cat <<EOF | $CC -o $t/a.o -c -xc -
#include <stdio.h>
int main() {
printf("Hello world\n");
}
EOF

$CC -B. -o $t/exe $t/a.o
$OBJDUMP -d $t/exe | grep -q '<_savegpr0_14>'

0 comments on commit d4ff48a

Please sign in to comment.