From 5f0f95a05e1dbabeb6021198208b40dc6698717f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Francisco=20Jos=C3=A9=20Garc=C3=ADa=20Garc=C3=ADa?= Date: Wed, 19 Aug 2026 19:36:40 +0200 Subject: [PATCH 1/4] Build a softfp world of the toolchain MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit softfp died as a maintained buildscripts branch in 2022 (a synced fork is expensive to keep up), but the workload didn't: github.com/vitasdk-softfp keeps shipping it for Android-to-Vita ports. Coming back as a branch risks the same drift, so VITASDK_FLOAT_ABI makes it a --with-float switch instead, inherited by gcc-base/gcc-final/newlib/pthread-embedded without touching any of their recipes. The world's identity is stamped into version_info.txt, pacman's Architecture and makepkg's CARCH so a softfp core can never be mistaken for the default one. The Sony modules are hard-float (confirmed against vitaGL's existing naked wrapper for sceGxmSetViewport). A softfp caller and a hard-float stub disagree on where 23 functions' float/double arguments and returns live. softfp-shim/ derives the AAPCS-base-to-AAPCS-VFP register move for each straight from vita-headers' real signatures, and patch-softfp-stub-archives.sh splices the generated wrapper into the already-installed stub archives: the real object gets renamed (objcopy --redefine-sym) and the wrapper takes its place under the original name. That's a library placed in front of the stubs in LIB_SPEC in an earlier version of this — it doesn't work, because GCC expands a caller's own -l flags before LIB_SPEC, and every one of these five modules is always linked explicitly by whatever package needs it. An archive splice has no such ordering to lose. Verified against a real linux/aarch64 container build: the toolchain contract passes in both directions (hard and softfp), and a link test reads the linker map to confirm all 23 shimmed symbols resolve against the wrapper, not the raw stub. --- .gitignore | 1 + CMakeLists.txt | 17 ++ cmake/WriteMakepkgConf.cmake | 19 ++ cmake/WritePacmanConfig.cmake | 6 +- cmake/create_version.cmake | 1 + cmake/recipes/BuildSdkComponents.cmake | 23 ++ cmake/recipes/FinalizeSdk.cmake | 6 + cmake/recipes/GccCommonArgs.cmake | 2 +- cmake/recipes/Provenance.cmake | 1 + scripts/build-softfp-shim.sh | 34 +++ scripts/patch-softfp-stub-archives.sh | 64 ++++++ scripts/repack-core.sh | 9 + scripts/validate-core-package.sh | 27 +++ softfp-shim/README.md | 74 +++++++ softfp-shim/functions.tsv | 23 ++ softfp-shim/generate.py | 209 ++++++++++++++++++ softfp-shim/wrappers/sceFontPixelToPointH.S | 16 ++ softfp-shim/wrappers/sceFontPixelToPointV.S | 16 ++ softfp-shim/wrappers/sceFontPointToPixelH.S | 16 ++ softfp-shim/wrappers/sceFontPointToPixelV.S | 16 ++ softfp-shim/wrappers/sceFontSetResolution.S | 12 + ...GxmDepthStencilSurfaceGetBackgroundDepth.S | 14 ++ ...GxmDepthStencilSurfaceSetBackgroundDepth.S | 11 + softfp-shim/wrappers/sceGxmSetViewport.S | 19 ++ softfp-shim/wrappers/sceGxmSetWClampValue.S | 11 + .../wrappers/sceMotionGetAngleThreshold.S | 14 ++ softfp-shim/wrappers/sceMotionRotateYaw.S | 11 + .../wrappers/sceMotionSetAngleThreshold.S | 11 + .../scePafGraphicsUpdateCurrentWave.S | 11 + softfp-shim/wrappers/scePvfPixelToPointH.S | 16 ++ softfp-shim/wrappers/scePvfPixelToPointV.S | 16 ++ softfp-shim/wrappers/scePvfPointToPixelH.S | 16 ++ softfp-shim/wrappers/scePvfPointToPixelV.S | 16 ++ softfp-shim/wrappers/scePvfSetCharSize.S | 12 + softfp-shim/wrappers/scePvfSetEM.S | 11 + softfp-shim/wrappers/scePvfSetEmboldenRate.S | 11 + softfp-shim/wrappers/scePvfSetResolution.S | 12 + softfp-shim/wrappers/scePvfSetSkewValue.S | 12 + softfp-shim/wrappers/sce_paf_strtod.S | 14 ++ tests/package/test-core-package.sh | 6 +- tests/toolchain-contract/abi.c | 8 +- tests/toolchain-contract/run.sh | 57 ++++- tests/toolchain-contract/softfp-shim.c | 56 +++++ 43 files changed, 947 insertions(+), 10 deletions(-) create mode 100644 cmake/WriteMakepkgConf.cmake create mode 100755 scripts/build-softfp-shim.sh create mode 100755 scripts/patch-softfp-stub-archives.sh create mode 100644 softfp-shim/README.md create mode 100644 softfp-shim/functions.tsv create mode 100755 softfp-shim/generate.py create mode 100644 softfp-shim/wrappers/sceFontPixelToPointH.S create mode 100644 softfp-shim/wrappers/sceFontPixelToPointV.S create mode 100644 softfp-shim/wrappers/sceFontPointToPixelH.S create mode 100644 softfp-shim/wrappers/sceFontPointToPixelV.S create mode 100644 softfp-shim/wrappers/sceFontSetResolution.S create mode 100644 softfp-shim/wrappers/sceGxmDepthStencilSurfaceGetBackgroundDepth.S create mode 100644 softfp-shim/wrappers/sceGxmDepthStencilSurfaceSetBackgroundDepth.S create mode 100644 softfp-shim/wrappers/sceGxmSetViewport.S create mode 100644 softfp-shim/wrappers/sceGxmSetWClampValue.S create mode 100644 softfp-shim/wrappers/sceMotionGetAngleThreshold.S create mode 100644 softfp-shim/wrappers/sceMotionRotateYaw.S create mode 100644 softfp-shim/wrappers/sceMotionSetAngleThreshold.S create mode 100644 softfp-shim/wrappers/scePafGraphicsUpdateCurrentWave.S create mode 100644 softfp-shim/wrappers/scePvfPixelToPointH.S create mode 100644 softfp-shim/wrappers/scePvfPixelToPointV.S create mode 100644 softfp-shim/wrappers/scePvfPointToPixelH.S create mode 100644 softfp-shim/wrappers/scePvfPointToPixelV.S create mode 100644 softfp-shim/wrappers/scePvfSetCharSize.S create mode 100644 softfp-shim/wrappers/scePvfSetEM.S create mode 100644 softfp-shim/wrappers/scePvfSetEmboldenRate.S create mode 100644 softfp-shim/wrappers/scePvfSetResolution.S create mode 100644 softfp-shim/wrappers/scePvfSetSkewValue.S create mode 100644 softfp-shim/wrappers/sce_paf_strtod.S create mode 100644 tests/toolchain-contract/softfp-shim.c diff --git a/.gitignore b/.gitignore index 5d9f7191..c071f450 100644 --- a/.gitignore +++ b/.gitignore @@ -1,4 +1,5 @@ /build_linux +/build_linux_softfp /build_mingw /.idea /build diff --git a/CMakeLists.txt b/CMakeLists.txt index 299078dd..315b62ae 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -91,6 +91,23 @@ list(APPEND CMAKE_MODULE_PATH "${PROJECT_SOURCE_DIR}/cmake") # Toolchain arch target set(target_arch arm-vita-eabi) + +# Float ABI baked into the toolchain: a build parameter, never a branch (see +# PLAN-softfp.md). Selects --with-float in the GCC configure; world_arch is +# the identity stamped into the core (pacman Architecture, makepkg CARCH, +# version_info.txt) so a softfp core can never be mistaken for the default one. +set(VITASDK_FLOAT_ABI "hard" CACHE STRING + "Float ABI baked into the toolchain: hard (default) or softfp") +set_property(CACHE VITASDK_FLOAT_ABI PROPERTY STRINGS hard softfp) +if(NOT VITASDK_FLOAT_ABI STREQUAL "hard" AND NOT VITASDK_FLOAT_ABI STREQUAL "softfp") + message(FATAL_ERROR "VITASDK_FLOAT_ABI must be 'hard' or 'softfp', got '${VITASDK_FLOAT_ABI}'") +endif() +if(VITASDK_FLOAT_ABI STREQUAL "softfp") + set(world_arch "vita-softfp") +else() + set(world_arch "vita") +endif() + # Build date string(TIMESTAMP build_date "%Y-%m-%d_%H-%M-%S") string(TIMESTAMP default_package_version "0.%Y%m%d.%H%M%S" UTC) diff --git a/cmake/WriteMakepkgConf.cmake b/cmake/WriteMakepkgConf.cmake new file mode 100644 index 00000000..dbcad89a --- /dev/null +++ b/cmake/WriteMakepkgConf.cmake @@ -0,0 +1,19 @@ +# +# Stamps the world's CARCH into the makepkg.conf shipped inside the SDK. +# vita-makepkg's own makepkg.conf.sample always says CARCH="vita": this is +# the one place that turns it into the world the core was actually built for. +# + +if(NOT DEFINED INPUT OR NOT DEFINED OUTPUT OR NOT DEFINED WORLD_ARCH) + message(FATAL_ERROR "INPUT, OUTPUT and WORLD_ARCH are required") +endif() + +file(READ "${INPUT}" contents) +string(REGEX REPLACE "\nCARCH=\"[^\"]*\"\n" "\nCARCH=\"${WORLD_ARCH}\"\n" + contents "${contents}") + +get_filename_component(output_directory "${OUTPUT}" DIRECTORY) +file(MAKE_DIRECTORY "${output_directory}") +set(temporary "${OUTPUT}.tmp") +file(WRITE "${temporary}" "${contents}") +file(RENAME "${temporary}" "${OUTPUT}") diff --git a/cmake/WritePacmanConfig.cmake b/cmake/WritePacmanConfig.cmake index eed652a4..a96f4176 100644 --- a/cmake/WritePacmanConfig.cmake +++ b/cmake/WritePacmanConfig.cmake @@ -1,5 +1,5 @@ -if(NOT DEFINED OUTPUT OR NOT DEFINED HOST_ARCHITECTURE) - message(FATAL_ERROR "OUTPUT and HOST_ARCHITECTURE are required") +if(NOT DEFINED OUTPUT OR NOT DEFINED HOST_ARCHITECTURE OR NOT DEFINED WORLD_ARCH) + message(FATAL_ERROR "OUTPUT, HOST_ARCHITECTURE and WORLD_ARCH are required") endif() get_filename_component(output_directory "${OUTPUT}" DIRECTORY) @@ -7,7 +7,7 @@ file(MAKE_DIRECTORY "${output_directory}") set(temporary "${OUTPUT}.tmp") file(WRITE "${temporary}" "[options]\n" - "Architecture = ${HOST_ARCHITECTURE} vita\n" + "Architecture = ${HOST_ARCHITECTURE} ${WORLD_ARCH}\n" "# vdpm verifies signed channel metadata and the selected database hash before use.\n" "SigLevel = Never\n") file(RENAME "${temporary}" "${OUTPUT}") diff --git a/cmake/create_version.cmake b/cmake/create_version.cmake index 3cdbde1b..adb60afd 100644 --- a/cmake/create_version.cmake +++ b/cmake/create_version.cmake @@ -7,6 +7,7 @@ file(READ ${INPUT_DIR}/pthread-embedded-version.txt _pthread_sha1) file(READ ${INPUT_DIR}/samples-version.txt _samples_sha1) file(WRITE ${OUTPUT_FILE} "Built at ${BUILD_DATE}\n") +file(APPEND ${OUTPUT_FILE} "world ${WORLD_ARCH} (float-abi=${VITASDK_FLOAT_ABI})\n") file(APPEND ${OUTPUT_FILE} "newlib ${_newlib_sha1}") file(APPEND ${OUTPUT_FILE} "pthread-embedded ${_pthread_sha1}") file(APPEND ${OUTPUT_FILE} "samples ${_samples_sha1}") diff --git a/cmake/recipes/BuildSdkComponents.cmake b/cmake/recipes/BuildSdkComponents.cmake index 3888f0ae..06b1ab87 100644 --- a/cmake/recipes/BuildSdkComponents.cmake +++ b/cmake/recipes/BuildSdkComponents.cmake @@ -25,6 +25,29 @@ ExternalProject_add(vita-headers ${UPDATE_DISCONNECTED_SUPPORT} ) +# The softfp world calls the same hard-float Sce* stubs vita-headers just +# installed, but with float/double arguments and return values sitting in +# the wrong registers (AAPCS-base vs AAPCS-VFP). Splice the 23 shims from +# softfp-shim/ into the affected stub archives in place -- see +# PLAN-softfp.md, "Fase 1 - los 23 shims de serie" and +# scripts/patch-softfp-stub-archives.sh for why this is an archive rewrite +# and not a -lvita_softfp_shim added to LIB_SPEC. +if(VITASDK_FLOAT_ABI STREQUAL "softfp") + add_custom_command( + OUTPUT ${CMAKE_BINARY_DIR}/softfp-shim.stamp + COMMAND ${PROJECT_SOURCE_DIR}/scripts/build-softfp-shim.sh + ${binutils_prefix}-gcc ${binutils_prefix}-ar ${binutils_prefix}-objcopy + ${PROJECT_SOURCE_DIR}/softfp-shim + ${CMAKE_INSTALL_PREFIX}/${target_arch}/lib + ${toolchain_build_install_dir}/${target_arch}/lib + COMMAND ${CMAKE_COMMAND} -E touch ${CMAKE_BINARY_DIR}/softfp-shim.stamp + DEPENDS vita-headers gcc-base binutils_${build_suffix} + COMMENT "Splicing the softfp ABI shims into the stub archives" + VERBATIM + ) + add_custom_target(softfp-shim ALL DEPENDS ${CMAKE_BINARY_DIR}/softfp-shim.stamp) +endif() + ExternalProject_Add(newlib DEPENDS binutils_${target_suffix} vita-headers GIT_REPOSITORY ${NEWLIB_REPOSITORY} diff --git a/cmake/recipes/FinalizeSdk.cmake b/cmake/recipes/FinalizeSdk.cmake index ea4246f0..589eaf5a 100644 --- a/cmake/recipes/FinalizeSdk.cmake +++ b/cmake/recipes/FinalizeSdk.cmake @@ -23,6 +23,7 @@ if(BUILD_PACMAN_CLIENT) COMMAND ${CMAKE_COMMAND} -DOUTPUT=${CMAKE_INSTALL_PREFIX}/etc/pacman.conf -DHOST_ARCHITECTURE=${host_published} + -DWORLD_ARCH=${world_arch} -P ${PROJECT_SOURCE_DIR}/cmake/WritePacmanConfig.cmake DEPENDS vdpm VERBATIM) @@ -43,6 +44,11 @@ set(finalize_sdk_dependencies if(BUILD_PACMAN_CLIENT) list(APPEND finalize_sdk_dependencies package-client-configuration) endif() +if(VITASDK_FLOAT_ABI STREQUAL "softfp") + # Splice the softfp shims into the stub archives before finalize-sdk + # strips them (cmake/strip_target_objects.cmake), not after. + list(APPEND finalize_sdk_dependencies softfp-shim) +endif() # Target objects are stripped where they are produced. In stage 2 they arrive # already stripped from stage 1, and the objcopy that would do it belongs to diff --git a/cmake/recipes/GccCommonArgs.cmake b/cmake/recipes/GccCommonArgs.cmake index 604f04ec..82e7c0ad 100644 --- a/cmake/recipes/GccCommonArgs.cmake +++ b/cmake/recipes/GccCommonArgs.cmake @@ -47,7 +47,7 @@ set(common_gcc_configure_args --with-arch=armv7-a --with-tune=cortex-a9 --with-fpu=neon - --with-float=hard + --with-float=${VITASDK_FLOAT_ABI} --with-mode=thumb "--with-pkgversion=${pkgversion}" ) diff --git a/cmake/recipes/Provenance.cmake b/cmake/recipes/Provenance.cmake index dd64a2a2..5590a309 100644 --- a/cmake/recipes/Provenance.cmake +++ b/cmake/recipes/Provenance.cmake @@ -25,6 +25,7 @@ if(VITASDK_STAGE1_DIR) else() add_custom_command(OUTPUT ${version_info_file} COMMAND ${CMAKE_COMMAND} -DINPUT_DIR=${CMAKE_BINARY_DIR} -DOUTPUT_FILE=${version_info_file} + -DWORLD_ARCH=${world_arch} -DVITASDK_FLOAT_ABI=${VITASDK_FLOAT_ABI} -P ${CMAKE_SOURCE_DIR}/cmake/create_version.cmake DEPENDS vita-headers vita-toolchain_${target_suffix} newlib pthread-embedded samples COMMENT "Creating version_info.txt" diff --git a/scripts/build-softfp-shim.sh b/scripts/build-softfp-shim.sh new file mode 100755 index 00000000..365bfa2b --- /dev/null +++ b/scripts/build-softfp-shim.sh @@ -0,0 +1,34 @@ +#!/usr/bin/env bash +# +# Assemble softfp-shim/wrappers/*.S and splice them into every stub archive +# they touch, in every given lib dir. See patch-softfp-stub-archives.sh for +# what "splice" means; this just does the assembling and calls it once per +# lib dir (vita-headers installs its stub archives into two places -- the +# final SDK prefix and the toolchain's own build tree -- so both need it). + +set -euo pipefail + +if [[ $# -lt 5 ]]; then + printf 'usage: %s ...\n' "$0" >&2 + exit 2 +fi + +cc=$1 +ar=$2 +objcopy=$3 +shim_dir=$4 +shift 4 + +obj_dir=$(mktemp -d) +trap 'rm -rf "$obj_dir"' EXIT + +for src in "$shim_dir"/wrappers/*.S; do + name=$(basename "$src" .S) + "$cc" -c -mfpu=neon -mfloat-abi=softfp "$src" -o "$obj_dir/$name.o" +done + +script_dir=$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd) +for lib_dir in "$@"; do + "$script_dir/patch-softfp-stub-archives.sh" "$lib_dir" "$ar" "$objcopy" \ + "$obj_dir" "$shim_dir/functions.tsv" +done diff --git a/scripts/patch-softfp-stub-archives.sh b/scripts/patch-softfp-stub-archives.sh new file mode 100755 index 00000000..4c2dfe97 --- /dev/null +++ b/scripts/patch-softfp-stub-archives.sh @@ -0,0 +1,64 @@ +#!/usr/bin/env bash +# +# Splice the softfp ABI shims (softfp-shim/wrappers/*.S, already assembled to +# *.o) into the stub archives vita-headers just installed, for the 23 +# functions listed in softfp-shim/functions.tsv (see PLAN-softfp.md, "Fase 1 +# - los 23 shims de serie"). +# +# For each function this renames the real stub object's exported symbol to +# __vita_softfp_target_ (objcopy --redefine-sym) and adds the matching +# wrapper object as a new archive member under the original name. A static +# archive resolves symbols through its member index, not by member order, so +# after the rename there is exactly one provider of left in the +# archive and no link-order dependency is introduced -- packages keep linking +# -lSceGxm_stub, -lScePvf_stub, etc. exactly as before. + +set -euo pipefail + +if [[ $# -ne 5 ]]; then + printf 'usage: %s \n' "$0" >&2 + exit 2 +fi + +lib_dir=$1 +ar=$2 +objcopy=$3 +wrapper_dir=$4 +functions_tsv=$5 + +[[ -d $lib_dir ]] || { printf 'lib dir not found: %s\n' "$lib_dir" >&2; exit 1; } + +work_dir=$(mktemp -d) +trap 'rm -rf "$work_dir"' EXIT + +patch_archive() { + local archive=$1 name=$2 + [[ -f $archive ]] || return 0 + + local member + member=$("$ar" t "$archive" | grep -E "_${name}\.(o|wo)\$" || true) + if [[ -z $member ]]; then + printf 'symbol %s not found in %s\n' "$name" "$archive" >&2 + exit 1 + fi + + local extract_dir="$work_dir/$(basename "$archive")-$name" + mkdir -p "$extract_dir" + (cd "$extract_dir" && "$ar" x "$archive" "$member") + "$objcopy" --redefine-sym "${name}=__vita_softfp_target_${name}" \ + "$extract_dir/$member" + + "$ar" r "$archive" "$extract_dir/$member" + "$ar" r "$archive" "$wrapper_dir/$name.o" + "$ar" s "$archive" +} + +while IFS=$'\t' read -r name header module; do + [[ -n $name ]] || continue + [[ -f "$wrapper_dir/$name.o" ]] || { + printf 'wrapper object not found: %s/%s.o\n' "$wrapper_dir" "$name" >&2 + exit 1 + } + patch_archive "$lib_dir/lib${module}_stub.a" "$name" + patch_archive "$lib_dir/lib${module}_stub_weak.a" "$name" +done < "$functions_tsv" diff --git a/scripts/repack-core.sh b/scripts/repack-core.sh index 0a1c7bde..cde4033e 100755 --- a/scripts/repack-core.sh +++ b/scripts/repack-core.sh @@ -143,7 +143,10 @@ cp -a "$vita_makepkg/libmakepkg" "$sdk_root/bin/libmakepkg" cp -a "$vita_makepkg/vita-makepkg" "$sdk_root/bin/vita-makepkg" cp -a "$vita_makepkg/makepkg.conf.sample" "$sdk_root/bin/makepkg.conf" +# Repacking only ever handles releases of the default world: softfp cores +# are never repacked by this script. cmake -DOUTPUT="$sdk_root/etc/pacman.conf" -DHOST_ARCHITECTURE="$host" \ + -DWORLD_ARCH=vita \ -P "$script_directory/../cmake/WritePacmanConfig.cmake" vdpm_version=$(awk -F= '$1 == "version" { print $2; exit }' \ @@ -167,6 +170,12 @@ fi # The component lines above this block still describe what produced the # binaries. These say who repacked them and with what, and name the source # archive by digest so the claim can be checked against what is published. +# Archives from before the world was stamped in version_info.txt never carry +# a "world" line; backfill it here since this script only ever repacks the +# default world (see the pacman.conf write above). +if ! grep -q '^world ' "$version_info"; then + printf 'world vita (float-abi=hard)\n' >> "$version_info" +fi { printf 'repacked from %s\n' "$(basename "$archive")" printf 'source sha256 %s\n' "${archive_digest%% *}" diff --git a/scripts/validate-core-package.sh b/scripts/validate-core-package.sh index a103a5e6..f9cf3393 100755 --- a/scripts/validate-core-package.sh +++ b/scripts/validate-core-package.sh @@ -60,6 +60,33 @@ if [[ $pkgname == vitasdk-core ]]; then printf 'core package does not contain provenance information\n' >&2 exit 1 } + + # The world (vita, vita-softfp, ...) is stamped in two independent places; + # a mismatch means the build tagged the release for one world while + # actually configuring the toolchain, or makepkg, for another. + world_from_version=$(bsdtar -xOf "$package" version_info.txt | + awk '$1 == "world" { print $2; exit }') + [[ -n $world_from_version ]] || { + printf 'version_info.txt does not declare a world\n' >&2 + exit 1 + } + + grep -qx 'bin/makepkg.conf' <<< "$archive_entries" || { + printf 'core package does not contain bin/makepkg.conf\n' >&2 + exit 1 + } + world_from_makepkg=$(bsdtar -xOf "$package" bin/makepkg.conf | + awk -F '"' '/^CARCH=/ { print $2; exit }') + [[ -n $world_from_makepkg ]] || { + printf 'bin/makepkg.conf does not declare CARCH\n' >&2 + exit 1 + } + + [[ $world_from_version == "$world_from_makepkg" ]] || { + printf 'world mismatch: version_info.txt says %s, bin/makepkg.conf CARCH says %s\n' \ + "$world_from_version" "$world_from_makepkg" >&2 + exit 1 + } else grep -Eq '^bin/vdpm(\.exe)?$' <<< "$archive_entries" || { printf 'client package does not contain the package client\n' >&2 diff --git a/softfp-shim/README.md b/softfp-shim/README.md new file mode 100644 index 00000000..0c3abfc1 --- /dev/null +++ b/softfp-shim/README.md @@ -0,0 +1,74 @@ +# softfp ABI shims + +The 23 functions in `functions.tsv` are the ones where an AAPCS-base +(softfp) caller and the AAPCS-VFP (hard) Sce* stub disagree about where a +float/double argument or return value lives — see +`../artifacts/softfp-abi-audit/README.md` and `PLAN-softfp.md`, "Fase 1 - los +23 shims de serie", for how that inventory was built and why it stops at +these 23 (no kernel imports, no callbacks, no HFAs by value are affected). + +## What gets built + +`wrappers/*.S` (generated, checked in) are small naked Thumb-2 functions, +one per affected symbol, named exactly like the real function. Each one +moves its float/double arguments from their softfp slot into the register +the hard-float stub expects, calls into it, and — for a float/double return +— moves the result back before returning. `generate.py` derives the move +sequence from the AAPCS rules themselves (which argument gets which +register, on each side), not from a hand-picked template. + +`scripts/build-softfp-shim.sh` and `scripts/patch-softfp-stub-archives.sh` +(one level up, in `buildscripts/`) assemble these wrappers and splice them +into the installed `libSceGxm_stub.a`, `libSceMotion_stub.a`, +`libScePaf_stub.a`, `libScePgf_stub.a` and `libScePvf_stub.a` (and their +`_weak` counterparts): the real object exporting e.g. `sceGxmSetViewport` is +renamed in place to `__vita_softfp_target_sceGxmSetViewport` +(`objcopy --redefine-sym`), and the wrapper is added as a new archive member +under the original name. A static archive resolves symbols through its +member index, not member order, so after the rename there is exactly one +provider of each name left — no link-order dependency, no new `-l` flag, no +GCC/LIB_SPEC patch. Packages keep linking `-lSceGxm_stub` etc. exactly as +before; see `cmake/recipes/BuildSdkComponents.cmake` (guarded by +`VITASDK_FLOAT_ABI STREQUAL "softfp"`) for where this runs in the build. + +An earlier version of this plan meant to do the interception through +`LIB_SPEC` (`-lvita_softfp_shim`, unconditionally appended, "in front of the +stubs"). That does not work: GCC's `LINK_COMMAND_SPEC` expands `%o` — every +object file and every `-l` flag a caller passes explicitly — before it +expands `LIB_SPEC` (`%L`). SceGxm/SceMotion/ScePaf/ScePgf/ScePvf are never +part of the implicit baseline (unlike `SceLibKernel_stub` and friends); +every package links them explicitly, so their `-lSceGxm_stub` would always +land on the command line ahead of anything LIB_SPEC could add, and the real +stub would win the archive race every time. The archive-splice above has no +such ordering dependency. + +## Regenerating + +Re-run this when `../artifacts/softfp-abi-audit/scan-float-abi.py` reports a +different set of user-facing float/double crossings than `functions.tsv` +(23 rows today): + +```sh +python3 generate.py ../vita-headers/include +``` + +`functions.tsv` (function, header path, stub module) is hand-curated, not +derived automatically — the module column especially: `scePafGraphicsUpdateCurrentWave` and `sce_paf_strtod` are both exported +from `libScePaf_stub.a` but from two different internal libraries +(`ScePafGraphics`, `ScePafStdc`), and `ScePgf` is the archive that ships the +`sceFont*` names. Re-derive it by hand (`ar t libSceXxx_stub.a`) if the +scanner's result set changes, and update it deliberately rather than +regenerating it. + +The generator raises `NotImplementedError` rather than guess if it ever +meets a double or HFA parameter (none of the current 23 have one) — that +shape needs its own move-sequence case before it can be trusted. + +## Known gap, not ours to close here + +A caller with its own pre-existing hard→softfp wrapper (the +`vitasdk-softfp` org's vitaGL fork, built with `SOFTFP_ABI=1`) would now +double-translate if built against this series without removing that +wrapper first. Flagged for the Fase 5 migration guide, not fixed here: a new +world has no binary legacy to be compatible with, so the fix is "stop +wrapping", not a mechanism in this shim. diff --git a/softfp-shim/functions.tsv b/softfp-shim/functions.tsv new file mode 100644 index 00000000..7a378a14 --- /dev/null +++ b/softfp-shim/functions.tsv @@ -0,0 +1,23 @@ +sceGxmSetViewport psp2/gxm.h SceGxm +sceGxmSetWClampValue psp2/gxm.h SceGxm +sceGxmDepthStencilSurfaceSetBackgroundDepth psp2/gxm.h SceGxm +sceGxmDepthStencilSurfaceGetBackgroundDepth psp2/gxm.h SceGxm +sceMotionSetAngleThreshold psp2/motion.h SceMotion +sceMotionGetAngleThreshold psp2/motion.h SceMotion +sceMotionRotateYaw psp2/motion.h SceMotion +scePafGraphicsUpdateCurrentWave psp2/paf/graphics.h ScePaf +sce_paf_strtod psp2/paf/stdc.h ScePaf +sceFontSetResolution psp2/pgf.h ScePgf +sceFontPixelToPointH psp2/pgf.h ScePgf +sceFontPixelToPointV psp2/pgf.h ScePgf +sceFontPointToPixelH psp2/pgf.h ScePgf +sceFontPointToPixelV psp2/pgf.h ScePgf +scePvfSetCharSize psp2/pvf.h ScePvf +scePvfSetEM psp2/pvf.h ScePvf +scePvfSetEmboldenRate psp2/pvf.h ScePvf +scePvfSetResolution psp2/pvf.h ScePvf +scePvfSetSkewValue psp2/pvf.h ScePvf +scePvfPixelToPointH psp2/pvf.h ScePvf +scePvfPixelToPointV psp2/pvf.h ScePvf +scePvfPointToPixelH psp2/pvf.h ScePvf +scePvfPointToPixelV psp2/pvf.h ScePvf diff --git a/softfp-shim/generate.py b/softfp-shim/generate.py new file mode 100755 index 00000000..72acd4e8 --- /dev/null +++ b/softfp-shim/generate.py @@ -0,0 +1,209 @@ +#!/usr/bin/env python3 +"""Generate the softfp-world naked ABI shims for the 23 float/double crossings +found by ../artifacts/softfp-abi-audit/scan-float-abi.py (see results.tsv and +PLAN-softfp.md, "Fase 1" / los 23 shims de serie). + +A shim translates a single AAPCS-base (softfp) call into the AAPCS-VFP (hard) +call the real Sce* stub expects: move each float/double argument from its +softfp slot (core register or stack, counted together with every other +argument) into its hard-float slot (an S/D register, counted only among the +float/double arguments), and move a float/double return value back from +s0/d0 into r0 or r0:r1. Everything else (pointers, plain integers) already +sits in the same core register on both sides and is left untouched. + +Each generated file defines exactly one symbol, named like the real +function, and branches or calls into `__vita_softfp_target_` -- the +real stub, renamed by scripts/patch-softfp-stub-archives.sh so the wrapper +can carry the original name without colliding with it. This script only +emits the wrapper .S files; splicing them into the installed stub archives +is that shell script's job. + +Regenerate when scan-float-abi.py reports a different set of user-facing +crossings: + + python3 generate.py /include + +`functions.tsv` (name, header path relative to include/, stub module) is +hand-curated from that report, not derived automatically -- it is small and +its correctness matters more than saving the curation step. +""" + +import argparse +import os +import re +import sys + +FLOAT_TYPES = {"float", "SceFloat", "SceFloat32", "ScePvfFloat32"} +DOUBLE_TYPES = {"double", "SceDouble", "SceDouble64"} + +FUNCTION = re.compile(r"([\w\s\*]+?)\b(\w+)\s*\(([^()]*)\)\s*;") + +HEADER = """\ +\t.syntax unified +\t.thumb +\t.text +\t.align\t2 +\t.global\t{name} +\t.thumb_func +\t.type\t{name}, %function +{name}: +""" + + +def classify_type(text): + text = text.strip() + if "*" in text: + return "core" + tokens = text.split() + if any(token in FLOAT_TYPES for token in tokens): + return "float" + if any(token in DOUBLE_TYPES for token in tokens): + return "double" + return "core" + + +def find_signature(header_text, name): + flat = re.sub(r"\s+", " ", header_text) + for return_type, found_name, parameters in FUNCTION.findall(flat): + if found_name != name: + continue + params = [] + parameters = parameters.strip() + if parameters and parameters != "void": + for parameter in parameters.split(","): + params.append(classify_type(parameter)) + ret_kind = "void" if return_type.strip() == "void" else classify_type(return_type) + return ret_kind, params + raise LookupError(f"declaration of {name} not found") + + +def softfp_slots(params): + """Every argument, float or not, consumes one word in declaration order.""" + return list(enumerate(params)) + + +def hard_destinations(params): + core_idx = 0 + float_idx = 0 + dests = [] + for kind in params: + if kind == "float": + dests.append(("vfp", float_idx)) + float_idx += 1 + elif kind == "core": + dests.append(("core", core_idx)) + core_idx += 1 + else: + raise NotImplementedError("double/HFA parameters are not handled") + if core_idx > 4 or float_idx > 16: + raise NotImplementedError("more core/vfp arguments than fit in registers") + return dests + + +def slot_source(slot): + if slot < 4: + return ("reg", slot) + return ("stack", (slot - 4) * 4) + + +def emit_body(name, target, ret_kind, params): + dests = hard_destinations(params) + lines = [] + + # Float args first: every vmov reads an *original* softfp register/stack + # slot, before anything below overwrites r0-r3. Register-sourced floats + # are read first (they alias r0-r3 directly); stack-sourced floats are + # loaded through a scratch core register afterwards, since by then their + # register-sourced siblings have already been consumed. + scratch_regs = ["r1", "r2", "r3"] + pending_stack = [] + for slot, kind in softfp_slots(params): + if kind != "float": + continue + dest_idx = dests[slot][1] + source_kind, source = slot_source(slot) + if source_kind == "reg": + lines.append(f"\tvmov\ts{dest_idx}, r{source}") + else: + pending_stack.append((dest_idx, source)) + for dest_idx, offset in pending_stack: + scratch = scratch_regs.pop(0) + lines.append(f"\tldr\t{scratch}, [sp, #{offset}]") + lines.append(f"\tvmov\ts{dest_idx}, {scratch}") + + # Core (pointer/integer) args next, in increasing destination-register + # order -- always safe, since a core argument's source slot number is + # never lower than its destination register number (interleaved float + # arguments only ever push a source slot further right). + core_moves = [] + for slot, kind in softfp_slots(params): + if kind != "core": + continue + dest_idx = dests[slot][1] + source_kind, source = slot_source(slot) + if source_kind != "reg": + raise NotImplementedError("stack-sourced core argument") + if source != dest_idx: + core_moves.append((dest_idx, source)) + for dest_idx, source in sorted(core_moves): + lines.append(f"\tmov\tr{dest_idx}, r{source}") + + if ret_kind == "float": + lines.insert(0, "\tpush\t{lr}") + lines.append(f"\tbl\t{target}") + lines.append("\tvmov\tr0, s0") + lines.append("\tpop\t{lr}") + lines.append("\tbx\tlr") + elif ret_kind == "double": + lines.insert(0, "\tpush\t{lr}") + lines.append(f"\tbl\t{target}") + lines.append("\tvmov\tr0, r1, d0") + lines.append("\tpop\t{lr}") + lines.append("\tbx\tlr") + else: + lines.append(f"\tb\t{target}") + + return "\n".join(lines) + "\n" + + +def generate_one(name, header_text, out_dir): + ret_kind, params = find_signature(header_text, name) + target = f"__vita_softfp_target_{name}" + body = emit_body(name, target, ret_kind, params) + path = os.path.join(out_dir, f"{name}.S") + with open(path, "w", encoding="utf-8") as handle: + handle.write(HEADER.format(name=name)) + handle.write(body) + handle.write(f"\t.size\t{name}, . - {name}\n") + return path + + +def main(): + parser = argparse.ArgumentParser() + parser.add_argument("include_dir", help="vita-headers include/ directory") + parser.add_argument("--functions", default=os.path.join( + os.path.dirname(__file__), "functions.tsv")) + parser.add_argument("--out", default=os.path.join( + os.path.dirname(__file__), "wrappers")) + options = parser.parse_args() + + os.makedirs(options.out, exist_ok=True) + + headers = {} + with open(options.functions, encoding="utf-8") as handle: + rows = [line.rstrip("\n").split("\t") for line in handle if line.strip()] + + generated = [] + for name, header, _module in rows: + if header not in headers: + with open(os.path.join(options.include_dir, header), + encoding="utf-8") as handle: + headers[header] = handle.read() + generated.append(generate_one(name, headers[header], options.out)) + + print(f"generated {len(generated)} wrappers in {options.out}", file=sys.stderr) + return 0 + + +if __name__ == "__main__": + sys.exit(main()) diff --git a/softfp-shim/wrappers/sceFontPixelToPointH.S b/softfp-shim/wrappers/sceFontPixelToPointH.S new file mode 100644 index 00000000..036e3416 --- /dev/null +++ b/softfp-shim/wrappers/sceFontPixelToPointH.S @@ -0,0 +1,16 @@ + .syntax unified + .thumb + .text + .align 2 + .global sceFontPixelToPointH + .thumb_func + .type sceFontPixelToPointH, %function +sceFontPixelToPointH: + push {lr} + vmov s0, r1 + mov r1, r2 + bl __vita_softfp_target_sceFontPixelToPointH + vmov r0, s0 + pop {lr} + bx lr + .size sceFontPixelToPointH, . - sceFontPixelToPointH diff --git a/softfp-shim/wrappers/sceFontPixelToPointV.S b/softfp-shim/wrappers/sceFontPixelToPointV.S new file mode 100644 index 00000000..a6152738 --- /dev/null +++ b/softfp-shim/wrappers/sceFontPixelToPointV.S @@ -0,0 +1,16 @@ + .syntax unified + .thumb + .text + .align 2 + .global sceFontPixelToPointV + .thumb_func + .type sceFontPixelToPointV, %function +sceFontPixelToPointV: + push {lr} + vmov s0, r1 + mov r1, r2 + bl __vita_softfp_target_sceFontPixelToPointV + vmov r0, s0 + pop {lr} + bx lr + .size sceFontPixelToPointV, . - sceFontPixelToPointV diff --git a/softfp-shim/wrappers/sceFontPointToPixelH.S b/softfp-shim/wrappers/sceFontPointToPixelH.S new file mode 100644 index 00000000..16b1fa0c --- /dev/null +++ b/softfp-shim/wrappers/sceFontPointToPixelH.S @@ -0,0 +1,16 @@ + .syntax unified + .thumb + .text + .align 2 + .global sceFontPointToPixelH + .thumb_func + .type sceFontPointToPixelH, %function +sceFontPointToPixelH: + push {lr} + vmov s0, r1 + mov r1, r2 + bl __vita_softfp_target_sceFontPointToPixelH + vmov r0, s0 + pop {lr} + bx lr + .size sceFontPointToPixelH, . - sceFontPointToPixelH diff --git a/softfp-shim/wrappers/sceFontPointToPixelV.S b/softfp-shim/wrappers/sceFontPointToPixelV.S new file mode 100644 index 00000000..975d9450 --- /dev/null +++ b/softfp-shim/wrappers/sceFontPointToPixelV.S @@ -0,0 +1,16 @@ + .syntax unified + .thumb + .text + .align 2 + .global sceFontPointToPixelV + .thumb_func + .type sceFontPointToPixelV, %function +sceFontPointToPixelV: + push {lr} + vmov s0, r1 + mov r1, r2 + bl __vita_softfp_target_sceFontPointToPixelV + vmov r0, s0 + pop {lr} + bx lr + .size sceFontPointToPixelV, . - sceFontPointToPixelV diff --git a/softfp-shim/wrappers/sceFontSetResolution.S b/softfp-shim/wrappers/sceFontSetResolution.S new file mode 100644 index 00000000..a5736fe3 --- /dev/null +++ b/softfp-shim/wrappers/sceFontSetResolution.S @@ -0,0 +1,12 @@ + .syntax unified + .thumb + .text + .align 2 + .global sceFontSetResolution + .thumb_func + .type sceFontSetResolution, %function +sceFontSetResolution: + vmov s0, r1 + vmov s1, r2 + b __vita_softfp_target_sceFontSetResolution + .size sceFontSetResolution, . - sceFontSetResolution diff --git a/softfp-shim/wrappers/sceGxmDepthStencilSurfaceGetBackgroundDepth.S b/softfp-shim/wrappers/sceGxmDepthStencilSurfaceGetBackgroundDepth.S new file mode 100644 index 00000000..8740dae4 --- /dev/null +++ b/softfp-shim/wrappers/sceGxmDepthStencilSurfaceGetBackgroundDepth.S @@ -0,0 +1,14 @@ + .syntax unified + .thumb + .text + .align 2 + .global sceGxmDepthStencilSurfaceGetBackgroundDepth + .thumb_func + .type sceGxmDepthStencilSurfaceGetBackgroundDepth, %function +sceGxmDepthStencilSurfaceGetBackgroundDepth: + push {lr} + bl __vita_softfp_target_sceGxmDepthStencilSurfaceGetBackgroundDepth + vmov r0, s0 + pop {lr} + bx lr + .size sceGxmDepthStencilSurfaceGetBackgroundDepth, . - sceGxmDepthStencilSurfaceGetBackgroundDepth diff --git a/softfp-shim/wrappers/sceGxmDepthStencilSurfaceSetBackgroundDepth.S b/softfp-shim/wrappers/sceGxmDepthStencilSurfaceSetBackgroundDepth.S new file mode 100644 index 00000000..e22f641e --- /dev/null +++ b/softfp-shim/wrappers/sceGxmDepthStencilSurfaceSetBackgroundDepth.S @@ -0,0 +1,11 @@ + .syntax unified + .thumb + .text + .align 2 + .global sceGxmDepthStencilSurfaceSetBackgroundDepth + .thumb_func + .type sceGxmDepthStencilSurfaceSetBackgroundDepth, %function +sceGxmDepthStencilSurfaceSetBackgroundDepth: + vmov s0, r1 + b __vita_softfp_target_sceGxmDepthStencilSurfaceSetBackgroundDepth + .size sceGxmDepthStencilSurfaceSetBackgroundDepth, . - sceGxmDepthStencilSurfaceSetBackgroundDepth diff --git a/softfp-shim/wrappers/sceGxmSetViewport.S b/softfp-shim/wrappers/sceGxmSetViewport.S new file mode 100644 index 00000000..e1520a35 --- /dev/null +++ b/softfp-shim/wrappers/sceGxmSetViewport.S @@ -0,0 +1,19 @@ + .syntax unified + .thumb + .text + .align 2 + .global sceGxmSetViewport + .thumb_func + .type sceGxmSetViewport, %function +sceGxmSetViewport: + vmov s0, r1 + vmov s1, r2 + vmov s2, r3 + ldr r1, [sp, #0] + vmov s3, r1 + ldr r2, [sp, #4] + vmov s4, r2 + ldr r3, [sp, #8] + vmov s5, r3 + b __vita_softfp_target_sceGxmSetViewport + .size sceGxmSetViewport, . - sceGxmSetViewport diff --git a/softfp-shim/wrappers/sceGxmSetWClampValue.S b/softfp-shim/wrappers/sceGxmSetWClampValue.S new file mode 100644 index 00000000..317ec0c0 --- /dev/null +++ b/softfp-shim/wrappers/sceGxmSetWClampValue.S @@ -0,0 +1,11 @@ + .syntax unified + .thumb + .text + .align 2 + .global sceGxmSetWClampValue + .thumb_func + .type sceGxmSetWClampValue, %function +sceGxmSetWClampValue: + vmov s0, r1 + b __vita_softfp_target_sceGxmSetWClampValue + .size sceGxmSetWClampValue, . - sceGxmSetWClampValue diff --git a/softfp-shim/wrappers/sceMotionGetAngleThreshold.S b/softfp-shim/wrappers/sceMotionGetAngleThreshold.S new file mode 100644 index 00000000..89f90736 --- /dev/null +++ b/softfp-shim/wrappers/sceMotionGetAngleThreshold.S @@ -0,0 +1,14 @@ + .syntax unified + .thumb + .text + .align 2 + .global sceMotionGetAngleThreshold + .thumb_func + .type sceMotionGetAngleThreshold, %function +sceMotionGetAngleThreshold: + push {lr} + bl __vita_softfp_target_sceMotionGetAngleThreshold + vmov r0, s0 + pop {lr} + bx lr + .size sceMotionGetAngleThreshold, . - sceMotionGetAngleThreshold diff --git a/softfp-shim/wrappers/sceMotionRotateYaw.S b/softfp-shim/wrappers/sceMotionRotateYaw.S new file mode 100644 index 00000000..858fd2d3 --- /dev/null +++ b/softfp-shim/wrappers/sceMotionRotateYaw.S @@ -0,0 +1,11 @@ + .syntax unified + .thumb + .text + .align 2 + .global sceMotionRotateYaw + .thumb_func + .type sceMotionRotateYaw, %function +sceMotionRotateYaw: + vmov s0, r0 + b __vita_softfp_target_sceMotionRotateYaw + .size sceMotionRotateYaw, . - sceMotionRotateYaw diff --git a/softfp-shim/wrappers/sceMotionSetAngleThreshold.S b/softfp-shim/wrappers/sceMotionSetAngleThreshold.S new file mode 100644 index 00000000..e35e4dab --- /dev/null +++ b/softfp-shim/wrappers/sceMotionSetAngleThreshold.S @@ -0,0 +1,11 @@ + .syntax unified + .thumb + .text + .align 2 + .global sceMotionSetAngleThreshold + .thumb_func + .type sceMotionSetAngleThreshold, %function +sceMotionSetAngleThreshold: + vmov s0, r0 + b __vita_softfp_target_sceMotionSetAngleThreshold + .size sceMotionSetAngleThreshold, . - sceMotionSetAngleThreshold diff --git a/softfp-shim/wrappers/scePafGraphicsUpdateCurrentWave.S b/softfp-shim/wrappers/scePafGraphicsUpdateCurrentWave.S new file mode 100644 index 00000000..88853e8b --- /dev/null +++ b/softfp-shim/wrappers/scePafGraphicsUpdateCurrentWave.S @@ -0,0 +1,11 @@ + .syntax unified + .thumb + .text + .align 2 + .global scePafGraphicsUpdateCurrentWave + .thumb_func + .type scePafGraphicsUpdateCurrentWave, %function +scePafGraphicsUpdateCurrentWave: + vmov s0, r1 + b __vita_softfp_target_scePafGraphicsUpdateCurrentWave + .size scePafGraphicsUpdateCurrentWave, . - scePafGraphicsUpdateCurrentWave diff --git a/softfp-shim/wrappers/scePvfPixelToPointH.S b/softfp-shim/wrappers/scePvfPixelToPointH.S new file mode 100644 index 00000000..32a3d2c3 --- /dev/null +++ b/softfp-shim/wrappers/scePvfPixelToPointH.S @@ -0,0 +1,16 @@ + .syntax unified + .thumb + .text + .align 2 + .global scePvfPixelToPointH + .thumb_func + .type scePvfPixelToPointH, %function +scePvfPixelToPointH: + push {lr} + vmov s0, r1 + mov r1, r2 + bl __vita_softfp_target_scePvfPixelToPointH + vmov r0, s0 + pop {lr} + bx lr + .size scePvfPixelToPointH, . - scePvfPixelToPointH diff --git a/softfp-shim/wrappers/scePvfPixelToPointV.S b/softfp-shim/wrappers/scePvfPixelToPointV.S new file mode 100644 index 00000000..6c69cf98 --- /dev/null +++ b/softfp-shim/wrappers/scePvfPixelToPointV.S @@ -0,0 +1,16 @@ + .syntax unified + .thumb + .text + .align 2 + .global scePvfPixelToPointV + .thumb_func + .type scePvfPixelToPointV, %function +scePvfPixelToPointV: + push {lr} + vmov s0, r1 + mov r1, r2 + bl __vita_softfp_target_scePvfPixelToPointV + vmov r0, s0 + pop {lr} + bx lr + .size scePvfPixelToPointV, . - scePvfPixelToPointV diff --git a/softfp-shim/wrappers/scePvfPointToPixelH.S b/softfp-shim/wrappers/scePvfPointToPixelH.S new file mode 100644 index 00000000..bdae78f1 --- /dev/null +++ b/softfp-shim/wrappers/scePvfPointToPixelH.S @@ -0,0 +1,16 @@ + .syntax unified + .thumb + .text + .align 2 + .global scePvfPointToPixelH + .thumb_func + .type scePvfPointToPixelH, %function +scePvfPointToPixelH: + push {lr} + vmov s0, r1 + mov r1, r2 + bl __vita_softfp_target_scePvfPointToPixelH + vmov r0, s0 + pop {lr} + bx lr + .size scePvfPointToPixelH, . - scePvfPointToPixelH diff --git a/softfp-shim/wrappers/scePvfPointToPixelV.S b/softfp-shim/wrappers/scePvfPointToPixelV.S new file mode 100644 index 00000000..db5a7d19 --- /dev/null +++ b/softfp-shim/wrappers/scePvfPointToPixelV.S @@ -0,0 +1,16 @@ + .syntax unified + .thumb + .text + .align 2 + .global scePvfPointToPixelV + .thumb_func + .type scePvfPointToPixelV, %function +scePvfPointToPixelV: + push {lr} + vmov s0, r1 + mov r1, r2 + bl __vita_softfp_target_scePvfPointToPixelV + vmov r0, s0 + pop {lr} + bx lr + .size scePvfPointToPixelV, . - scePvfPointToPixelV diff --git a/softfp-shim/wrappers/scePvfSetCharSize.S b/softfp-shim/wrappers/scePvfSetCharSize.S new file mode 100644 index 00000000..96664367 --- /dev/null +++ b/softfp-shim/wrappers/scePvfSetCharSize.S @@ -0,0 +1,12 @@ + .syntax unified + .thumb + .text + .align 2 + .global scePvfSetCharSize + .thumb_func + .type scePvfSetCharSize, %function +scePvfSetCharSize: + vmov s0, r1 + vmov s1, r2 + b __vita_softfp_target_scePvfSetCharSize + .size scePvfSetCharSize, . - scePvfSetCharSize diff --git a/softfp-shim/wrappers/scePvfSetEM.S b/softfp-shim/wrappers/scePvfSetEM.S new file mode 100644 index 00000000..f41faa4f --- /dev/null +++ b/softfp-shim/wrappers/scePvfSetEM.S @@ -0,0 +1,11 @@ + .syntax unified + .thumb + .text + .align 2 + .global scePvfSetEM + .thumb_func + .type scePvfSetEM, %function +scePvfSetEM: + vmov s0, r1 + b __vita_softfp_target_scePvfSetEM + .size scePvfSetEM, . - scePvfSetEM diff --git a/softfp-shim/wrappers/scePvfSetEmboldenRate.S b/softfp-shim/wrappers/scePvfSetEmboldenRate.S new file mode 100644 index 00000000..2ef05976 --- /dev/null +++ b/softfp-shim/wrappers/scePvfSetEmboldenRate.S @@ -0,0 +1,11 @@ + .syntax unified + .thumb + .text + .align 2 + .global scePvfSetEmboldenRate + .thumb_func + .type scePvfSetEmboldenRate, %function +scePvfSetEmboldenRate: + vmov s0, r1 + b __vita_softfp_target_scePvfSetEmboldenRate + .size scePvfSetEmboldenRate, . - scePvfSetEmboldenRate diff --git a/softfp-shim/wrappers/scePvfSetResolution.S b/softfp-shim/wrappers/scePvfSetResolution.S new file mode 100644 index 00000000..97a78f65 --- /dev/null +++ b/softfp-shim/wrappers/scePvfSetResolution.S @@ -0,0 +1,12 @@ + .syntax unified + .thumb + .text + .align 2 + .global scePvfSetResolution + .thumb_func + .type scePvfSetResolution, %function +scePvfSetResolution: + vmov s0, r1 + vmov s1, r2 + b __vita_softfp_target_scePvfSetResolution + .size scePvfSetResolution, . - scePvfSetResolution diff --git a/softfp-shim/wrappers/scePvfSetSkewValue.S b/softfp-shim/wrappers/scePvfSetSkewValue.S new file mode 100644 index 00000000..bcffb613 --- /dev/null +++ b/softfp-shim/wrappers/scePvfSetSkewValue.S @@ -0,0 +1,12 @@ + .syntax unified + .thumb + .text + .align 2 + .global scePvfSetSkewValue + .thumb_func + .type scePvfSetSkewValue, %function +scePvfSetSkewValue: + vmov s0, r1 + vmov s1, r2 + b __vita_softfp_target_scePvfSetSkewValue + .size scePvfSetSkewValue, . - scePvfSetSkewValue diff --git a/softfp-shim/wrappers/sce_paf_strtod.S b/softfp-shim/wrappers/sce_paf_strtod.S new file mode 100644 index 00000000..9c2f8cae --- /dev/null +++ b/softfp-shim/wrappers/sce_paf_strtod.S @@ -0,0 +1,14 @@ + .syntax unified + .thumb + .text + .align 2 + .global sce_paf_strtod + .thumb_func + .type sce_paf_strtod, %function +sce_paf_strtod: + push {lr} + bl __vita_softfp_target_sce_paf_strtod + vmov r0, r1, d0 + pop {lr} + bx lr + .size sce_paf_strtod, . - sce_paf_strtod diff --git a/tests/package/test-core-package.sh b/tests/package/test-core-package.sh index dada811e..6fa785c1 100755 --- a/tests/package/test-core-package.sh +++ b/tests/package/test-core-package.sh @@ -35,7 +35,8 @@ chmod +x "$sdk_root/bin/arm-vita-eabi-gcc" "$sdk_root/libexec/vdpm/pacman" \ "$sdk_root/libexec/vdpm/pacman-conf" "$sdk_root/bin/vdpm" "$sdk_root/bin/vdpm-channel" printf 'refresh\n' > "$sdk_root/bin/include/refresh-repositories.sh" printf 'archive\n' > "$sdk_root/arm-vita-eabi/lib/libfixture.a" -printf 'source=fixture\n' > "$sdk_root/version_info.txt" +printf 'source=fixture\nworld vita (float-abi=hard)\n' > "$sdk_root/version_info.txt" +printf 'CARCH="vita"\n' > "$sdk_root/bin/makepkg.conf" printf 'notices\n' > "$sdk_root/share/vdpm/THIRD_PARTY_NOTICES.md" printf 'vdpm license\n' > "$sdk_root/share/vdpm/licenses/vdpm-LGPL-2.1.txt" printf 'pacman license\n' > "$sdk_root/share/vdpm/licenses/pacman-GPL-2.0.txt" @@ -134,7 +135,8 @@ mkdir -p "$windows_root/bin" "$windows_root/arm-vita-eabi/lib" \ printf 'gcc\n' > "$windows_root/bin/arm-vita-eabi-gcc.exe" printf 'vdpm\n' > "$windows_root/bin/vdpm.exe" printf 'archive\n' > "$windows_root/arm-vita-eabi/lib/libfixture.a" -printf 'source=fixture\n' > "$windows_root/version_info.txt" +printf 'source=fixture\nworld vita (float-abi=hard)\n' > "$windows_root/version_info.txt" +printf 'CARCH="vita"\n' > "$windows_root/bin/makepkg.conf" printf 'notices\n' > "$windows_root/share/vdpm/THIRD_PARTY_NOTICES.md" printf 'refresh\n' > "$windows_root/share/vdpm/refresh-repositories.ps1" printf 'vdpm license\n' > "$windows_root/share/vdpm/licenses/vdpm-LGPL-2.1.txt" diff --git a/tests/toolchain-contract/abi.c b/tests/toolchain-contract/abi.c index b962a6f7..e93d6616 100644 --- a/tests/toolchain-contract/abi.c +++ b/tests/toolchain-contract/abi.c @@ -9,9 +9,11 @@ #error "Vita uses ARM EABI" #endif -#ifndef __ARM_PCS_VFP -#error "Vita uses the hard-float procedure-call standard" -#endif +/* + * The float ABI (hard vs softfp) is a build parameter, not a fixed property + * of this source file: run.sh detects which one this compiler defaults to + * and asserts the __ARM_PCS_VFP / Tag_ABI_VFP_args contract for that world. + */ _Static_assert(sizeof(char) == 1, "unexpected char size"); _Static_assert((char)-1 < 0, "plain char must be signed"); diff --git a/tests/toolchain-contract/run.sh b/tests/toolchain-contract/run.sh index 1e592603..fc4dab79 100755 --- a/tests/toolchain-contract/run.sh +++ b/tests/toolchain-contract/run.sh @@ -46,14 +46,43 @@ echo "checking predefined macros" macros=$("${CC}" -dM -E -x c /dev/null) expect_text "${macros}" "#define __vita__ 1" "__vita__ macro" expect_text "${macros}" "#define __ARM_EABI__ 1" "ARM EABI macro" -expect_text "${macros}" "#define __ARM_PCS_VFP 1" "hard-float PCS macro" expect_text "${macros}" "#define __ARM_ARCH 7" "ARMv7 default" expect_text "${macros}" "#define __ARM_NEON 1" "NEON default" +echo "checking float ABI contract" +# The float ABI (hard vs softfp) is a build parameter (VITASDK_FLOAT_ABI): +# detect which one this compiler defaults to, then assert the contract for +# that world in both directions instead of assuming hard-float. +expect_text "${macros}" "#define __ARM_FP " \ + "hardware FPU macro (both float ABIs compute on VFP hardware)" +if printf '%s\n' "${macros}" | grep -qF '#define __ARM_PCS_VFP 1'; then + float_abi=hard +else + float_abi=softfp +fi +echo "detected float ABI: ${float_abi}" + +if [ "${float_abi}" = "hard" ]; then + expect_text "${macros}" "#define __ARM_PCS_VFP 1" "hard-float PCS macro" +else + reject_text "${macros}" "#define __ARM_PCS_VFP 1" \ + "hard-float PCS macro in a softfp toolchain" +fi + echo "checking C ABI" "${CC}" -std=c11 -Wall -Wextra -Werror -c \ "${srcdir}/abi.c" -o "${workdir}/abi.o" +echo "checking ARM float ABI attribute" +abi_attributes=$("${READELF}" -A "${workdir}/abi.o") +if [ "${float_abi}" = "hard" ]; then + expect_text "${abi_attributes}" "Tag_ABI_VFP_args" \ + "VFP-args ABI attribute in a hard-float object" +else + reject_text "${abi_attributes}" "Tag_ABI_VFP_args" \ + "VFP-args ABI attribute in a softfp object" +fi + echo "checking C++ ABI, exceptions and RTTI" "${CXX}" -std=c++17 -Wall -Wextra -Werror -c \ "${srcdir}/cxx.cpp" -o "${workdir}/cxx.o" @@ -114,4 +143,30 @@ echo "checking ARM unwind section generation" echo "checking that public headers compile on their own" "${srcdir}/self-contained-headers.sh" +if [ "${float_abi}" = "softfp" ]; then + echo "checking the softfp ABI shims (23 functions) resolve against the shim, not the raw stub" + shim_map="${workdir}/softfp-shim.map" + "${CC}" -std=c11 -Wall -Wextra -Werror \ + "${srcdir}/softfp-shim.c" -o "${workdir}/softfp-shim.elf" \ + -lSceGxm_stub -lSceMotion_stub -lScePaf_stub -lScePgf_stub -lScePvf_stub \ + -Wl,-Map="${shim_map}" + + shim_map_text=$(cat "${shim_map}") + for shimmed_function in \ + sceGxmSetViewport sceGxmSetWClampValue \ + sceGxmDepthStencilSurfaceSetBackgroundDepth \ + sceGxmDepthStencilSurfaceGetBackgroundDepth \ + sceMotionSetAngleThreshold sceMotionGetAngleThreshold sceMotionRotateYaw \ + scePafGraphicsUpdateCurrentWave sce_paf_strtod \ + sceFontSetResolution sceFontPixelToPointH sceFontPixelToPointV \ + sceFontPointToPixelH sceFontPointToPixelV \ + scePvfSetCharSize scePvfSetEM scePvfSetEmboldenRate scePvfSetResolution \ + scePvfSetSkewValue scePvfPixelToPointH scePvfPixelToPointV \ + scePvfPointToPixelH scePvfPointToPixelV + do + expect_text "${shim_map_text}" "(${shimmed_function}.o)" \ + "${shimmed_function} resolved against the softfp shim wrapper" + done +fi + echo "Vita GCC/binutils contract OK" diff --git a/tests/toolchain-contract/softfp-shim.c b/tests/toolchain-contract/softfp-shim.c new file mode 100644 index 00000000..72756791 --- /dev/null +++ b/tests/toolchain-contract/softfp-shim.c @@ -0,0 +1,56 @@ +/* Exercises all 23 functions covered by softfp-shim/ -- see run.sh, which + * links this against the real stub archives (-lSceGxm_stub etc., exactly as + * a package would) and checks the link map to confirm each one resolved to + * the shim wrapper, not the raw hard-float stub. */ + +#include +#include +#include +#include +#include +#include + +void exercise_softfp_shims(void) +{ + SceGxmContext *context = 0; + sceGxmSetViewport(context, 0.0f, 1.0f, 0.0f, 1.0f, 0.0f, 1.0f); + sceGxmSetWClampValue(context, 1.0f); + + SceGxmDepthStencilSurface *surface = 0; + sceGxmDepthStencilSurfaceSetBackgroundDepth(surface, 1.0f); + (void)sceGxmDepthStencilSurfaceGetBackgroundDepth(surface); + + sceMotionSetAngleThreshold(1.0f); + (void)sceMotionGetAngleThreshold(); + sceMotionRotateYaw(1.0f); + + scePafGraphicsUpdateCurrentWave(0, 1.0f); + (void)sce_paf_strtod("1.5", 0); + + SceFontLibHandle libHandle = 0; + unsigned int fontErrorCode = 0; + sceFontSetResolution(libHandle, 1.0f, 1.0f); + (void)sceFontPixelToPointH(libHandle, 1.0f, &fontErrorCode); + (void)sceFontPixelToPointV(libHandle, 1.0f, &fontErrorCode); + (void)sceFontPointToPixelH(libHandle, 1.0f, &fontErrorCode); + (void)sceFontPointToPixelV(libHandle, 1.0f, &fontErrorCode); + + ScePvfLibId libID = 0; + ScePvfFontId fontID = 0; + ScePvfError pvfError = 0; + scePvfSetCharSize(fontID, 1.0f, 1.0f); + scePvfSetEM(libID, 1.0f); + scePvfSetEmboldenRate(fontID, 1.0f); + scePvfSetResolution(libID, 1.0f, 1.0f); + scePvfSetSkewValue(fontID, 1.0f, 1.0f); + (void)scePvfPixelToPointH(libID, 1.0f, &pvfError); + (void)scePvfPixelToPointV(libID, 1.0f, &pvfError); + (void)scePvfPointToPixelH(libID, 1.0f, &pvfError); + (void)scePvfPointToPixelV(libID, 1.0f, &pvfError); +} + +int main(void) +{ + exercise_softfp_shims(); + return 0; +} From 112cbabe268b28c464941bb286cd4a2a7c043cc4 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Francisco=20Jos=C3=A9=20Garc=C3=ADa=20Garc=C3=ADa?= Date: Wed, 19 Aug 2026 20:04:29 +0200 Subject: [PATCH 2/4] Generate the softfp shims at build time instead of committing them Regeneration is a handful of regex passes over a few vita-headers files, cheap enough that trusting a checked-in copy to still match vita-headers was the wrong trade: a stale .S from before a signature change is a wrong ABI shim that still assembles and links without complaint, and nothing would have caught it. build-softfp-shim.sh now runs generate.py against the vita-headers this same build just installed, into a scratch directory, before assembling anything -- functions.tsv stays checked in (it records module ownership vita-headers itself does not expose), only the derived wrappers do not. --- .gitignore | 1 + cmake/recipes/BuildSdkComponents.cmake | 1 + scripts/build-softfp-shim.sh | 30 +++++----- softfp-shim/README.md | 57 ++++++++++++------- softfp-shim/wrappers/sceFontPixelToPointH.S | 16 ------ softfp-shim/wrappers/sceFontPixelToPointV.S | 16 ------ softfp-shim/wrappers/sceFontPointToPixelH.S | 16 ------ softfp-shim/wrappers/sceFontPointToPixelV.S | 16 ------ softfp-shim/wrappers/sceFontSetResolution.S | 12 ---- ...GxmDepthStencilSurfaceGetBackgroundDepth.S | 14 ----- ...GxmDepthStencilSurfaceSetBackgroundDepth.S | 11 ---- softfp-shim/wrappers/sceGxmSetViewport.S | 19 ------- softfp-shim/wrappers/sceGxmSetWClampValue.S | 11 ---- .../wrappers/sceMotionGetAngleThreshold.S | 14 ----- softfp-shim/wrappers/sceMotionRotateYaw.S | 11 ---- .../wrappers/sceMotionSetAngleThreshold.S | 11 ---- .../scePafGraphicsUpdateCurrentWave.S | 11 ---- softfp-shim/wrappers/scePvfPixelToPointH.S | 16 ------ softfp-shim/wrappers/scePvfPixelToPointV.S | 16 ------ softfp-shim/wrappers/scePvfPointToPixelH.S | 16 ------ softfp-shim/wrappers/scePvfPointToPixelV.S | 16 ------ softfp-shim/wrappers/scePvfSetCharSize.S | 12 ---- softfp-shim/wrappers/scePvfSetEM.S | 11 ---- softfp-shim/wrappers/scePvfSetEmboldenRate.S | 11 ---- softfp-shim/wrappers/scePvfSetResolution.S | 12 ---- softfp-shim/wrappers/scePvfSetSkewValue.S | 12 ---- softfp-shim/wrappers/sce_paf_strtod.S | 14 ----- 27 files changed, 57 insertions(+), 346 deletions(-) delete mode 100644 softfp-shim/wrappers/sceFontPixelToPointH.S delete mode 100644 softfp-shim/wrappers/sceFontPixelToPointV.S delete mode 100644 softfp-shim/wrappers/sceFontPointToPixelH.S delete mode 100644 softfp-shim/wrappers/sceFontPointToPixelV.S delete mode 100644 softfp-shim/wrappers/sceFontSetResolution.S delete mode 100644 softfp-shim/wrappers/sceGxmDepthStencilSurfaceGetBackgroundDepth.S delete mode 100644 softfp-shim/wrappers/sceGxmDepthStencilSurfaceSetBackgroundDepth.S delete mode 100644 softfp-shim/wrappers/sceGxmSetViewport.S delete mode 100644 softfp-shim/wrappers/sceGxmSetWClampValue.S delete mode 100644 softfp-shim/wrappers/sceMotionGetAngleThreshold.S delete mode 100644 softfp-shim/wrappers/sceMotionRotateYaw.S delete mode 100644 softfp-shim/wrappers/sceMotionSetAngleThreshold.S delete mode 100644 softfp-shim/wrappers/scePafGraphicsUpdateCurrentWave.S delete mode 100644 softfp-shim/wrappers/scePvfPixelToPointH.S delete mode 100644 softfp-shim/wrappers/scePvfPixelToPointV.S delete mode 100644 softfp-shim/wrappers/scePvfPointToPixelH.S delete mode 100644 softfp-shim/wrappers/scePvfPointToPixelV.S delete mode 100644 softfp-shim/wrappers/scePvfSetCharSize.S delete mode 100644 softfp-shim/wrappers/scePvfSetEM.S delete mode 100644 softfp-shim/wrappers/scePvfSetEmboldenRate.S delete mode 100644 softfp-shim/wrappers/scePvfSetResolution.S delete mode 100644 softfp-shim/wrappers/scePvfSetSkewValue.S delete mode 100644 softfp-shim/wrappers/sce_paf_strtod.S diff --git a/.gitignore b/.gitignore index c071f450..075c1d66 100644 --- a/.gitignore +++ b/.gitignore @@ -4,3 +4,4 @@ /.idea /build __pycache__/ +/softfp-shim/wrappers diff --git a/cmake/recipes/BuildSdkComponents.cmake b/cmake/recipes/BuildSdkComponents.cmake index 06b1ab87..a64f8a05 100644 --- a/cmake/recipes/BuildSdkComponents.cmake +++ b/cmake/recipes/BuildSdkComponents.cmake @@ -38,6 +38,7 @@ if(VITASDK_FLOAT_ABI STREQUAL "softfp") COMMAND ${PROJECT_SOURCE_DIR}/scripts/build-softfp-shim.sh ${binutils_prefix}-gcc ${binutils_prefix}-ar ${binutils_prefix}-objcopy ${PROJECT_SOURCE_DIR}/softfp-shim + ${CMAKE_INSTALL_PREFIX}/${target_arch}/include ${CMAKE_INSTALL_PREFIX}/${target_arch}/lib ${toolchain_build_install_dir}/${target_arch}/lib COMMAND ${CMAKE_COMMAND} -E touch ${CMAKE_BINARY_DIR}/softfp-shim.stamp diff --git a/scripts/build-softfp-shim.sh b/scripts/build-softfp-shim.sh index 365bfa2b..6917b74c 100755 --- a/scripts/build-softfp-shim.sh +++ b/scripts/build-softfp-shim.sh @@ -1,15 +1,16 @@ #!/usr/bin/env bash # -# Assemble softfp-shim/wrappers/*.S and splice them into every stub archive -# they touch, in every given lib dir. See patch-softfp-stub-archives.sh for -# what "splice" means; this just does the assembling and calls it once per -# lib dir (vita-headers installs its stub archives into two places -- the -# final SDK prefix and the toolchain's own build tree -- so both need it). +# Generate softfp-shim/wrappers/*.S from the vita-headers this build just +# installed, assemble them, and splice them into every stub archive they +# touch, in every given lib dir. See patch-softfp-stub-archives.sh for what +# "splice" means; generation is cheap enough (a handful of regex passes over +# a few headers) to redo on every softfp build rather than trust a checked-in +# copy to still match vita-headers -- see softfp-shim/README.md. set -euo pipefail -if [[ $# -lt 5 ]]; then - printf 'usage: %s ...\n' "$0" >&2 +if [[ $# -lt 6 ]]; then + printf 'usage: %s ...\n' "$0" >&2 exit 2 fi @@ -17,18 +18,21 @@ cc=$1 ar=$2 objcopy=$3 shim_dir=$4 -shift 4 +headers_dir=$5 +shift 5 -obj_dir=$(mktemp -d) -trap 'rm -rf "$obj_dir"' EXIT +work_dir=$(mktemp -d) +trap 'rm -rf "$work_dir"' EXIT -for src in "$shim_dir"/wrappers/*.S; do +python3 "$shim_dir/generate.py" "$headers_dir" --out "$work_dir/wrappers" + +for src in "$work_dir"/wrappers/*.S; do name=$(basename "$src" .S) - "$cc" -c -mfpu=neon -mfloat-abi=softfp "$src" -o "$obj_dir/$name.o" + "$cc" -c -mfpu=neon -mfloat-abi=softfp "$src" -o "$work_dir/$name.o" done script_dir=$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd) for lib_dir in "$@"; do "$script_dir/patch-softfp-stub-archives.sh" "$lib_dir" "$ar" "$objcopy" \ - "$obj_dir" "$shim_dir/functions.tsv" + "$work_dir" "$shim_dir/functions.tsv" done diff --git a/softfp-shim/README.md b/softfp-shim/README.md index 0c3abfc1..81484a19 100644 --- a/softfp-shim/README.md +++ b/softfp-shim/README.md @@ -9,13 +9,30 @@ these 23 (no kernel imports, no callbacks, no HFAs by value are affected). ## What gets built -`wrappers/*.S` (generated, checked in) are small naked Thumb-2 functions, -one per affected symbol, named exactly like the real function. Each one -moves its float/double arguments from their softfp slot into the register -the hard-float stub expects, calls into it, and — for a float/double return -— moves the result back before returning. `generate.py` derives the move -sequence from the AAPCS rules themselves (which argument gets which -register, on each side), not from a hand-picked template. +`wrappers/*.S` are small naked Thumb-2 functions, one per affected symbol, +named exactly like the real function. Each one moves its float/double +arguments from their softfp slot into the register the hard-float stub +expects, calls into it, and — for a float/double return — moves the result +back before returning. `generate.py` derives the move sequence from the +AAPCS rules themselves (which argument gets which register, on each side), +not from a hand-picked template. + +`wrappers/` is generated, not checked in (see `.gitignore`): +`scripts/build-softfp-shim.sh` runs `generate.py` against the vita-headers +this same build just installed before assembling anything, every time a +softfp world is built. The generation itself is a handful of regex passes +over a few headers — cheap enough that trusting a committed copy to still +match vita-headers, instead of just re-deriving it, would be the wrong +trade: a stale `.S` from before a vita-headers signature change is a wrong +ABI shim that still assembles and links without complaint. + +The trade this makes instead: `python3` becomes a real build-time +dependency, where none of the rest of this repo needs one (checked before +committing to this: nothing under `CMakeLists.txt`/`cmake/` invokes it). +Scoped to the softfp world only — `cmake/recipes/BuildSdkComponents.cmake` +only runs `build-softfp-shim.sh` inside `VITASDK_FLOAT_ABI STREQUAL +"softfp"` — so the default hard-float build stays exactly as +dependency-free as it was. `scripts/build-softfp-shim.sh` and `scripts/patch-softfp-stub-archives.sh` (one level up, in `buildscripts/`) assemble these wrappers and splice them @@ -42,24 +59,26 @@ land on the command line ahead of anything LIB_SPEC could add, and the real stub would win the archive race every time. The archive-splice above has no such ordering dependency. -## Regenerating +## Updating `functions.tsv` -Re-run this when `../artifacts/softfp-abi-audit/scan-float-abi.py` reports a -different set of user-facing float/double crossings than `functions.tsv` -(23 rows today): +The build regenerates `wrappers/*.S` itself, but `functions.tsv` (function, +header path, stub module) is hand-curated, not derived automatically — the +module column especially: `scePafGraphicsUpdateCurrentWave` and +`sce_paf_strtod` are both exported from `libScePaf_stub.a` but from two +different internal libraries (`ScePafGraphics`, `ScePafStdc`), and `ScePgf` +is the archive that ships the `sceFont*` names. Update it by hand +(`ar t libSceXxx_stub.a` against a real build finds the current mapping) +when `../artifacts/softfp-abi-audit/scan-float-abi.py` reports a different +set of user-facing float/double crossings than the 23 rows here today, and +commit that change deliberately. + +To see the generated output without a full build, run it the same way the +build does: ```sh python3 generate.py ../vita-headers/include ``` -`functions.tsv` (function, header path, stub module) is hand-curated, not -derived automatically — the module column especially: `scePafGraphicsUpdateCurrentWave` and `sce_paf_strtod` are both exported -from `libScePaf_stub.a` but from two different internal libraries -(`ScePafGraphics`, `ScePafStdc`), and `ScePgf` is the archive that ships the -`sceFont*` names. Re-derive it by hand (`ar t libSceXxx_stub.a`) if the -scanner's result set changes, and update it deliberately rather than -regenerating it. - The generator raises `NotImplementedError` rather than guess if it ever meets a double or HFA parameter (none of the current 23 have one) — that shape needs its own move-sequence case before it can be trusted. diff --git a/softfp-shim/wrappers/sceFontPixelToPointH.S b/softfp-shim/wrappers/sceFontPixelToPointH.S deleted file mode 100644 index 036e3416..00000000 --- a/softfp-shim/wrappers/sceFontPixelToPointH.S +++ /dev/null @@ -1,16 +0,0 @@ - .syntax unified - .thumb - .text - .align 2 - .global sceFontPixelToPointH - .thumb_func - .type sceFontPixelToPointH, %function -sceFontPixelToPointH: - push {lr} - vmov s0, r1 - mov r1, r2 - bl __vita_softfp_target_sceFontPixelToPointH - vmov r0, s0 - pop {lr} - bx lr - .size sceFontPixelToPointH, . - sceFontPixelToPointH diff --git a/softfp-shim/wrappers/sceFontPixelToPointV.S b/softfp-shim/wrappers/sceFontPixelToPointV.S deleted file mode 100644 index a6152738..00000000 --- a/softfp-shim/wrappers/sceFontPixelToPointV.S +++ /dev/null @@ -1,16 +0,0 @@ - .syntax unified - .thumb - .text - .align 2 - .global sceFontPixelToPointV - .thumb_func - .type sceFontPixelToPointV, %function -sceFontPixelToPointV: - push {lr} - vmov s0, r1 - mov r1, r2 - bl __vita_softfp_target_sceFontPixelToPointV - vmov r0, s0 - pop {lr} - bx lr - .size sceFontPixelToPointV, . - sceFontPixelToPointV diff --git a/softfp-shim/wrappers/sceFontPointToPixelH.S b/softfp-shim/wrappers/sceFontPointToPixelH.S deleted file mode 100644 index 16b1fa0c..00000000 --- a/softfp-shim/wrappers/sceFontPointToPixelH.S +++ /dev/null @@ -1,16 +0,0 @@ - .syntax unified - .thumb - .text - .align 2 - .global sceFontPointToPixelH - .thumb_func - .type sceFontPointToPixelH, %function -sceFontPointToPixelH: - push {lr} - vmov s0, r1 - mov r1, r2 - bl __vita_softfp_target_sceFontPointToPixelH - vmov r0, s0 - pop {lr} - bx lr - .size sceFontPointToPixelH, . - sceFontPointToPixelH diff --git a/softfp-shim/wrappers/sceFontPointToPixelV.S b/softfp-shim/wrappers/sceFontPointToPixelV.S deleted file mode 100644 index 975d9450..00000000 --- a/softfp-shim/wrappers/sceFontPointToPixelV.S +++ /dev/null @@ -1,16 +0,0 @@ - .syntax unified - .thumb - .text - .align 2 - .global sceFontPointToPixelV - .thumb_func - .type sceFontPointToPixelV, %function -sceFontPointToPixelV: - push {lr} - vmov s0, r1 - mov r1, r2 - bl __vita_softfp_target_sceFontPointToPixelV - vmov r0, s0 - pop {lr} - bx lr - .size sceFontPointToPixelV, . - sceFontPointToPixelV diff --git a/softfp-shim/wrappers/sceFontSetResolution.S b/softfp-shim/wrappers/sceFontSetResolution.S deleted file mode 100644 index a5736fe3..00000000 --- a/softfp-shim/wrappers/sceFontSetResolution.S +++ /dev/null @@ -1,12 +0,0 @@ - .syntax unified - .thumb - .text - .align 2 - .global sceFontSetResolution - .thumb_func - .type sceFontSetResolution, %function -sceFontSetResolution: - vmov s0, r1 - vmov s1, r2 - b __vita_softfp_target_sceFontSetResolution - .size sceFontSetResolution, . - sceFontSetResolution diff --git a/softfp-shim/wrappers/sceGxmDepthStencilSurfaceGetBackgroundDepth.S b/softfp-shim/wrappers/sceGxmDepthStencilSurfaceGetBackgroundDepth.S deleted file mode 100644 index 8740dae4..00000000 --- a/softfp-shim/wrappers/sceGxmDepthStencilSurfaceGetBackgroundDepth.S +++ /dev/null @@ -1,14 +0,0 @@ - .syntax unified - .thumb - .text - .align 2 - .global sceGxmDepthStencilSurfaceGetBackgroundDepth - .thumb_func - .type sceGxmDepthStencilSurfaceGetBackgroundDepth, %function -sceGxmDepthStencilSurfaceGetBackgroundDepth: - push {lr} - bl __vita_softfp_target_sceGxmDepthStencilSurfaceGetBackgroundDepth - vmov r0, s0 - pop {lr} - bx lr - .size sceGxmDepthStencilSurfaceGetBackgroundDepth, . - sceGxmDepthStencilSurfaceGetBackgroundDepth diff --git a/softfp-shim/wrappers/sceGxmDepthStencilSurfaceSetBackgroundDepth.S b/softfp-shim/wrappers/sceGxmDepthStencilSurfaceSetBackgroundDepth.S deleted file mode 100644 index e22f641e..00000000 --- a/softfp-shim/wrappers/sceGxmDepthStencilSurfaceSetBackgroundDepth.S +++ /dev/null @@ -1,11 +0,0 @@ - .syntax unified - .thumb - .text - .align 2 - .global sceGxmDepthStencilSurfaceSetBackgroundDepth - .thumb_func - .type sceGxmDepthStencilSurfaceSetBackgroundDepth, %function -sceGxmDepthStencilSurfaceSetBackgroundDepth: - vmov s0, r1 - b __vita_softfp_target_sceGxmDepthStencilSurfaceSetBackgroundDepth - .size sceGxmDepthStencilSurfaceSetBackgroundDepth, . - sceGxmDepthStencilSurfaceSetBackgroundDepth diff --git a/softfp-shim/wrappers/sceGxmSetViewport.S b/softfp-shim/wrappers/sceGxmSetViewport.S deleted file mode 100644 index e1520a35..00000000 --- a/softfp-shim/wrappers/sceGxmSetViewport.S +++ /dev/null @@ -1,19 +0,0 @@ - .syntax unified - .thumb - .text - .align 2 - .global sceGxmSetViewport - .thumb_func - .type sceGxmSetViewport, %function -sceGxmSetViewport: - vmov s0, r1 - vmov s1, r2 - vmov s2, r3 - ldr r1, [sp, #0] - vmov s3, r1 - ldr r2, [sp, #4] - vmov s4, r2 - ldr r3, [sp, #8] - vmov s5, r3 - b __vita_softfp_target_sceGxmSetViewport - .size sceGxmSetViewport, . - sceGxmSetViewport diff --git a/softfp-shim/wrappers/sceGxmSetWClampValue.S b/softfp-shim/wrappers/sceGxmSetWClampValue.S deleted file mode 100644 index 317ec0c0..00000000 --- a/softfp-shim/wrappers/sceGxmSetWClampValue.S +++ /dev/null @@ -1,11 +0,0 @@ - .syntax unified - .thumb - .text - .align 2 - .global sceGxmSetWClampValue - .thumb_func - .type sceGxmSetWClampValue, %function -sceGxmSetWClampValue: - vmov s0, r1 - b __vita_softfp_target_sceGxmSetWClampValue - .size sceGxmSetWClampValue, . - sceGxmSetWClampValue diff --git a/softfp-shim/wrappers/sceMotionGetAngleThreshold.S b/softfp-shim/wrappers/sceMotionGetAngleThreshold.S deleted file mode 100644 index 89f90736..00000000 --- a/softfp-shim/wrappers/sceMotionGetAngleThreshold.S +++ /dev/null @@ -1,14 +0,0 @@ - .syntax unified - .thumb - .text - .align 2 - .global sceMotionGetAngleThreshold - .thumb_func - .type sceMotionGetAngleThreshold, %function -sceMotionGetAngleThreshold: - push {lr} - bl __vita_softfp_target_sceMotionGetAngleThreshold - vmov r0, s0 - pop {lr} - bx lr - .size sceMotionGetAngleThreshold, . - sceMotionGetAngleThreshold diff --git a/softfp-shim/wrappers/sceMotionRotateYaw.S b/softfp-shim/wrappers/sceMotionRotateYaw.S deleted file mode 100644 index 858fd2d3..00000000 --- a/softfp-shim/wrappers/sceMotionRotateYaw.S +++ /dev/null @@ -1,11 +0,0 @@ - .syntax unified - .thumb - .text - .align 2 - .global sceMotionRotateYaw - .thumb_func - .type sceMotionRotateYaw, %function -sceMotionRotateYaw: - vmov s0, r0 - b __vita_softfp_target_sceMotionRotateYaw - .size sceMotionRotateYaw, . - sceMotionRotateYaw diff --git a/softfp-shim/wrappers/sceMotionSetAngleThreshold.S b/softfp-shim/wrappers/sceMotionSetAngleThreshold.S deleted file mode 100644 index e35e4dab..00000000 --- a/softfp-shim/wrappers/sceMotionSetAngleThreshold.S +++ /dev/null @@ -1,11 +0,0 @@ - .syntax unified - .thumb - .text - .align 2 - .global sceMotionSetAngleThreshold - .thumb_func - .type sceMotionSetAngleThreshold, %function -sceMotionSetAngleThreshold: - vmov s0, r0 - b __vita_softfp_target_sceMotionSetAngleThreshold - .size sceMotionSetAngleThreshold, . - sceMotionSetAngleThreshold diff --git a/softfp-shim/wrappers/scePafGraphicsUpdateCurrentWave.S b/softfp-shim/wrappers/scePafGraphicsUpdateCurrentWave.S deleted file mode 100644 index 88853e8b..00000000 --- a/softfp-shim/wrappers/scePafGraphicsUpdateCurrentWave.S +++ /dev/null @@ -1,11 +0,0 @@ - .syntax unified - .thumb - .text - .align 2 - .global scePafGraphicsUpdateCurrentWave - .thumb_func - .type scePafGraphicsUpdateCurrentWave, %function -scePafGraphicsUpdateCurrentWave: - vmov s0, r1 - b __vita_softfp_target_scePafGraphicsUpdateCurrentWave - .size scePafGraphicsUpdateCurrentWave, . - scePafGraphicsUpdateCurrentWave diff --git a/softfp-shim/wrappers/scePvfPixelToPointH.S b/softfp-shim/wrappers/scePvfPixelToPointH.S deleted file mode 100644 index 32a3d2c3..00000000 --- a/softfp-shim/wrappers/scePvfPixelToPointH.S +++ /dev/null @@ -1,16 +0,0 @@ - .syntax unified - .thumb - .text - .align 2 - .global scePvfPixelToPointH - .thumb_func - .type scePvfPixelToPointH, %function -scePvfPixelToPointH: - push {lr} - vmov s0, r1 - mov r1, r2 - bl __vita_softfp_target_scePvfPixelToPointH - vmov r0, s0 - pop {lr} - bx lr - .size scePvfPixelToPointH, . - scePvfPixelToPointH diff --git a/softfp-shim/wrappers/scePvfPixelToPointV.S b/softfp-shim/wrappers/scePvfPixelToPointV.S deleted file mode 100644 index 6c69cf98..00000000 --- a/softfp-shim/wrappers/scePvfPixelToPointV.S +++ /dev/null @@ -1,16 +0,0 @@ - .syntax unified - .thumb - .text - .align 2 - .global scePvfPixelToPointV - .thumb_func - .type scePvfPixelToPointV, %function -scePvfPixelToPointV: - push {lr} - vmov s0, r1 - mov r1, r2 - bl __vita_softfp_target_scePvfPixelToPointV - vmov r0, s0 - pop {lr} - bx lr - .size scePvfPixelToPointV, . - scePvfPixelToPointV diff --git a/softfp-shim/wrappers/scePvfPointToPixelH.S b/softfp-shim/wrappers/scePvfPointToPixelH.S deleted file mode 100644 index bdae78f1..00000000 --- a/softfp-shim/wrappers/scePvfPointToPixelH.S +++ /dev/null @@ -1,16 +0,0 @@ - .syntax unified - .thumb - .text - .align 2 - .global scePvfPointToPixelH - .thumb_func - .type scePvfPointToPixelH, %function -scePvfPointToPixelH: - push {lr} - vmov s0, r1 - mov r1, r2 - bl __vita_softfp_target_scePvfPointToPixelH - vmov r0, s0 - pop {lr} - bx lr - .size scePvfPointToPixelH, . - scePvfPointToPixelH diff --git a/softfp-shim/wrappers/scePvfPointToPixelV.S b/softfp-shim/wrappers/scePvfPointToPixelV.S deleted file mode 100644 index db5a7d19..00000000 --- a/softfp-shim/wrappers/scePvfPointToPixelV.S +++ /dev/null @@ -1,16 +0,0 @@ - .syntax unified - .thumb - .text - .align 2 - .global scePvfPointToPixelV - .thumb_func - .type scePvfPointToPixelV, %function -scePvfPointToPixelV: - push {lr} - vmov s0, r1 - mov r1, r2 - bl __vita_softfp_target_scePvfPointToPixelV - vmov r0, s0 - pop {lr} - bx lr - .size scePvfPointToPixelV, . - scePvfPointToPixelV diff --git a/softfp-shim/wrappers/scePvfSetCharSize.S b/softfp-shim/wrappers/scePvfSetCharSize.S deleted file mode 100644 index 96664367..00000000 --- a/softfp-shim/wrappers/scePvfSetCharSize.S +++ /dev/null @@ -1,12 +0,0 @@ - .syntax unified - .thumb - .text - .align 2 - .global scePvfSetCharSize - .thumb_func - .type scePvfSetCharSize, %function -scePvfSetCharSize: - vmov s0, r1 - vmov s1, r2 - b __vita_softfp_target_scePvfSetCharSize - .size scePvfSetCharSize, . - scePvfSetCharSize diff --git a/softfp-shim/wrappers/scePvfSetEM.S b/softfp-shim/wrappers/scePvfSetEM.S deleted file mode 100644 index f41faa4f..00000000 --- a/softfp-shim/wrappers/scePvfSetEM.S +++ /dev/null @@ -1,11 +0,0 @@ - .syntax unified - .thumb - .text - .align 2 - .global scePvfSetEM - .thumb_func - .type scePvfSetEM, %function -scePvfSetEM: - vmov s0, r1 - b __vita_softfp_target_scePvfSetEM - .size scePvfSetEM, . - scePvfSetEM diff --git a/softfp-shim/wrappers/scePvfSetEmboldenRate.S b/softfp-shim/wrappers/scePvfSetEmboldenRate.S deleted file mode 100644 index 2ef05976..00000000 --- a/softfp-shim/wrappers/scePvfSetEmboldenRate.S +++ /dev/null @@ -1,11 +0,0 @@ - .syntax unified - .thumb - .text - .align 2 - .global scePvfSetEmboldenRate - .thumb_func - .type scePvfSetEmboldenRate, %function -scePvfSetEmboldenRate: - vmov s0, r1 - b __vita_softfp_target_scePvfSetEmboldenRate - .size scePvfSetEmboldenRate, . - scePvfSetEmboldenRate diff --git a/softfp-shim/wrappers/scePvfSetResolution.S b/softfp-shim/wrappers/scePvfSetResolution.S deleted file mode 100644 index 97a78f65..00000000 --- a/softfp-shim/wrappers/scePvfSetResolution.S +++ /dev/null @@ -1,12 +0,0 @@ - .syntax unified - .thumb - .text - .align 2 - .global scePvfSetResolution - .thumb_func - .type scePvfSetResolution, %function -scePvfSetResolution: - vmov s0, r1 - vmov s1, r2 - b __vita_softfp_target_scePvfSetResolution - .size scePvfSetResolution, . - scePvfSetResolution diff --git a/softfp-shim/wrappers/scePvfSetSkewValue.S b/softfp-shim/wrappers/scePvfSetSkewValue.S deleted file mode 100644 index bcffb613..00000000 --- a/softfp-shim/wrappers/scePvfSetSkewValue.S +++ /dev/null @@ -1,12 +0,0 @@ - .syntax unified - .thumb - .text - .align 2 - .global scePvfSetSkewValue - .thumb_func - .type scePvfSetSkewValue, %function -scePvfSetSkewValue: - vmov s0, r1 - vmov s1, r2 - b __vita_softfp_target_scePvfSetSkewValue - .size scePvfSetSkewValue, . - scePvfSetSkewValue diff --git a/softfp-shim/wrappers/sce_paf_strtod.S b/softfp-shim/wrappers/sce_paf_strtod.S deleted file mode 100644 index 9c2f8cae..00000000 --- a/softfp-shim/wrappers/sce_paf_strtod.S +++ /dev/null @@ -1,14 +0,0 @@ - .syntax unified - .thumb - .text - .align 2 - .global sce_paf_strtod - .thumb_func - .type sce_paf_strtod, %function -sce_paf_strtod: - push {lr} - bl __vita_softfp_target_sce_paf_strtod - vmov r0, r1, d0 - pop {lr} - bx lr - .size sce_paf_strtod, . - sce_paf_strtod From 68d049237dafdf9dcff2c6c2024080ef7429cb4a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Francisco=20Jos=C3=A9=20Garc=C3=ADa=20Garc=C3=ADa?= Date: Wed, 19 Aug 2026 23:18:45 +0200 Subject: [PATCH 3/4] Fix vita-makepkg dropping the world's CARCH in bin/makepkg.conf Regressed by an earlier git checkout -- in this same session that reverted this file to HEAD and got only partially undone: vita-makepkg went back to a plain copy of makepkg.conf.sample, which always says CARCH="vita", instead of running it through WriteMakepkgConf.cmake. Caught by CI, not locally: validate-core-package.sh's own world-coherence check failed a real vita-softfp build with "version_info.txt says vita-softfp, bin/makepkg.conf CARCH says vita" on every host. --- cmake/recipes/BuildHostTools.cmake | 6 +++++- cmake/recipes/BuildSdkComponents.cmake | 1 - 2 files changed, 5 insertions(+), 2 deletions(-) diff --git a/cmake/recipes/BuildHostTools.cmake b/cmake/recipes/BuildHostTools.cmake index cc1287f2..b1a07cd8 100644 --- a/cmake/recipes/BuildHostTools.cmake +++ b/cmake/recipes/BuildHostTools.cmake @@ -79,6 +79,10 @@ ExternalProject_Add(vita-makepkg INSTALL_COMMAND ${CMAKE_COMMAND} -E make_directory ${CMAKE_INSTALL_PREFIX}/bin/ COMMAND ${CMAKE_COMMAND} -E copy_directory /libmakepkg ${CMAKE_INSTALL_PREFIX}/bin/libmakepkg COMMAND ${CMAKE_COMMAND} -E copy /vita-makepkg ${CMAKE_INSTALL_PREFIX}/bin/ - COMMAND ${CMAKE_COMMAND} -E copy /makepkg.conf.sample ${CMAKE_INSTALL_PREFIX}/bin/makepkg.conf + COMMAND ${CMAKE_COMMAND} + -DINPUT=/makepkg.conf.sample + -DOUTPUT=${CMAKE_INSTALL_PREFIX}/bin/makepkg.conf + -DWORLD_ARCH=${world_arch} + -P ${PROJECT_SOURCE_DIR}/cmake/WriteMakepkgConf.cmake ${UPDATE_DISCONNECTED_SUPPORT} ) diff --git a/cmake/recipes/BuildSdkComponents.cmake b/cmake/recipes/BuildSdkComponents.cmake index a64f8a05..8dff66d1 100644 --- a/cmake/recipes/BuildSdkComponents.cmake +++ b/cmake/recipes/BuildSdkComponents.cmake @@ -106,4 +106,3 @@ ExternalProject_Add(samples COMMAND ${GIT_EXECUTABLE} -C rev-parse HEAD > ${CMAKE_BINARY_DIR}/samples-version.txt ${UPDATE_DISCONNECTED_SUPPORT} ) - From 0c870078ac4db1e65b7c1a5cd94d2ee231699ad0 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Francisco=20Jos=C3=A9=20Garc=C3=ADa=20Garc=C3=ADa?= Date: Thu, 27 Aug 2026 16:15:15 +0200 Subject: [PATCH 4/4] Make the profile decide the float ABI it names The staged executor takes the profile from the lock, requires it, and then dropped it -- the comment where it landed said as much: "profile is required but not yet consumed: no profile -> VITASDK_FLOAT_ABI mapping exists in CMakeLists.txt yet". So `describe --profile vita-softfp` produced a lock that said softfp and a toolchain that was hard-float, and nothing anywhere said the two disagreed. Profiles.cmake already names the worlds this tree publishes, so it is where the ABI each of them bakes in belongs, next to the name. CMakeLists takes VITASDK_PROFILE, refuses one the tree does not publish, and derives the float ABI and the world's arch from it; build-host.sh passes it in both cmake invocations, since stage 1 builds the sysroot the later stages import. A profile wins over VITASDK_FLOAT_ABI, and silently. CMake cannot tell a cache entry left at its default from one somebody passed, so a check that the two agree would either miss -DVITASDK_FLOAT_ABI=hard or refuse every re-configure of an existing build directory. Passing both is passing the same thing twice. The test runs stage 1 against a cmake that records its arguments, which is what the flag being parsed and dropped would have failed. --- CMakeLists.txt | 24 ++++++++++++++++++++++++ cmake/Profiles.cmake | 6 ++++++ scripts/ci/build-host.sh | 7 ++++--- tests/ci/test-build-host-args.sh | 24 ++++++++++++++++++++++++ 4 files changed, 58 insertions(+), 3 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index 315b62ae..6ecb936c 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -99,6 +99,30 @@ set(target_arch arm-vita-eabi) set(VITASDK_FLOAT_ABI "hard" CACHE STRING "Float ABI baked into the toolchain: hard (default) or softfp") set_property(CACHE VITASDK_FLOAT_ABI PROPERTY STRINGS hard softfp) + +# A profile names a world, and the world decides the ABI rather than the other +# way round: CI asks for a profile because that is what the lock carries, and +# describe already refuses one this repository does not publish. +# +# A profile wins over VITASDK_FLOAT_ABI, and does so silently. CMake cannot +# tell a cache entry left at its default from one somebody passed, so a check +# that the two agree would either miss -DVITASDK_FLOAT_ABI=hard or refuse +# every re-configure of an existing build directory. Passing both is passing +# the same thing twice; the profile is the one that says which world this is. +include(Profiles) +set(VITASDK_PROFILE "" CACHE STRING "World to build; selects the float ABI") +if(VITASDK_PROFILE) + if(NOT VITASDK_PROFILE IN_LIST VITASDK_PROFILES) + message(FATAL_ERROR + "unknown profile '${VITASDK_PROFILE}'; this tree publishes: ${VITASDK_PROFILES}") + endif() + set(profile_float_abi ${VITASDK_PROFILE_FLOAT_ABI_${VITASDK_PROFILE}}) + if(NOT profile_float_abi) + message(FATAL_ERROR "profile '${VITASDK_PROFILE}' declares no float ABI") + endif() + set(VITASDK_FLOAT_ABI ${profile_float_abi} CACHE STRING "" FORCE) +endif() + if(NOT VITASDK_FLOAT_ABI STREQUAL "hard" AND NOT VITASDK_FLOAT_ABI STREQUAL "softfp") message(FATAL_ERROR "VITASDK_FLOAT_ABI must be 'hard' or 'softfp', got '${VITASDK_FLOAT_ABI}'") endif() diff --git a/cmake/Profiles.cmake b/cmake/Profiles.cmake index 981b42ec..ca3f557c 100644 --- a/cmake/Profiles.cmake +++ b/cmake/Profiles.cmake @@ -2,3 +2,9 @@ include_guard(GLOBAL) # Published profile (world) names; describe rejects anything else. set(VITASDK_PROFILES vita vita-softfp) + +# The float ABI each profile bakes into the toolchain. A profile is a world and +# a world is named by the architecture its packages carry, so the name is the +# same on both sides of the build. +set(VITASDK_PROFILE_FLOAT_ABI_vita hard) +set(VITASDK_PROFILE_FLOAT_ABI_vita-softfp softfp) diff --git a/scripts/ci/build-host.sh b/scripts/ci/build-host.sh index 66d91d8a..912ff00d 100755 --- a/scripts/ci/build-host.sh +++ b/scripts/ci/build-host.sh @@ -71,9 +71,6 @@ for required in host stage artifacts_dir out_dir build_id version revision profi exit 2 } done -# profile is required but not yet consumed: no profile -> VITASDK_FLOAT_ABI -# mapping exists in CMakeLists.txt yet. -: "$profile" actual_revision=$(git -C "$repo_root" rev-parse HEAD) [[ $actual_revision == "$revision" ]] || { @@ -175,6 +172,9 @@ build_and_stage() { local -a extra_args=("$@") local -a cmake_args=( -S "$repo_root" -B build ${extra_args[@]+"${extra_args[@]}"} + # The lock says which world this is; the profile is how the tree is + # told, and it is what decides the float ABI baked into the toolchain. + -DVITASDK_PROFILE="$profile" -DVITASDK_SOURCE_REVISION="$revision" -DVITASDK_SOURCE_DATE_EPOCH="$source_date_epoch" # The lock names the host; artifacts published under any other name @@ -363,6 +363,7 @@ if [[ $stage == 1 ]]; then enable_ccache cmake -S "$repo_root" -B build \ -DVITASDK_TARGET_ONLY=ON \ + -DVITASDK_PROFILE="$profile" \ -DVITASDK_SOURCE_REVISION="$revision" \ -DVITASDK_SOURCE_DATE_EPOCH="$source_date_epoch" cmake --build build --target sysroot --parallel "$(ci_nproc)" diff --git a/tests/ci/test-build-host-args.sh b/tests/ci/test-build-host-args.sh index f69a821e..cc7fe47c 100755 --- a/tests/ci/test-build-host-args.sh +++ b/tests/ci/test-build-host-args.sh @@ -124,4 +124,28 @@ grep -q 'curl disabled in test' <<< "$output" || { exit 1 } +# 6. The profile reaches cmake. The lock is where CI says which world it is +# building, and the profile is the only thing that carries it into the tree; +# until this existed the flag was parsed, required, and then dropped, so a +# softfp lock produced a hard-float toolchain that said nothing. +recorded="$temporary_directory/cmake-args" +cat > "$fake_bin/cmake" <> "$recorded" +exit 0 +EOF +chmod +x "$fake_bin/cmake" + +run_build_host \ + --host x86_64-linux-gnu --stage 1 \ + --artifacts-dir "$temporary_directory/artifacts-6" --out-dir "$temporary_directory/out-6" \ + --build-id sha256:test --version 0.1.1 --revision "$revision" \ + --profile vita-softfp --packaged false >/dev/null 2>&1 || true + +grep -qx -- '-DVITASDK_PROFILE=vita-softfp' "$recorded" || { + printf 'stage 1 did not pass the profile to cmake:\n%s\n' "$(cat "$recorded")" >&2 + exit 1 +} +rm -f "$fake_bin/cmake" "$recorded" + printf 'build-host.sh argument contract tests passed\n'