Reputation: 1308
I'm trying to get my head around printing doubles in assembly but I'm failing miserably. I'm getting segfault when calling my own function that I'm planning to use as a helper to print doubles for debugging purposes. I was following these printf
examples: https://www.csee.umbc.edu/portal/help/nasm/sample.shtml
My code currently looks like this:
section .data
formatStrf: db `The number is %f\n`,0
section .text
extern printf
printfcallfloat:
;Pass in RDI
PUSH RDI ;Preserve value of rdi
PUSH RAX ;Preserve value of RAX
PUSH RDI;The value we want to print
PUSH DWORD formatStrf
CALL printf ;Segfault
POP RAX;Pop the stack back (too lazy to manually change the RSP value)
POP RAX
POP RAX;Restore the RAX and RDI
POP RDI
RET
I'm passing the floating point value to the RDI
reg as follows:
MOVSD QWORD [RSP], XMM0 ;Copy to stack
MOV RDI, QWORD [RSP]
CALL printfcallfloat
EDIT: I'm running this on linux.
Upvotes: 2
Views: 740
Reputation: 7981
Edit: as pointed out in the comments, this is only for Windows architectures. See Chris' answer for the convention on Linux systems.
The page you linked to has examples for x86
, the 32-bit architecture. The x86_64
architecture differs in how arguments are passed to functions.
The first four integer arguments are passed in registers. Integer values are passed in left-to-right order in RCX, RDX, R8, and R9, respectively. Arguments five and higher are passed on the stack.
Any floating-poing arguments would normally be passed in XMM0...3
instead, but for varargs this is different:
If parameters are passed via varargs (for example, ellipsis arguments), then the normal register parameter passing convention applies, including spilling the fifth and subsequent arguments to the stack. It's the callee's responsibility to dump arguments that have their address taken. For floating-point values only, both the integer register and the floating-point register must contain the value, in case the callee expects the value in the integer registers.
So, in other words, before your call to printf
, you should set RCX
to the format string, and set both RDX
and XMM1
to the number.
Upvotes: 1
Reputation: 126526
On x86_64, arguments are passed in registers, and not on the stack (the stack is used only if the size of the arguments to too large to fit in the registers). All the gory details1 are laid out in the SYSV ABI for x86_64
The basics of that is that the first 6 integer/pointer arguments are passed in RDI/RSI/RDX/RCX/R8/R9, while the first 8 float/double arguments are passed in XMM0..XMM7. In addition, you need to specify the number of XMM registers used for arguments in AL2. So in your case, you want the format in RDI, the double value in XMM0 and 1 in AL
The wikipedia page also has lots of good (concise) info about this.
1For non-Microsoft systems -- MS being MS they do things in their own incompatible way
2You only actually need to set this for varargs functions that use at least one XMM register. For non-varargs functions it will be ignored, and if it is set too large for a varargs function, the result will be a few wasted cycles (saving uneeded XMM regs), but wont actually break anything.
Upvotes: 4