我正在读一本关于如何使用NASM在汇编中编程的书,但在构建一个打印3.1400000的程序时遇到了问题。
代码可能有一些问题,比如在中使用错误的语句section .data pi: .float 3.14
应该是双quad类型,但我不知道是哪种伪操作地图;我试过了。但是dq不是那样的。
此外,我读到调用堆栈需要在程序启动前对齐,我希望使用基指针可以解决这个问题,否则程序将打印段错误。
另一个需要注意的是,我使用GAS和Intel语法,因此我不确定下面的语法映射是否正确。
代码:
#fmtflt.s
.intel_syntax noprefix
.extern printf
.section .data
pi: .float 3.14
.section .rodata
fmtflt: .ascii "%1f12 "
.section .text
.globl main
main:
push rbp
mov rbp, rsp
mov rax, 0 # set total numers xmm register
movq xmm0, [pi] # set content pi to
mov rdi, offset fmtflt # set address format string
call printf # call printf function
mov rsp, rbp
pop rbp
ret
编译:gcc-无饼图-o fmtflt fmtflt.s
输出:
实际:0.00000
预期:3.140000
有人能填补缺失的部分,让程序打印出预期的输出吗?
在节中使用了错误的语句。data pi:.foat 3.14的类型应该是双quad,但我不知道哪个伪操作映射到它;
使用.double
汇编一个8字节的双精度浮点值。看见https://sourceware.org/binutils/docs/as/i386_002dFloat.html#i386_002dFloat.
然后,正如Joseph所指出的,看看这条线:
mov rax, 0 # set total numers xmm register
正如注释所说,rax
应该设置为用于传递参数的xmm(SSE(寄存器的总数。请参阅x86-64 SysV ABI的图3.4,它是在使用它的Linux等系统上调用约定的权威参考。您将在xmm寄存器中传递1个参数(在下一行(,因此将rax
设置为1
,而不是0
。指令mov eax, 1
具有相同的效果(因为移动到32位寄存器中会使64位寄存器的上半部分为零(,并且少一个字节。
有了这些更改,程序为我正确地打印了3.140000
我也读到调用堆栈需要在程序启动前对齐,我希望使用基指针可以解决这个问题,否则程序将打印段错误。
是的,你把那部分说对了。