浮点异常程序集 64 位

Posted

技术标签:

【中文标题】浮点异常程序集 64 位【英文标题】:floating point exception assembly 64 bit 【发布时间】:2019-12-18 16:35:16 【问题描述】:

浮点异常核心转储。我正在使用 64 位汇编。我想我在使用 div 指令时遇到了错误,从我所看到的错误中,(人们似乎在不清除 RDX 时得到它)但是当我使用 xor 函数清除它时,我没有'不知道我的代码有什么问题。

section     .text
global      _start                              ;must be declared for linker (ld)

_start:
mov rdi,1                                  ;tell linker entry point
mov rax,rdi
push rax
jmp loop

loop:
pop rax
cmp rax,19
jle test3
mov rax,1;quit
syscall ;quit

test3:
add rdi,1
push rdi
mov rax,rdi 
xor rdx,rdx
mov rbx,3
div rbx
cmp rdx,0
je fizz
jmp test5

test5:
mov rax,rdi 
xor rdx,rdx
mov rbx,5
div rbx
cmp rdx,0
je buzz
jmp loop 


fizz:
    mov     rdx,5                               ;message length
    mov     rcx,msg                             ;message to write
    mov     rbx,1                               ;file descriptor (stdout)
    mov     rax,4                               ;system call number (sys_write)
    syscall                               ;call kernel
jmp loop

buzz:
    mov     rdx,5                               ;message length
    mov     rcx,msg2                            ;message to write
    mov     rbx,1                               ;file descriptor (stdout)
    mov     rax,4                               ;system call number (sys_write)
    syscall                               ;call kernel
jmp loop


section     .data

msg     db  'fizz',10               
msg2     db  'buzz',10   

【问题讨论】:

是的,#DE 是 x86 Linux 上获取 SIGFPE 算术异常信号的唯一方法,除非您取消屏蔽一些实际的 FP 异常。哪个div 指令错误?使用调试器找出答案。另外,你是如何组装+链接和运行这个的? 您确定在更改源代码后重新构建了可执行文件吗?我在我的 Linux 桌面上试过这个,它只是进入一个无限循环,没有打印任何东西。 (您的代码看起来过于复杂,所以我没有尝试自己调试无限循环,例如 je / jmp 很傻,只需使用 jne 或失败;还有像 dec ebx / jz fizz 这样的向下计数器会更有效)。 (我用nasm -felf64 fizzbuzz.asm 组装并直接用ld -o fizzbuzz fizzbuzz.o 链接到一个静态可执行文件)。所以这不是你要问的minimal reproducible example。 我正在使用 nasm。在ubuntu终端编译并运行 我现在也一样,无限循环,什么也不打印。为什么代码没有结束?它应该一旦 rdi 等于 20 使用调试器单步查找。 IDK 为什么你使用 push/pop;看起来很奇怪。哦,顺便说一句,您为系统调用参数使用了错误的寄存器;这就是为什么他们总是返回-EFAULT(使用strace)。您使用的是 32 位索书号和寄存器,而不是 64 位。 【参考方案1】:

您的程序生成错误的syscalls。

在 System V ABI 中,syscall 的参数位于以下寄存器中: rdirsirdxrcxr8r9

另外,1 代表 sys_write4 代表 sys_statsys_exit 代表 60)。

浮点异常仅在除数为0rdx 未被清除时发生。因为两者都不是,所以不应该发生。

section     .text
global      _start                              ;must be declared for linker (ld)

_start:
mov r8,1                                  ;tell linker entry point
mov rax,r8; rdi is needed for syscalls, have to use another register 
          ; or save it before preparing to call the kernel
push rax
jmp loop

loop:
pop rax
cmp rax,19
jle test3
mov rax, 60; sys_exit
xor rdi, rdi; clear rdi(exit code)
syscall

test3:
add r8,1
push r8
mov rax,r8 
xor rdx,rdx
mov rbx,3
div rbx
cmp rdx,0
je fizz
jmp test5

test5:
mov rax,r8 
xor rdx,rdx
mov rbx,5
div rbx
cmp rdx,0
je buzz
jmp loop 


fizz:
    mov     rdx,5                               ;message length
    mov     rsi,msg                             ;message to write
    mov     rdi,1                               ;file descriptor (stdout)
    mov     rax,1                               ;system call number (sys_write)
    syscall                               ;call kernel
jmp loop

buzz:
    mov     rdx,5                               ;message length
    mov     rsi,msg2                            ;message to write
    mov     rdi,1                               ;file descriptor (stdout)
    mov     rax,1                               ;system call number (sys_write)
    syscall                               ;call kernel
jmp loop


section     .data

msg     db  'fizz',10               
msg2     db  'buzz',10   

输出是:

fizz
buzz
fizz
fizz
buzz
fizz
fizz
fizz
buzz

您可以在此表中找到syscall 号码: https://blog.rchapman.org/posts/Linux_System_Call_Table_for_x86_64/

【讨论】:

普通的 fizzbuzz 也会打印出不是 3 或 5 的倍数的数字。请参阅How do I print an integer in Assembly Level Programming without printf from the c library?(或递增 ASCII 数字)。 OP 的代码甚至没有尝试这样做,所以是 +1 让 OP 的代码工作。 (尽管它仍然非常低效且笨拙。例如,有一个 jmp test5 是无操作的;无论如何执行都会落到那里。fizzbuzz 块中的大多数指令都是相同的。)

以上是关于浮点异常程序集 64 位的主要内容,如果未能解决你的问题,请参考以下文章

64 位 .NET Informix ADO.NET 提供程序的程序集加载错误

不同的 .NET 程序集引用取决于 32-64 位 [重复]

未能加载的文件或程序集.怎么解决

将 C 代码转换为 x86-64 位程序集?

将两个32位数相乘并将64位结果打印为十进制NASM程序集

尝试在 64 位 Windows-7 中从 c# 应用程序将 datagridview 导出到 OpenOffice Calc 时出现 cli 程序集错误