2

I have usercall with calling convention I do not fully understand, it returns std::string but IDA recognize it as void.

I've noticed that every calle reads from x8/w8 afterwards, from wikipedia;

x8: used to hold indirect return value address

Can someone explain "indirect return value address" ?

From https://docs.microsoft.com/en-us/cpp/build/arm64-windows-abi-conventions?view=vs-2019

Return values

Integral values are returned in x0.

Floating-point values are returned in s0, d0, or v0, as appropriate.

HFA and HVA values are returned in s0-s3, d0-d3, or v0-v3, as appropriate.

Types returned by value are handled differently depending on whether they have certain properties. Types which have all of these properties,

they're aggregate by the C++14 standard definition, that is, they have no user-provided constructors, no private or protected non-static data members, no base classes, and no virtual functions, and they have a trivial copy-assignment operator, and they have a trivial destructor, use the following return style:

Types less than or equal to 8 bytes are returned in x0. Types less than or equal to 16 bytes are returned in x0 and x1, with x0 containing the lower-order 8 bytes.

For types greater than 16 bytes, the caller shall reserve a block of memory of sufficient size and alignment to hold the result. The address of the memory block shall be passed as an additional argument to the function in x8. The callee may modify the result memory block at any point during the execution of the subroutine. The callee isn't required to preserve the value stored in x8.

All other types use this convention:

The caller shall reserve a block of memory of sufficient size and alignment to hold the result. The address of the memory block shall be passed as an additional argument to the function in x0, or x1 if $this is passed in x0. The callee may modify the result memory block at any point during the execution of the subroutine. The callee returns the address of the memory block in x0.

Update 2:

From ARM docs

Registers with a special purpose

• X8 is the indirect result register. This is used to pass the address location of an indirect result, for example, where a function returns a large structure. ...

... the structure contains more than 16 bytes. According to the AAPCS for AArch64, the returned object is written to the memory pointed to by XR.

1 Answer 1

2

From https://github.com/Siguza/ios-resources/blob/master/bits/arm64.md

x8 pointer to where to write the return value if >128 bits, otherwise scratch register

So it seems x8 is used to pass an address at which the return value will land if it's too big, rather than the return value directly, hence indirect I suppose.

I couldn't find official documentation as the ARM page was barely loading for me.

2
  • why not return a pointer in x0?
    – James W.
    Commented Dec 9, 2019 at 19:05
  • I have no idea, it's a convention after all. If I had to make up a reason, I'd say this allows some performance optimization. If you dedicate one register as a register that's likely going to contain an address, you could physically optimize the wiring so fetching data from memory pointed at by x8 is fast. You don't want to do that for all of them, so you pick one register with special treatment and make using it as a memory-pointing register a convention. Commented Dec 9, 2019 at 19:23

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Not the answer you're looking for? Browse other questions tagged or ask your own question.