Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Syscalls 64-bit values passed as arguments on 32-bit architectures #1338

Closed
lacraig2 opened this issue Aug 25, 2023 · 2 comments
Closed

Syscalls 64-bit values passed as arguments on 32-bit architectures #1338

lacraig2 opened this issue Aug 25, 2023 · 2 comments

Comments

@lacraig2
Copy link
Member

Several architectures are incorrectly handling passing of 64-bit values on 32-bit hosts.

In x86, it appears that we copy the same register to high and low bits:

uint64_t get_64_linux_x86(CPUState *cpu, uint32_t argnum) {
assert (argnum < 6);
return (((uint64_t) get_linux_x86_argnum(cpu, argnum)) << 32) | (get_linux_x86_argnum(cpu, argnum));
}

which even if corrected to be the next argument doesn't fix the issue of the next argument being on the wrong index.

In ARM, we get closer:

uint64_t get_64_linux_arm(CPUState *cpu, uint32_t argnum) {
#ifdef TARGET_ARM
CPUArchState *env = (CPUArchState*)cpu->env_ptr;
#if !defined(TARGET_AARCH64)
// arm32 regs in r0-r6
assert (argnum < 7);
return (((uint64_t) env->regs[argnum]) << 32) | (env->regs[argnum+1]);
#else
// aarch64 fits 64 bit registers in regs in x0-x5
assert (argnum < 6);
return (uint64_t) env->xregs[argnum];
#endif
#else
return 0;
#endif
}

However, we don't increment the argument and so are one off for any syscall following. Further, ARM requires these 64-bit extended values to be on even registers. See: https://man7.org/linux/man-pages/man2/syscall.2.html

For example, on the ARM architecture Embedded ABI (EABI), a
64-bit value (e.g., long long) must be aligned to an even
register pair. Thus, using syscall() instead of the wrapper
provided by glibc, the readahead(2) system call would be invoked
as follows on the ARM architecture with the EABI in little endian
mode:

       syscall(SYS_readahead, fd, 0,
               (unsigned int) (offset & 0xFFFFFFFF),
               (unsigned int) (offset >> 32),
               count);

In MIPS we make no real attempt at resolving this. This issue is connected to #1337, but there will be independent fixes required.

@lacraig2
Copy link
Member Author

We use readahead as a good example for various architectures:

