Warning: file_get_contents(/data/phpspider/zhask/data//catemap/0/assembly/6.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
C ASM x64函数指针未返回正确值_C_Assembly_X86 64_Nasm_Function Pointers - Fatal编程技术网

C ASM x64函数指针未返回正确值

C ASM x64函数指针未返回正确值,c,assembly,x86-64,nasm,function-pointers,C,Assembly,X86 64,Nasm,Function Pointers,我对汇编中的函数指针有问题,即使我的函数返回负数,它也总是将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

我对汇编中的函数指针有问题,即使我的函数返回负数,它也总是将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
汇编:

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后有代码要打印,但也有代码要在未使用bar2后打印。您应该在bar:之前添加ret,以防止执行此操作。
你的代码似乎太复杂了

首先,让我们用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后有代码要打印,但也有代码要在未使用bar2后打印。您应该在bar:之前添加ret,以防止执行此操作。 int是32位,但rax是64位寄存器。返回int的函数将其返回值放在eax中,这通常会将rax的高半部分归零。因此,如果cmp返回-1,即32位数字0xFFFFFF,则rax将包含0x00000000FFFFFF。这不是一个负的64位数字,因此测试rax时,rax不会设置符号标志

尝试使用test eax,eax作为您的测试。

int是32位的,但rax是64位的寄存器。返回int的函数将其返回值放在eax中,这通常会将rax的高半部分归零。因此,如果cmp返回-1,即32位数字0xFFFFFF,则rax将包含0x00000000FFFFFF。这不是一个负的64位数字,因此测试rax时,rax不会设置符号标志


尝试使用test eax,eax作为您的测试。

Edited,我在帖子中手工编写了代码,因为我在一个虚拟机上,我忘记了那一行,但并不是我想比较两次,这就是为什么jmp foo2不是因为我忘了cmp,它对cmp rax做了同样的事情,0@Fayeure您的cmp将打印x-x,所以你应该做一次比较,而不做那次比较,在只打印一次x-x的情况下进行两次比较。我打印x-x只是为了显示它调用了函数,但没有返回正确的值,没有这一点,输出就更好了,我也有同样的问题,我在帖子中手工编写了代码,因为我在一台虚拟机上,我忘记了那一行,但不是我想比较两次,这就是为什么jmp Foo2不是因为我忘记了cmp,它对cmp rax做了同样的事情,0@Fayeure您的cmp将打印x-x,所以你应该做一次比较,而不是两次比较,同时只打印一次x-x。我打印x-x只是为了显示它调用了函数,但没有返回好的值,否则输出就更好了,我也有同样的问题。你的跳转指令应该是标签foo中的JG吗?JA没有检查符号标志。@JA可能是外星人,但JA不是跳到上面的吗?@JA和jg也做了同样的事情。你的代码有多个ABI冲突。它正在重击属于调用者的rbx,而不恢复它,并使用rsp not aligned mod 16进行函数调用。我不确定这些是否是您所看到的内容的来源,但是如果没有它们的修复,它就不可能可靠地工作。@Fayeure:Read,x86-64部分,用于调用约定。这些都是必须了解和遵循的。rbx是被叫方保存的寄存器,您必须保留它;也就是说,您必须确保当函数返回时,rbx包含与输入函数时相同的值。您可以在函数开始时将其推到堆栈上,然后在结束时将其弹出,以代替堆栈调整。但更简单的方法是使用调用方保存的暂存寄存器;rax、rcx、rdx、r8、r9、r10、r11中的任何一个都可以。您的跳转指令不应该是标签foo中的JG吗?JA没有检查符号标志。@JA可能是外星人,但JA不是跳到上面的吗?@JA和jg也做了同样的事情。你的代码有多个ABI冲突。它正在重击属于调用者的rbx,而不恢复它,并使用rsp not aligned mod 16进行函数调用。我不确定这些是否是您所看到的内容的来源,但是如果没有它们的修复,它就不可能可靠地工作。@Fayeure:Read,x86-64部分,用于调用约定。这些都是必须了解和遵循的。rbx是被叫方保存的区域
你必须保存它;也就是说,您必须确保当函数返回时,rbx包含与输入函数时相同的值。您可以在函数开始时将其推到堆栈上,然后在结束时将其弹出,以代替堆栈调整。但更简单的方法是使用调用方保存的暂存寄存器;rax,rcx,rdx,r8,r9,r10,r11中的任何一个都可以。谢谢你是垃圾堆溢出之神,伙计,是这样的:谢谢你是垃圾堆溢出之神,伙计,是这样的:D