You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

C调用64位汇编sign函数时int参数符号丢失问题

问题背景

尝试在64位汇编环境下实现符号函数sign供C代码调用,函数返回值为int类型,判定规则如下:

  • 参数为负数时返回-1
  • 参数为0时返回0
  • 参数为正数时返回1

故障现象

程序可正常识别正数与0,但传入负数时会被误判为正数,最终返回结果1。

附现有代码

C侧代码 main.c

#include <stdio.h>

extern int sign(signed int);

int main()
{
    signed int num;
    scanf("%d",&num);
    printf("num: %d sign: %d\n",num,sign(num));
    return 0;
}

汇编侧代码 sign.asm

global sign

section .text
sign:
    test rdi,rdi
    js neg_lab
    je zero_lab

    mov rax,1
    jmp end_lab

neg_lab:
    mov rax,-1
    jmp end_lab
    
zero_lab:
    xor rax,rax

end_lab:
    ret

前期排查时手动给待检测寄存器分别赋值正数、负数、零测试,汇编逻辑可正确识别三类数值,负数判定正常,因此初步判断问题出在参数传递环节。

故障根因

手动测试的结果不具备参考性,因为手动给寄存器赋值时没有复现C调用的真实传参状态。
在遵循System V AMD64调用约定的64位环境下,C语言传入32位int类型参数时,仅会写入对应传参寄存器的低32位,不会自动将符号位扩展到64位。传入负数时,低32位为对应负数的补码表示,高32位全为0,此时整个64位rdi寄存器存储的是正数值,原有代码中test rdi, rdi检测的是64位整数值的符号位(最高位),无法触发js负跳转,最终会走到返回1的正数分支。
以传入int类型的-1为例,传参完成后rdi的实际值为0x00000000FFFFFFFF,64位视角下最高位为0,符号标志位SF不会置位,负跳转自然不生效。

修复方案

两种方案任选其一即可:

  1. 调整检测位宽匹配参数类型,仅判断低32位寄存器,同时返回值也只操作低32位(x86-64下写入32位寄存器会自动将对应64位寄存器高32位清零,符合返回值规范):
global sign

section .text
sign:
    test edi,edi  ; 检测低32位,对应传入的32位int参数
    js neg_lab
    je zero_lab

    mov eax,1
    jmp end_lab

neg_lab:
    mov eax,-1
    jmp end_lab
    
zero_lab:
    xor eax,eax

end_lab:
    ret
  1. 函数入口处先对传入的32位参数做符号扩展,扩展为64位值后再走原有判断逻辑,只需要在sign标签后第一行添加指令movsxd rdi, edi即可,其余代码无需改动。

内容的提问来源于stack exchange,提问作者Gábor

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.29 01:24:22