diff --git a/externals/powah/powah_emit.hpp b/externals/powah/powah_emit.hpp index bc1bfb803b..51fea03fc9 100644 --- a/externals/powah/powah_emit.hpp +++ b/externals/powah/powah_emit.hpp @@ -138,14 +138,15 @@ struct Context { } void ApplyRelocs() { - for (auto const [index, info] : relocs) { - assert(labels[index] != 0); //label must have an addr + for (auto const &[index, info] : relocs) { + //assert(labels[index] != 0); //label must have an addr + int32_t rel = (int32_t)labels[index] - (int32_t)info.offset; switch (info.kind) { case RelocKind::FormB: - base[info.offset] |= bitExt(labels[index] - info.offset, 16, 14); + base[info.offset] |= bitExt(rel, 16, 14); break; case RelocKind::FormI: - base[info.offset] |= bitExt(labels[index] - info.offset, 6, 24); + base[info.offset] |= bitExt(rel, 6, 24); break; } } @@ -176,7 +177,7 @@ struct Context { } uint32_t bitExt(uint32_t value, uint32_t offs, uint32_t n) { - uint32_t mask = (1UL << (n + 1)) - 1; + uint32_t mask = (1UL << n) - 1; return (value & mask) << (32 - (n + offs)); } void emit_XO(uint32_t op, GPR const rt, GPR const ra, GPR const rb, bool oe, bool rc) { diff --git a/externals/powah/tests.cpp b/externals/powah/tests.cpp index 6d555b4f4a..c60ce0c724 100644 --- a/externals/powah/tests.cpp +++ b/externals/powah/tests.cpp @@ -141,7 +141,19 @@ TEST_CASE("ppc64: rotldi", "[ppc64]") { REQUIRE(data[12] == EB32(0x7823837c)); } -#if 1 //&& defined(ARCHITECTURE_ppc64) +TEST_CASE("ppc64: branch-backwards", "[ppc64]") { + std::vector data(64); + powah::Context ctx(data.data(), data.size()); + powah::Label l_3 = ctx.DefineLabel(); + ctx.LABEL(l_3); + ctx.ADD(powah::R1, powah::R2, powah::R3); + ctx.B(l_3); + ctx.ApplyRelocs(); + REQUIRE(data[0] == EB32(0x141a227c)); + REQUIRE(data[1] == EB32(0xfcffff4b)); +} + +#if defined(ARCHITECTURE_ppc64) /* 0: d619637c mullw 3, 3, 3 4: 20006378 clrldi 3, 3, 32 @@ -221,6 +233,7 @@ TEST_CASE("ppc64: live-exec xoralu", "[ppc64]") { }; auto* fn = (int (*)(int, int, int))data; REQUIRE(fn(0, 1, 2) == orig(0, 1, 2)); + REQUIRE(fn(6456, 4564, 4564561) == orig(6456, 4564, 4564561)); munmap((void*)data, 4096); }