I need to create a function in asm (on Windows) that replicates the following behaviour:
_int64 q(_int64 a, _int64 b, _int64 c, _int64 d, _int64 e) {
_int64 sum = a + b + c + d + e;
printf("a = %I64d b = %I64d c = %I64d d = %I64d e = %I64d sum = %I64d\n", a, b, c, d, e, sum);
return sum;
}
I know I need to allocate shadow space for printf and also that I need to store some parameters in the stack, because only the first 4 parameters are in registers (rcx, rdx, r8 and r9)
My problem comes with the string format and the stack management. My code so far looks like this:
.data
string1 dq 'a = %I64d b = %I64d c = %I64d d = %I64d e = %I64d sum = %I64d', 10, 0 ; The printf format, "\n",'0'
.code
public q ;a in rcx, b in rdx, c in r8, d in r9, e in stack
q: push rbp
mov rbp, rsp
sub rsp, 32 ;allocating shadow space for printf
;for calling printf, we need to have [string] in rcx,
;a in rdx, b in r8, c in r9, d in stack1, e in stack2, and sum in stack3
add rax, rcx ;first make the sum
add rax, rdx
add rax, r8
add rax, r9
mov rbx, [rbp + 8] ;getting e from the stack
add rax, rbx ;final add, in rax now is sum
push rax ;changing parameters in registers (last 3 in stack)
push rbx
push r9
mov r9, r8 ;c in r9
mov r8, rdx ;b in r8
mov rdx, rcx ;a in rdx
lea rcx, [string] ;string in rcx
call printf
mov rsp, rbp ;back to previous pointer
pop rbp ;release resources
ret 0
end
At this moment it does not compile, with an
error A2084: constant value too large
I don't know if I need to change the format or split it in 2, in that case I need to storage some other parameter in the stack, and then I am not very sure how to proceed...
If that error is on the line with the string, use db
instead of dq
: you don't want the 10, 0
elements padded to qwords even if it did accept the quoted part as a string the way NASM does.
I think MASM allows quoted constants for db
, so that should get it to assemble.
And then we have multiple other bugs at runtime:
Also, you need to sub rsp, 32
to reserve shadow space after pushing 3 registers, if you want to restore them after. Otherwise those 24 bytes are the bottom of the shadow space the called function (printf
) sees.
But that's pointless because you're not restoring them after the call. So you violate the calling convention by clobbering rbx
; It doesn't look like you're doing anything with them after the call, so just use a call-clobbered reg, or better calculate the value in the right arg-passing register in the first place.