mirror of
https://github.com/Cesarus85/ringfall-mjolnir-vr.git
synced 2026-10-17 11:00:27 +02:00
Compare commits
6
Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
7c294c9c39 | ||
|
|
f90d955527 | ||
|
|
085676d827 | ||
|
|
4301ca88d6 | ||
|
|
9c70f5f5e3 | ||
|
|
d9669f6eef |
No files matched your search
@@ -99,7 +99,7 @@ jobs:
|
||||
|
||||
- name: Test
|
||||
run: |
|
||||
python -m pytest -q tools/test_linux_port.py tools/test_host_watch_hash.py tools/test_touch_menu.py tools/harness tools/test_profile.py
|
||||
python -m pytest -q tools/test_linux_port.py tools/test_android_asm_convert.py tools/test_host_watch_hash.py tools/test_touch_menu.py tools/harness tools/test_profile.py
|
||||
python tools/test_light_storage.py
|
||||
|
||||
- name: Compile cache
|
||||
|
||||
@@ -388,7 +388,9 @@ The guest is the game, the platform layer and a small runtime:
|
||||
AArch64 target of clang. The options `-U__APPLE__` and
|
||||
`-fno-define-target-os-macros` hide the Darwin environment.
|
||||
2. `tools/android_asm_convert.py` changes the Mach-O assembly to ELF
|
||||
assembly.
|
||||
assembly. It renames symbols, but keeps string literals (`.ascii`,
|
||||
`.asciz`) byte for byte: they hold tables as well as text
|
||||
(`tools/test_android_asm_convert.py`).
|
||||
3. The AArch64 assembler makes the objects.
|
||||
4. `ld.lld` links the objects with `guest/guest.ld` to a static image,
|
||||
`build/android/halo_guest.elf`, at a fixed address above the Xbox memory
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<!-- The PC version's menus: ui\shell\main_menu\multiplayer_type_select\connected (tools/ce_menus.py) -->
|
||||
<menus>
|
||||
<widget name="main_menu/multiplayer_type_select/connected/connected_map_select_wrapper" width="640" height="480" flags="pass_unhandled_to_focused_child pause_game tag_controller_index force_handle_mouse">
|
||||
<widget name="main_menu/multiplayer_type_select/connected/connected_map_select_wrapper" width="640" height="480" flags="pass_unhandled_to_focused_child pause_game main_menu_if_no_history tag_controller_index force_handle_mouse">
|
||||
<child widget="main_menu/multiplayer_type_select/mp_map_select/mp_map_select_screen"/>
|
||||
</widget>
|
||||
<widget name="main_menu/multiplayer_type_select/connected/gametype_select_screen_wrapper" width="640" height="480" flags="pass_unhandled_to_focused_child pause_game">
|
||||
|
||||
@@ -395,6 +395,10 @@ void voice_audio_play(int speaker, unsigned short sequence, const unsigned char
|
||||
|
||||
if (length <= 0 || length > VOICE_MAXIMUM_PACKET)
|
||||
return;
|
||||
/* (every build sends a frame of 20 ms: anything else, damaged, is
|
||||
dropped before the decoder sees it, and made up for as lost) */
|
||||
if (opus_packet_get_nb_samples(packet, length, VOICE_RATE) != VOICE_FRAME_SAMPLES)
|
||||
return;
|
||||
pthread_mutex_lock(&voice_lock);
|
||||
slot = voice_slot_for(speaker, TRUE);
|
||||
if (!slot)
|
||||
|
||||
@@ -15,7 +15,13 @@ Usage: android_asm_convert.py input.s output.s
|
||||
import re
|
||||
import sys
|
||||
|
||||
IDENT = re.compile(r'"[^"]*"|[A-Za-z_.$][\w.$]*')
|
||||
# a quoted name (its escapes kept: \" does not end it) or a plain one
|
||||
IDENT = re.compile(r'"(?:[^"\\]|\\.)*"|[A-Za-z_.$][\w.$]*')
|
||||
|
||||
# directives whose operands are string literals, the same in both
|
||||
# syntaxes: they go through as they are, never renamed as symbols (data
|
||||
# starting with "_" would lose that byte)
|
||||
STRING_DIRECTIVES = {".ascii", ".asciz", ".string"}
|
||||
|
||||
DROP_DIRECTIVES = {
|
||||
".subsections_via_symbols", ".build_version", ".watchos_version_min",
|
||||
@@ -217,10 +223,7 @@ class Converter:
|
||||
if op == ".align":
|
||||
self.emit(f"\t.p2align {args}")
|
||||
return
|
||||
if op in (".ascii", ".asciz", ".string"):
|
||||
# string data, kept as it is: no symbol names in it (renamed, a
|
||||
# "_" at the start of a word was dropped: a string with \" in it
|
||||
# went wrong, Opus's tables among them)
|
||||
if op in STRING_DIRECTIVES:
|
||||
self.emit(f"\t{op} {args}")
|
||||
return
|
||||
if op.startswith("."):
|
||||
|
||||
@@ -22,7 +22,7 @@ no files beside its guest image.
|
||||
|
||||
The data are 32-bit words, not bytes: the Android build passes the guest's
|
||||
assembly through tools/android_asm_convert.py, which rewrites identifiers in
|
||||
operands and would garble a long .ascii string of binary data.
|
||||
operands (it keeps .ascii strings as they are, but once garbled them).
|
||||
"""
|
||||
|
||||
import json
|
||||
|
||||
@@ -618,6 +618,11 @@ MAP_KIND_CHOOSER = "main_menu/new_select/list_item_0_map_kind"
|
||||
# changes to the PC version's widgets (by our names): attributes set, all
|
||||
# their handlers replaced, children added, game data inputs added
|
||||
WIDGET_PATCHES = {
|
||||
# The host returns here after a round with no menu history. Back must
|
||||
# reopen the main menu when it closes the last screen, as the lobby does.
|
||||
f"{MT}/connected/connected_map_select_wrapper": {"set": {
|
||||
"flags": "pass_unhandled_to_focused_child pause_game main_menu_if_no_history tag_controller_index force_handle_mouse",
|
||||
}},
|
||||
# (the profile settings' picture: on Gamepad Setup's row, the profile's
|
||||
# button settings, BITMAP_FRAMES; menu_functions.c's
|
||||
# profile_gamepad_layout)
|
||||
|
||||
@@ -1,32 +1,76 @@
|
||||
"""Tests of tools/android_asm_convert.py, the Mach-O to ELF assembly
|
||||
conversion of the Android build's guest code."""
|
||||
"""The Darwin to ELF assembly conversion of the ILP32 guest
|
||||
(tools/android_asm_convert.py): string literals keep every byte. It once took
|
||||
a quoted .ascii operand for a quoted symbol name and dropped its leading "_"
|
||||
(and, after an escaped quote, the "_" of any word after it), which shifted
|
||||
tables such as Opus's pulse cache by a byte: voice chat crashed in
|
||||
decode_pulses on the arm64 and Android builds."""
|
||||
import shutil
|
||||
import struct
|
||||
import subprocess
|
||||
import sys
|
||||
from pathlib import Path
|
||||
|
||||
sys.path.insert(0, str(Path(__file__).resolve().parent))
|
||||
import pytest
|
||||
|
||||
from android_asm_convert import Converter # noqa: E402
|
||||
from tools.android_asm_convert import Converter
|
||||
|
||||
ROOT = Path(__file__).resolve().parent.parent
|
||||
|
||||
|
||||
def convert(*lines):
|
||||
return Converter(list(lines)).run().split("\n")
|
||||
return Converter(list(lines)).run().splitlines()
|
||||
|
||||
|
||||
def test_symbols_lose_their_underscore():
|
||||
out = convert("_main:", "\tbl\t_foo", "\t.long\t_bar")
|
||||
assert out[:3] == ["main:", "\tbl foo", "\t.long bar"]
|
||||
@pytest.mark.parametrize("directive", [
|
||||
'.ascii\t"_c[}]L{s{"',
|
||||
'.asciz\t"_transport_error_none"',
|
||||
'.ascii\t"v\\177\\"O7v\\177_\\037\\374"',
|
||||
'.ascii\t"=`\'\\\\_\\026"',
|
||||
'.asciz\t"ltmp0 _x @PAGE ; not a comment"',
|
||||
])
|
||||
def test_string_literals_are_kept(directive):
|
||||
op, args = directive.split("\t", 1)
|
||||
assert convert("l_.str:", directive) == [".Ll_.str:", f"\t{op} {args}"]
|
||||
|
||||
|
||||
def test_strings_are_kept():
|
||||
# (a string starting with "_", or one with \" in it, lost a "_": Opus's
|
||||
# pulse cache was one byte short, and its encoder crashed)
|
||||
out = convert(
|
||||
'\t.asciz\t"_lan_"',
|
||||
'\t.ascii\t"\\"$&\'\\0063_\\206"',
|
||||
'\t.string\t"l_.str _foo"',
|
||||
)
|
||||
assert out[:3] == [
|
||||
'\t.asciz "_lan_"',
|
||||
'\t.ascii "\\"$&\'\\0063_\\206"',
|
||||
'\t.string "l_.str _foo"',
|
||||
]
|
||||
def test_symbols_are_still_renamed():
|
||||
assert convert("\t.globl\t_table", "_table:", "\tadrp\tx8, _table@PAGE",
|
||||
"\tadd\tx8, x8, _table@PAGEOFF", '\t.long\t"_odd name"') == [
|
||||
"\t.globl table", "table:", "\tadrp x8, table", "\tadd x8, x8, :lo12:table", '\t.long "odd name"']
|
||||
|
||||
|
||||
def rodata(elf: bytes) -> bytes:
|
||||
"""the .rodata section of a 64-bit little-endian ELF object"""
|
||||
shoff, = struct.unpack_from("<Q", elf, 0x28)
|
||||
shentsize, shnum, shstrndx = struct.unpack_from("<HHH", elf, 0x3a)
|
||||
sections = [struct.unpack_from("<IIQQQQ", elf, shoff + index * shentsize) for index in range(shnum)]
|
||||
names = sections[shstrndx][4]
|
||||
for name, _, _, _, offset, size in sections:
|
||||
if elf[names + name:elf.index(b"\0", names + name)] == b".rodata":
|
||||
return elf[offset:offset + size]
|
||||
raise AssertionError("no .rodata")
|
||||
|
||||
|
||||
def test_tables_survive_the_build(tmp_path):
|
||||
"""every byte value, and the patterns that were lost, through the
|
||||
guest's pipeline (clang for arm64_32, the conversion, the assembler)"""
|
||||
clang = shutil.which("clang")
|
||||
if not clang:
|
||||
pytest.skip("no clang")
|
||||
table = bytes(range(256)) + b'_a"_b\\_c' + bytes(reversed(range(256)))
|
||||
source = tmp_path / "table.c"
|
||||
source.write_text(
|
||||
"const unsigned char table[] = {" + ",".join(str(b) for b in table) + "};\n"
|
||||
'const char text[] = "_starts with an underscore";\n')
|
||||
darwin, converted, obj = tmp_path / "table.darwin.s", tmp_path / "table.s", tmp_path / "table.o"
|
||||
try:
|
||||
subprocess.run([clang, "--target=arm64_32-apple-watchos", "-O2", "-S", str(source), "-o", str(darwin)],
|
||||
check=True, capture_output=True)
|
||||
except subprocess.CalledProcessError:
|
||||
pytest.skip("clang has no arm64_32 target")
|
||||
subprocess.run([sys.executable, str(ROOT / "tools" / "android_asm_convert.py"), str(darwin), str(converted)],
|
||||
check=True)
|
||||
subprocess.run([clang, "--target=aarch64-linux-gnu", "-c", str(converted), "-o", str(obj)], check=True)
|
||||
data = rodata(obj.read_bytes())
|
||||
assert table in data
|
||||
assert b"_starts with an underscore\0" in data
|
||||
Reference in new issue
Block a user