Skip to content

FreeBSD PowerPC64: fix the C++-UNO bridge, build on little-endian - #512

Merged
pgiffuni merged 5 commits into
apache:trunkfrom
pkubaj:ppc64-fix
Oct 24, 2026
Merged

pgiffuni merged 5 commits into
apache:trunkfrom
pkubaj:ppc64-fix

Conversation

@pkubaj

@pkubaj pkubaj commented Oct 23, 2026

Copy link
Copy Markdown
Contributor

Two fixes for the FreeBSD powerpc64 C++-UNO bridge, plus what
powerpc64le needs to bootstrap and to find its JRE.

  • call.s was generated on a glibc system with -fstack-protector and
    checks a canary at -28688(r13). On FreeBSD that slot holds the DTV
    pointer, which rtld replaces when a thread first uses TLS after a
    library with TLS was loaded, so a bridged call could abort in
    __stack_chk_fail (saving a document from Python was enough).
  • Under ELFv2, structs of up to 16 bytes come back in r3/r4 and structs
    of up to eight floats or doubles in f1-f8. The bridge used a hidden
    return pointer for every struct, so Basic, Python and Java got
    garbage from methods like getCellAddress(), and the bridgetest
    crashed.
  • source_soenv.sh only knew the powerpc64--freebsd triplet, so
    bootstrap failed on powerpc64le.
  • set_soenv.in and jvmfwk: OpenJDK on powerpc64le uses jre/lib/ppc64le.

Testing, FreeBSD 15.1 powerpc64le, AOO 4.1.17 built by the FreeBSD port
(which carries this bridge as local patches) with these fixes:

  • testtools bridgetest passes in-process and over URP, against the C++
    and the Java test objects (the build skips it on FreeBSD PPC, so it
    was run by hand from the build tree);
  • a PyUNO script over a pipe connection: Writer/Calc/Draw/Impress
    export and reload (odt/doc/pdf, ods/xls/csv, odg, odp/ppt), structs
    returned by value (CellAddress, CellRangeAddress, Point, Size), C++
    exceptions mapped to Python, a Python listener called back from the
    office, a Basic macro;
  • OpenJDK 8 found under jre/lib/ppc64le and started in-process.

FreeBSD 15.1 powerpc64 (big-endian), the same port and checks: the
bridgetest and the PyUNO script pass there too.

trunk at 430d157 on FreeBSD 15.1 powerpc64le, built by the FreeBSD
port editors/openoffice-devel (its local patches give the same files as
this series): it builds, and the same checks pass. The URP bridgetest
client needed -env:OOO_BASE_DIR set to the installed office, because
trunk's testtools services.rdb registers uuresolver under
$OOO_BASE_DIR/program. Since 430d157 the files this series touches
have changed only in unrelated places.

These changes were prepared with the help of an AI assistant (Claude);
the commits carry a Co-authored-by line as the ASF generative tooling
guidance suggests.

pkubaj and others added 5 commits October 23, 2026 21:57
call.s was generated by gcc on a glibc system with -fstack-protector,
so callVirtualMethod and privateSnippetExecutor keep their stack canary
at -28688(r13), the slot where glibc stores the stack guard. On FreeBSD
that slot is the first word of the thread control block, the DTV
pointer. rtld replaces the DTV when a thread first uses TLS after a
library with TLS was loaded, so a bridged call during which that
happens fails the check and aborts in __stack_chk_fail. Saving a
document from Python over the URP bridge was enough to trigger it.

Remove the canary code from both functions.

Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com>
The bridge used a hidden return pointer for every struct, but under the
ELFv2 ABI structs of up to 16 bytes come back in r3/r4, and structs made
of up to eight floats or doubles come back in f1-f8. Calling a C++
method that returns such a struct from Basic, Python or Java, e.g.
getCellAddress() or getPosition(), passed the return buffer where the
callee expected this, and the testtools bridgetest crashed.

Use return_in_hidden_param() for both call directions and for the vtable
snippets, pass f1-f8 to MapReturn(), and load f1-f8 in
privateSnippetExecutor when a C++ caller expects such a float struct.