In x86 we see that our 64-bit value should be converted into 2 32-bit arguments.

                             *                          FUNCTION                          *
                             **************************************************************
                             ssize_t __cdecl readahead(int __fd, __off64_t __offset, 
             ssize_t           EAX:4          <RETURN>
             int               Stack[0x4]:4   __fd                                    XREF[2]:     000306d7(R), 
                                                                                                   000306e6(W)  
             __off64_t         Stack[0x8]:8   __offset                                XREF[1,1]:   000306cf(R), 
                                                                                                   000306d3(R)  
             size_t            Stack[0x10]:4  __count                                 XREF[1]:     000306db(R)  
             ulong             EAX:4          __ret
                             readahead                                       XREF[1]:     Entry Point(*)  
        000306c8 56              PUSH       ESI
        000306c9 b8 e1 00        MOV        __ret,0xe1
                 00 00
        000306ce 53              PUSH       EBX
        000306cf 8b 4c 24 10     MOV        ECX,dword ptr [ESP + __offset]
        000306d3 8b 54 24 14     MOV        EDX,dword ptr [ESP + __offset+0x4]
        000306d7 8b 5c 24 0c     MOV        EBX,dword ptr [ESP + __fd]
        000306db 8b 74 24 18     MOV        ESI,dword ptr [ESP + __count]
        000306df 65 ff 15        CALL       dword ptr GS:[0x10]
                 10 00 00 00
        000306e6 89 44 24 0c     MOV        dword ptr [ESP + __fd],__ret
        000306ea 5b              POP        EBX
        000306eb 5e              POP        ESI
        000306ec e9 f8 dc        JMP        __syscall_ret                                    long __syscall_ret(ulong r)
                 ff ff
                             -- Flow Override: CALL_RETURN (CALL_TERMINATOR)

On ARM, we can confirm what the documentation was telling us that 64-bit values need to be at even offsets.

                             **************************************************************
                             *                          FUNCTION                          *
                             **************************************************************
                             ssize_t __stdcall readahead(int __fd, __off64_t __offset
             ssize_t           r0:4           <RETURN>
             int               r0:4           __fd
             __off64_t         Stack[0x0]:8   __offset                                XREF[1]:     000376e8(R)  
             size_t            r1:4           __count
             undefined4        Stack[-0x8]:4  local_8                                 XREF[1]:     000376f4(*)  
                             readahead                                       XREF[1]:     Entry Point(*)  
        000376e0 90 00 2d e9     stmdb      sp!,{r4,r7}
        000376e4 00 10 a0 e3     mov        __count,#0x0
        000376e8 08 40 9d e5     ldr        r4,[sp,#__offset]
        000376ec e1 70 a0 e3     mov        r7,#0xe1
        000376f0 00 00 00 ef     swi        0x0
        000376f4 90 00 bd e8     ldmia      sp!,{r4,r7}=>local_8
        000376f8 32 f8 ff ea     b          __syscall_ret                                    undefined __syscall_ret()
                             -- Flow Override: CALL_RETURN (CALL_TERMINATOR)

On MIPS it appears that we simply need to increment the argument and follow a similar offset adding:

                   **************************************************************
                             *                          FUNCTION                          *
                             **************************************************************
                             ssize_t __stdcall readahead(int __fd, __off64_t __offset
                               assume gp = 0x1063d0
                               assume t9 = 0x3ea54
             ssize_t           v0:4           <RETURN>
             int               a0:4           __fd
             __off64_t         Stack[0x10]:8  __offset                                XREF[1]:     0003ea60(R)  
             size_t            a1:4           __count
             undefined4        Stack[-0x10]:4 local_10                                XREF[1]:     0003ea6c(W)  
                             readahead                                       XREF[1]:     Entry Point(*)  
        0003ea54 3c 1c 00 0c     lui        gp,0xc
             assume t9 = <UNKNOWN>
             assume gp = <UNKNOWN>
        0003ea58 27 9c 79 7c     addiu      gp,gp,0x797c
        0003ea5c 03 99 e0 21     addu       gp,gp,t9
        0003ea60 8f a8 00 10     lw         t0,__offset(sp)
        0003ea64 00 00 28 25     or         __count,zero,zero
        0003ea68 27 bd ff e0     addiu      sp,sp,-0x20
        0003ea6c af a8 00 10     sw         t0,local_10(sp)
        0003ea70 24 02 10 7f     li         v0,0x107f
        0003ea74 00 00 00 0c     syscall
        0003ea78 27 bd 00 20     addiu      sp,sp,0x20
        0003ea7c 10 e0 00 04     beq        a3,zero,LAB_0003ea90
        0003ea80 00 40 20 25     _or        __fd,v0,zero
        0003ea84 18 40 00 02     blez       v0,LAB_0003ea90
        0003ea88 00 00 00 00     _nop
        0003ea8c 00 02 20 23     subu       __fd,zero,v0
                             LAB_0003ea90                                    XREF[2]:     0003ea7c(j), 0003ea84(j)  
        0003ea90 8f 99 80 e8     lw         t9,-0x7f18(gp)=>->__syscall_ret                  = 0003b29c
        0003ea94 00 00 00 00     nop
        0003ea98 10 00 f2 00     b          __syscall_ret                                    undefined __syscall_ret()
        0003ea9c 00 00 00 00     _nop
                             -- Flow Override: CALL_RETURN (CALL_TERMINATOR)

@lacraig2
Copy link
Member Author

Fixed with #1342

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

1 participant