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

如何在64位NASM中调用libc函数(如strcat、printf)

调用libc函数的x86_64寄存器传参规则(System V AMD64 ABI)

你在开发编程语言时调用libc函数,核心要遵循Linux/x86_64平台的System V AMD64调用约定,这是所有C库(包括libc)遵守的标准,下面直接给你讲规则,结合你的代码修正,再扩展到strcat这类函数:

一、核心参数传递规则

  • 整数/指针类型参数:前6个参数依次存在 rdi、rsi、rdx、rcx、r8、r9 寄存器里,超过6个的参数从右往左压栈。
  • 浮点类型参数:前8个浮点参数用 xmm0 到 xmm7 寄存器传递。
  • 返回值:整数/指针返回值存在 rax,浮点返回值存在 xmm0。
  • 寄存器保存:rbx、rbp、r12~r15 是被调用者保存的寄存器(调用libc函数后这些值不会被修改),其他寄存器(比如rdi、rsi)是调用者保存的,调用前要自行保存需要保留的值。

二、你的printf代码问题修正与解释

你现有的printInt、printFloat函数没有正确传递要打印的参数,导致运行时会输出随机值,下面是修正后的版本,同时补充调用示例:

SECTION .data
     integer_printf:     db  '%d', 10, 0
     float_printf:       db  '%f', 10, 0
     string_format:      db  '%s', 10, 0
     var:                db  "test", 0
     pi:                 dq  3.1415  ; 双精度浮点数,对应%f格式

SECTION .text
     extern printf
     global main

; 调用前需把要打印的整数放入rsi
printInt:
     mov rdi, integer_printf  ; 第1个参数:格式串地址
     ; 第2个参数已由调用者存入rsi
     xor rax, rax             ; 无浮点参数,rax置0
     call printf
     ret

; 调用前需把要打印的双精度浮点数放入xmm0
printFloat:
     mov rdi, float_printf    ; 第1个参数:格式串地址
     mov rax, 1               ; 传递了1个浮点参数,rax设为对应数量
     call printf
     ret

; 调用前需把要打印的字符串指针放入rsi
printStr:
     mov rdi, string_format   ; 第1个参数:格式串地址
     ; 第2个参数已由调用者存入rsi
     xor rax, rax
     call printf
     ret

exit_program:
     mov rax, 60              ; exit系统调用号
     mov rdi, 0               ; 退出码0
     syscall
     ret

main:
     ; 测试打印字符串
     mov rsi, var
     call printStr

     ; 测试打印整数123
     mov rsi, 123
     call printInt

     ; 测试打印浮点数3.1415
     movsd xmm0, [rel pi]     ; 从内存加载双精度浮点数到xmm0
     call printFloat

     call exit_program

编译命令保持你原来的即可:

nasm -f elf64 -o test.o main.asm && gcc -o test test.o -lc -no-pie

三、调用strcat的示例

strcat的原型是char *strcat(char *dest, const char *src);,按照调用约定:

  • 第1个参数dest(目标字符串地址)放入rdi
  • 第2个参数src(源字符串地址)放入rsi
  • 返回值是dest的指针,存在rax中

示例代码片段:

SECTION .data
     dest: db "Hello ", 0
     src:  db "World!", 0

SECTION .text
     extern strcat

; 在main中调用strcat
lea rdi, [rel dest]  ; 传入dest地址到rdi
lea rsi, [rel src]   ; 传入src地址到rsi
call strcat          ; rax现在指向拼接后的dest

; 打印拼接结果
mov rsi, rax
call printStr

四、关键注意点

  • 调用printf时,如果用到浮点格式符(%f、%lf等),必须把rax设置为传递的浮点参数数量(即用到的xmm寄存器个数),否则会导致栈布局混乱,出现错误输出或崩溃。
  • 所有字符串参数必须以\0结尾,符合C语言的字符串标准,否则libc函数会读取内存直到遇到0,引发未定义行为。
  • x86_64 ABI要求调用函数前栈必须是16字节对齐的,gcc链接main函数时会自动处理栈对齐,但如果你自己写的函数调用前栈不对齐,需要手动调整(比如sub rsp, 8)。

内容的提问来源于stack exchange,提问作者Hrodebert

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.20 12:35:02