Fix sceNetHtonl/Htons/Ntohl/Ntohs discarding their converted result (#211)

Each of the four byte-order helpers computed the swap into Rax and then
returned via ctx.SetReturn(0). SetReturn writes its argument into Rax, so it
immediately overwrote the converted value with 0 and the guest saw every
sceNetHtonl / sceNetHtons / sceNetNtohl / sceNetNtohs call return 0.

Leave the swapped value in Rax and return ORBIS_GEN2_OK as the dispatch status
instead, matching how the value-returning exports in this file (e.g.
sceNetPoolCreate) already work.

Add a NetExports test suite covering the swaps, the 16-bit width masking, an
htonl/ntohl round-trip, and a regression guard that a non-zero input never
converts to 0.
This commit is contained in:
can
2026-07-16 16:24:34 +03:00
committed by GitHub
parent 26dbad8ac8
commit a8be1daca4
2 changed files with 106 additions and 4 deletions
+12 -4
View File
@@ -344,8 +344,10 @@ public static class NetExports
public static int NetHtonl(CpuContext ctx)
{
var value = unchecked((uint)ctx[CpuRegister.Rdi]);
// The byte-swapped result is the return value and already lives in Rax; return OK as the
// dispatch status without going through SetReturn, which would overwrite Rax with 0.
ctx[CpuRegister.Rax] = BinaryPrimitives.ReverseEndianness(value);
return ctx.SetReturn(0);
return (int)OrbisGen2Result.ORBIS_GEN2_OK;
}
[SysAbiExport(
@@ -356,8 +358,10 @@ public static class NetExports
public static int NetHtons(CpuContext ctx)
{
var value = unchecked((ushort)ctx[CpuRegister.Rdi]);
// The byte-swapped result is the return value and already lives in Rax; return OK as the
// dispatch status without going through SetReturn, which would overwrite Rax with 0.
ctx[CpuRegister.Rax] = BinaryPrimitives.ReverseEndianness(value);
return ctx.SetReturn(0);
return (int)OrbisGen2Result.ORBIS_GEN2_OK;
}
[SysAbiExport(
@@ -368,8 +372,10 @@ public static class NetExports
public static int NetNtohl(CpuContext ctx)
{
var value = unchecked((uint)ctx[CpuRegister.Rdi]);
// The byte-swapped result is the return value and already lives in Rax; return OK as the
// dispatch status without going through SetReturn, which would overwrite Rax with 0.
ctx[CpuRegister.Rax] = BinaryPrimitives.ReverseEndianness(value);
return ctx.SetReturn(0);
return (int)OrbisGen2Result.ORBIS_GEN2_OK;
}
[SysAbiExport(
@@ -380,8 +386,10 @@ public static class NetExports
public static int NetNtohs(CpuContext ctx)
{
var value = unchecked((ushort)ctx[CpuRegister.Rdi]);
// The byte-swapped result is the return value and already lives in Rax; return OK as the
// dispatch status without going through SetReturn, which would overwrite Rax with 0.
ctx[CpuRegister.Rax] = BinaryPrimitives.ReverseEndianness(value);
return ctx.SetReturn(0);
return (int)OrbisGen2Result.ORBIS_GEN2_OK;
}
[SysAbiExport(