With this the bridgetest passes on FreeBSD 15.1 powerpc64 and
powerpc64le, in-process and over URP, against both the C++ and the Java
test objects.

Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com>
source_soenv.sh only matched the powerpc64-*-freebsd* triplet, so on
powerpc64le bootstrap stopped with "unknown *Env.Set.sh for:
powerpc64le-unknown-freebsd15.1" even though configure had written
FreeBSDPPC64Env.Set.sh. Match powerpc64le-*-freebsd* too.

Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com>
OpenJDK on powerpc64le keeps its native libraries under jre/lib/ppc64le,
not jre/lib/ppc64, so on little-endian FreeBSD the linker looked for
libjawt in a directory that doesn't exist. Pick the directory from the
platform triplet.

Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com>
OpenJDK 8 on little-endian 64-bit PowerPC installs libjvm.so under
jre/lib/ppc64le, so a Java 8 runtime was not recognized there. Use
"ppc64le" as JFW_PLUGIN_ARCH when OSL_BIGENDIAN is not defined, like
the MIPS entry does.

Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com>
@pgiffuni

Copy link
Copy Markdown
Contributor

Here is a quick review (from ChatGPT):
I do not see a reason to reject the overall approach: the ELFv2 return-value correction is necessary, and the reported FreeBSD tests are encouraging.

  1. High priority: homogeneous floating-point aggregate detection is too permissive
    File: main/bridges/source/cpp_uno/gcc3_freebsd_powerpc64/uno2cpp.cxx
    Function: collect_fpr_members()

The new helper recursively collects structure members and accepts a structure when every leaf member is either float or double and all leaves have the same type. It limits the total to eight members.

That is a useful starting point, but it does not verify the actual member layout or the absence of padding. The PowerPC64 ELFv2 ABI defines homogeneous aggregates in terms of the aggregate's layout as well as its element types; its specification explicitly excludes certain aggregates containing padding words. Kib

The concern is that the bridge could classify a type as an HFA based on its members even when its memory layout does not match the sequence of floating-point values the bridge subsequently copies into or out of FPRs.

Recommended change:

  • Verify member offsets and element sizes, not just member types.
  • Ensure the complete aggregate layout is compatible with the flattened sequence.
  • Reject unsupported layouts and use the ordinary aggregate-return classification instead.
  • Include inherited structures and nested structures in the tests.
    I would treat this as a classification correctness issue to resolve, rather than claiming that a specific existing UNO type is already broken.
  1. High priority: the tests should exercise both directions of every new return convention
    Files: uno2cpp.cxx, cpp2uno.cxx, call.s

The patch changes both directions of the bridge:

  • C++ calling into UNO, where the bridge must reconstruct returned values.
  • UNO calling into C++, where the bridge must capture the native return registers.
    It also introduces a special return code, TYPECLASS_FPRS = 100, to tell privateSnippetExecutor to restore floating-point return registers. That convention crosses the C++/assembly boundary, so a mismatch could be difficult to diagnose.

@pkubaj

pkubaj commented Oct 23, 2026

Copy link
Copy Markdown
Contributor Author
  1. A UNO struct can only hold UNO types, cppumaker emits no packing or alignment attributes. Checked with base LLVM on FreeBSD 15.1-RELEASE. Nested floats, inherited doubles, nested + inherited (four doubles) and eight doubles all come back in f1-fN. Nine doubles, and mixed double/float aggregates, come back in r3/r4 or through a hidden pointer, which is what return_in_fprs() and return_in_hidden_param() pick for them.
  2. Since macOS changes in August trunk has the cases for TwoFloats, AllFloats and ThreeDoubles (the last one is larger
    than 16 bytes, so it only works if it's classified as an HFA), SmallStruct, ThreeLongs, OneByte and MixedFloatLong (r3/r4), and MediumStruct and BigStruct (hidden pointer).
    Nested and inherited float structs aren't in the bridgetest. I only checked them against the compiler (above), because adding them to the bridgetest IDL means every other bridge has to pass them too. I can add them if you think that's worth it.

@pgiffuni

pgiffuni commented Oct 24, 2026 •

Copy link
Copy Markdown
Contributor
  1. It doesn't hurt to be more robust here; I think the code is OK as it is, but if you see instability, this might be something to look at in a future revision.

FWIW, ChatGPT had other suggestions as well which are not critical.

@pgiffuni
pgiffuni merged commit 22994af into apache:trunk Oct 24, 2026
1 check passed
@pkubaj
pkubaj deleted the ppc64-fix branch October 24, 2026 09:23
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants