ASM x64 函数指针未返回有效值
ASM x64 function pointer not returning the good value
我在汇编中遇到函数指针问题,即使我的函数 returns 是负数,它总是将 rax
设置为正数,我做了一个最小的可重现示例,其中包含一个函数比较两个整数,它做同样的事情:
ASM 函数代码[编辑]:
global foo
section .data
msg: db `superior\n`
msg_len: equ $-msg
section .text
foo:
push rbx
mov rbx, rdi
mov rdi, 2
mov rsi, 1
sub rsp, 8 ; align the stack frame
call rbx
add rsp, 8
test rax, rax ;[EDIT] correct: test eax, eax
js bar
mov rax, 1
mov rdi, 1
mov rsi, msg
mov rdx, msg_len
syscall
bar:
mov rdi, 1
mov rsi, 2
sub rsp, 8 ; same here
call rbx
add rsp, 8
test rax, rax ;[EDIT] correct: test eax, eax
js exit
mov rax, 1
mov rdi, 1
mov rsi, msg
mov rdx, msg_len
syscall
exit:
pop rbx ;restoring initial data of rbx
ret
main.c代码:
#include <stdio.h>
int foo(int (*f)()); //my asm function prototype
int cmp(int i, int j)
{
printf("%d - %d\n", i, j);
return(i - j);
}
int main(void)
{
foo(&cmp);
return (0);
}
输出为:
2 - 1
superior
1 - 2
superior
但应该只是:
2 - 1
superior
编译:
nasm -f elf64 foo.s
gcc -c main.c -o main.o
gcc main.o foo.o
感谢帮助
[编辑] 它不起作用,因为我检查了 rax 而不是 eax,现在它起作用了。感谢您的帮助
您的代码似乎太复杂了。
首先,让我们用像 C 这样的语言写下要做的事情:
int foo(int (*f)()) {
if (cmp(2, 1) > 0) {
PRINT;
}
if (cmp(1, 2) > 0) {
PRINT;
}
}
那我们就照着写汇编代码吧:
global foo
section .data
msg: db `superior\n`
msg_len: equ $-msg
section .text
; int foo(int (*f)()) {
foo:
mov rbx, rdi ; function pointer stored in rbx
; if (cmp(2, 1) > 0) {
mov rdi, 2 ; first integer
mov rsi, 1 ; second integer
call rbx ; call function pointer
cmp rax, 0
jle bar ; jump if rdi <= rsi (signed)
; PRINT;
mov rax, 1
mov rdi, 1
mov rsi, msg
mov rdx, msg_len
syscall ; write "superior\n"
; }
bar:
; if (cmp(1, 2) > 0) {
mov rdi, 1
mov rsi, 2
call rbx
cmp rax, 0
jle bar2
; PRINT;
mov rax, 1
mov rdi, 1
mov rsi, msg
mov rdx, msg_len
syscall ; write "superior\n"
; }
bar2:
; }
ret
要保留您的代码,需要修复的要点是:
ja
用于无符号比较。 jg
应该用于有符号比较。
bar2
后有代码打印,但是ja bar2
跳转后也有代码打印。您应该在 bar:
之前添加 ret
以防止执行此操作。
一个int
是32位的,但是rax
是一个64位的寄存器。 returns int
的函数会将其 return 值放入 eax
,这通常会将 rax
的高半部分置零。所以如果cmp
returns-1
,也就是32位的数0xffffffff
,那么rax
就会包含0x00000000ffffffff
。这不是负 64 位数字,因此 test rax, rax
不会设置符号标志。
尝试使用 test eax, eax
作为测试。
我在汇编中遇到函数指针问题,即使我的函数 returns 是负数,它总是将 rax
设置为正数,我做了一个最小的可重现示例,其中包含一个函数比较两个整数,它做同样的事情:
ASM 函数代码[编辑]:
global foo
section .data
msg: db `superior\n`
msg_len: equ $-msg
section .text
foo:
push rbx
mov rbx, rdi
mov rdi, 2
mov rsi, 1
sub rsp, 8 ; align the stack frame
call rbx
add rsp, 8
test rax, rax ;[EDIT] correct: test eax, eax
js bar
mov rax, 1
mov rdi, 1
mov rsi, msg
mov rdx, msg_len
syscall
bar:
mov rdi, 1
mov rsi, 2
sub rsp, 8 ; same here
call rbx
add rsp, 8
test rax, rax ;[EDIT] correct: test eax, eax
js exit
mov rax, 1
mov rdi, 1
mov rsi, msg
mov rdx, msg_len
syscall
exit:
pop rbx ;restoring initial data of rbx
ret
main.c代码:
#include <stdio.h>
int foo(int (*f)()); //my asm function prototype
int cmp(int i, int j)
{
printf("%d - %d\n", i, j);
return(i - j);
}
int main(void)
{
foo(&cmp);
return (0);
}
输出为:
2 - 1
superior
1 - 2
superior
但应该只是:
2 - 1
superior
编译:
nasm -f elf64 foo.s
gcc -c main.c -o main.o
gcc main.o foo.o
感谢帮助
[编辑] 它不起作用,因为我检查了 rax 而不是 eax,现在它起作用了。感谢您的帮助
您的代码似乎太复杂了。
首先,让我们用像 C 这样的语言写下要做的事情:
int foo(int (*f)()) {
if (cmp(2, 1) > 0) {
PRINT;
}
if (cmp(1, 2) > 0) {
PRINT;
}
}
那我们就照着写汇编代码吧:
global foo
section .data
msg: db `superior\n`
msg_len: equ $-msg
section .text
; int foo(int (*f)()) {
foo:
mov rbx, rdi ; function pointer stored in rbx
; if (cmp(2, 1) > 0) {
mov rdi, 2 ; first integer
mov rsi, 1 ; second integer
call rbx ; call function pointer
cmp rax, 0
jle bar ; jump if rdi <= rsi (signed)
; PRINT;
mov rax, 1
mov rdi, 1
mov rsi, msg
mov rdx, msg_len
syscall ; write "superior\n"
; }
bar:
; if (cmp(1, 2) > 0) {
mov rdi, 1
mov rsi, 2
call rbx
cmp rax, 0
jle bar2
; PRINT;
mov rax, 1
mov rdi, 1
mov rsi, msg
mov rdx, msg_len
syscall ; write "superior\n"
; }
bar2:
; }
ret
要保留您的代码,需要修复的要点是:
ja
用于无符号比较。jg
应该用于有符号比较。bar2
后有代码打印,但是ja bar2
跳转后也有代码打印。您应该在bar:
之前添加ret
以防止执行此操作。
一个int
是32位的,但是rax
是一个64位的寄存器。 returns int
的函数会将其 return 值放入 eax
,这通常会将 rax
的高半部分置零。所以如果cmp
returns-1
,也就是32位的数0xffffffff
,那么rax
就会包含0x00000000ffffffff
。这不是负 64 位数字,因此 test rax, rax
不会设置符号标志。
尝试使用 test eax, eax
作为测试。