From a95bc48985b3fb1f81ca307ce89000d4dd6aa715 Mon Sep 17 00:00:00 2001 From: Pedro Giffuni Date: Wed, 21 Oct 2026 12:18:11 -0500 Subject: [PATCH 1/2] freebsd_aarch64: Fix stack alignment and return handling Fix two issues in the FreeBSD aarch64 C++-UNO bridge: 1. abi.cxx: align_stack_offset and stack_size now use the type's natural alignment (nAlignment) and raw size (nSize) instead of hardcoded 8/alignment and 8-byte slot rounding. This matches the AAPCS64/System V ABI requirement that stack arguments use their natural alignment and size, matching the macOS reference. 2. uno2cpp.cxx: Restructure the return-value switch to use 'default' with a bSimpleReturn check (matching the macOS reference), so fill_struct is only called for register-returned aggregates, not for types that use the x8 hidden-result buffer. --- .../cpp_uno/gcc3_freebsd_aarch64/abi.cxx | 18 ++++++++---------- .../cpp_uno/gcc3_freebsd_aarch64/uno2cpp.cxx | 13 ++++++++----- 2 files changed, 16 insertions(+), 15 deletions(-) diff --git a/main/bridges/source/cpp_uno/gcc3_freebsd_aarch64/abi.cxx b/main/bridges/source/cpp_uno/gcc3_freebsd_aarch64/abi.cxx index c119e4580b..0106fd44dc 100644 --- a/main/bridges/source/cpp_uno/gcc3_freebsd_aarch64/abi.cxx +++ b/main/bridges/source/cpp_uno/gcc3_freebsd_aarch64/abi.cxx @@ -333,10 +333,13 @@ void fill_struct( typelib_TypeDescriptionReference *pTypeRef, const sal_uInt64* sal_uInt32 align_stack_offset( sal_uInt32 offset, typelib_TypeDescriptionReference *pTypeRef ) { - // On aarch64 System V ABI, the smallest stack slot is 8 bytes. - // Align to 8 bytes regardless of the type's natural alignment. - const sal_uInt32 align = 8; - return ( offset + align - 1 ) & ~( align - 1 ); + typelib_TypeDescription * pTypeDescr = 0; + TYPELIB_DANGER_GET( &pTypeDescr, pTypeRef ); + sal_uInt32 alignment = pTypeDescr->nAlignment; + TYPELIB_DANGER_RELEASE( pTypeDescr ); + if ( alignment == 0 ) + alignment = 1; + return ( offset + alignment - 1 ) & ~( alignment - 1 ); } sal_uInt32 stack_size( typelib_TypeDescriptionReference *pTypeRef ) @@ -345,12 +348,7 @@ sal_uInt32 stack_size( typelib_TypeDescriptionReference *pTypeRef ) TYPELIB_DANGER_GET( &pTypeDescr, pTypeRef ); sal_uInt32 size = pTypeDescr->nSize; TYPELIB_DANGER_RELEASE( pTypeDescr ); - // In the System V AMD64 / AAPCS64 stack layout, the smallest slot that - // can be passed is 8 bytes (the natural stack slot size). Round up - // so that small types like BOOLEAN (1B), SHORT (2B), LONG (4B) each - // occupy a full 8-byte slot on the overflow stack, matching what the - // callee's ABI expects. - return ( size + 7 ) & ~7u; + return size; } } // namespace aarch64 diff --git a/main/bridges/source/cpp_uno/gcc3_freebsd_aarch64/uno2cpp.cxx b/main/bridges/source/cpp_uno/gcc3_freebsd_aarch64/uno2cpp.cxx index 8cb8c0d517..fc754843e9 100644 --- a/main/bridges/source/cpp_uno/gcc3_freebsd_aarch64/uno2cpp.cxx +++ b/main/bridges/source/cpp_uno/gcc3_freebsd_aarch64/uno2cpp.cxx @@ -164,12 +164,15 @@ static void callVirtualMethod(void * pThis, sal_uInt32 nVtableIndex, case typelib_TypeClass_DOUBLE: *reinterpret_cast( pRegisterReturn ) = fpReturn[0]; break; - case typelib_TypeClass_STRUCT: - case typelib_TypeClass_EXCEPTION: - aarch64::fill_struct( pReturnTypeRef, &gpReturn[0], &fpReturn[0], pRegisterReturn ); - break; default: - break; + { + sal_Int32 const nRetSize = pReturnTypeRef->pType->nSize; + if (bSimpleReturn && nRetSize > 0) + { + aarch64::fill_struct( pReturnTypeRef, &gpReturn[0], &fpReturn[0], pRegisterReturn ); + } + break; + } } } From 32049e8cb674d101cf4bedff3bd7d834d31736aa Mon Sep 17 00:00:00 2001 From: Pedro Giffuni Date: Wed, 21 Oct 2026 20:20:29 -0500 Subject: [PATCH 2/2] Fix FreeBSD aarch64 C++-UNO bridge stack handling for AAPCS64 Ensure each stack argument occupies a full 8-byte slot per AAPCS64 requirements. Small types (BYTE, SHORT, LONG, BOOLEAN, etc.) are now sign/zero-extended into a sal_uInt64 scratch slot before being copied to the stack, preventing garbage values from uninitialized upper bytes. This fixes the testPackedStack BridgeTest failure where nStack was 24 instead of the expected 48, and resolves the cascading transportAny crash caused by corrupt stack values. --- .../cpp_uno/gcc3_freebsd_aarch64/abi.cxx | 4 ++ .../cpp_uno/gcc3_freebsd_aarch64/uno2cpp.cxx | 48 +++++++++++++++++-- 2 files changed, 49 insertions(+), 3 deletions(-) diff --git a/main/bridges/source/cpp_uno/gcc3_freebsd_aarch64/abi.cxx b/main/bridges/source/cpp_uno/gcc3_freebsd_aarch64/abi.cxx index 0106fd44dc..08c11c4b50 100644 --- a/main/bridges/source/cpp_uno/gcc3_freebsd_aarch64/abi.cxx +++ b/main/bridges/source/cpp_uno/gcc3_freebsd_aarch64/abi.cxx @@ -347,6 +347,10 @@ sal_uInt32 stack_size( typelib_TypeDescriptionReference *pTypeRef ) typelib_TypeDescription * pTypeDescr = 0; TYPELIB_DANGER_GET( &pTypeDescr, pTypeRef ); sal_uInt32 size = pTypeDescr->nSize; + // AAPCS64 requires each stack argument to occupy a full 8-byte + // slot; small types are sign- or zero-extended into the slot. + if ( size < 8 ) + size = 8; TYPELIB_DANGER_RELEASE( pTypeDescr ); return size; } diff --git a/main/bridges/source/cpp_uno/gcc3_freebsd_aarch64/uno2cpp.cxx b/main/bridges/source/cpp_uno/gcc3_freebsd_aarch64/uno2cpp.cxx index fc754843e9..30dbd72000 100644 --- a/main/bridges/source/cpp_uno/gcc3_freebsd_aarch64/uno2cpp.cxx +++ b/main/bridges/source/cpp_uno/gcc3_freebsd_aarch64/uno2cpp.cxx @@ -356,9 +356,51 @@ static void cpp_call( } if ( onStack ) { - nStack = aarch64::align_stack_offset( nStack, rParam.pTypeRef ); - sal_uInt32 size = aarch64::stack_size( rParam.pTypeRef ); - memcpy( pStackStart + nStack, pCppArgs[nPos], size ); + // AAPCS64: each stack argument occupies a full 8-byte slot + // with the value sign- or zero-extended. The INSERT macros + // already perform the correct extension into a GPR-sized + // (sal_uInt64) scratch slot; reuse them with a local counter. + nStack = aarch64::align_stack_offset( nStack, rParam.pTypeRef ); + sal_uInt32 size = aarch64::stack_size( rParam.pTypeRef ); + sal_uInt64 scratch[1] = {0}; + int tempNr = 0; + switch (pParamTypeDescr->eTypeClass) + { + case typelib_TypeClass_FLOAT: + INSERT_FLOAT( pCppArgs[nPos], tempNr, reinterpret_cast(scratch) ); + break; + case typelib_TypeClass_DOUBLE: + INSERT_DOUBLE( pCppArgs[nPos], tempNr, reinterpret_cast(scratch) ); + break; + case typelib_TypeClass_HYPER: + case typelib_TypeClass_UNSIGNED_HYPER: + INSERT_INT64( pCppArgs[nPos], tempNr, scratch ); + break; + case typelib_TypeClass_LONG: + INSERT_SIGNED_INT32( pCppArgs[nPos], tempNr, scratch ); + break; + case typelib_TypeClass_UNSIGNED_LONG: + case typelib_TypeClass_ENUM: + INSERT_INT32( pCppArgs[nPos], tempNr, scratch ); + break; + case typelib_TypeClass_SHORT: + INSERT_SIGNED_INT16( pCppArgs[nPos], tempNr, scratch ); + break; + case typelib_TypeClass_CHAR: + case typelib_TypeClass_UNSIGNED_SHORT: + INSERT_INT16( pCppArgs[nPos], tempNr, scratch ); + break; + case typelib_TypeClass_BYTE: + INSERT_SIGNED_INT8( pCppArgs[nPos], tempNr, scratch ); + break; + case typelib_TypeClass_BOOLEAN: + INSERT_INT8( pCppArgs[nPos], tempNr, scratch ); + break; + default: + memcpy( scratch, pCppArgs[nPos], pParamTypeDescr->nSize ); + break; + } + memcpy( pStackStart + nStack, scratch, size ); nStack += size; }