assembly - NASM x86_64 printf 第 7 个参数
问题描述
我有一个dprintf
用 NASM 编写的简单程序,它打印一个包含 6 个以上参数的长格式。我根据调用约定(RDI、RSI、RDX、RCX、R8、R9)传递参数。只要我只使用那些我的程序就可以正常工作。
我无法弄清楚为什么每次尝试将某些内容作为附加参数推送到堆栈时都会出现段错误。这是来源:
;a comment
%macro DATA 0
section .data
string: db "%6$ca comment%1$c%4$cmacro DATA 0%1$csection .data%1$c%2$cstring: db %3$c%5$s%3$c, 0%1$c%2$cpath: db %3$cGrace_kid.s%3$c, 0%1$c%4$cendmacro%1$c%4$cdefine SC_OPEN 0x2000005%1$c%4$cmacro MAIN 0%1$c%1$cDATA%1$c%1$csection .text%1$c%2$cglobal start%1$c%2$cglobal _main%1$c%2$cextern _dprintf%1$c%1$cstart:%1$c%2$ccall _main%1$c%2$cret%1$c%1$c_main:%1$c%2$cpush rbp%1$c%2$cmov rbp, rsp%1$c%2$cmov rax, SC_OPEN%1$c%2$clea rdi, [rel path]%1$c%2$cmov rsi, 0x0200%1$c%2$cxor rsi, 0x0002%1$c%2$cmov rdx, 0640o%1$c%2$cclc%1$c%2$csyscall%1$c%2$cjc ret%1$c%2$ccmp rax, 0%1$c%2$cjle ret%1$c%2$cmov rdi,rax%1$c%2$clea rsi, [rel string]%1$c%2$cmov rdx, 10%1$c%2$cmov rcx, 9%1$c%2$ccall _dprintf%1$c%2$cxor rax, rax%1$cret:%1$c%2$cleave%1$c%2$cret%1$c%4$cendmacro%1$c%1$cMAIN%1$c", 0
path: db "Grace_kid.s", 0
%endmacro
%define SC_OPEN 0x2000005
%macro MAIN 0
DATA
section .text
global start
global _main
extern _dprintf
start:
call _main
ret
_main:
push rbp
mov rbp, rsp
;sub rsp, 16
mov rax, SC_OPEN
lea rdi, [rel path]
mov rsi, 0x0200
xor rsi, 0x0002
mov rdx, 0640o
clc
syscall
jc ret
cmp rax, 0
jle ret
mov rdi, rax
lea rsi, [rel string]
mov rdx, 10
mov rcx, 9
mov r8, 34
mov r9, 37
mov rbx, 59
push rbx
xor rax, rax
call _dprintf
xor rax, rax
ret:
leave
ret
%endmacro
MAIN
我组装和链接这些命令:
nasm -fmacho64 file.s
ld file.o -macosx_version_min 10.14 -lSystem
这工作得很好,但我想添加额外的参数。我尝试使用以下方法将其推入堆栈:
mov rbx, 59
push rbx
我是否将一些字节分给RSP会产生段错误。
我在 MacOS Mojave 下,我正在使用最新版本的 NASM。
解决方案
由于这个问题最终具有一定的价值,它可能可以使用答案。有两个重大问题:
您
_dprintf
使用 7 个参数调用,这些参数具有C等效项:dprintf (fd, format_str, 10, 9, 34, 47, 59)
问题是在你的格式字符串中你有
%5$s
. 第 5 个可变参数是值 59,而不是指向字符串的指针。dprintf
正在尝试访问它没有权限的内存,并且您收到错误 EXC_BAD_ACCESS 和段错误。您也有%6$c
格式字符串,但没有第 6 个可变参数。从您的评论中可以清楚地看出,您希望它format_str
本身是第 5 个参数,而值 59 是第 6 个参数。推送最后 2 个参数的代码应该如下所示:push 59 lea rbx, [rel string] push rbx xor rax, rax call _dprintf
相应的C调用将是:
dprintf (fd, format_str, 10, 9, 34, 47, format_str, 59)
注意:当压入堆栈中不适合寄存器的参数时,它们必须以相反的顺序压入
x86-64 System V ABI 调用约定在调用符合要求的函数(包括System和C库)之前,要求堆栈至少对齐 16 字节。在 MacOS 上,系统库对堆栈对齐问题非常敏感,因为它出于性能原因尽可能使用对齐的 SIMD 指令,即使仅使用整数类参数也是如此。
_main
也符合这个标准。ABI 需要在呼叫前的点进行 16 次再见对齐。如果您传递需要 256 位 SIMD 向量的参数,则需要 32 字节对齐 - 但这里不是这种情况。进入_main
(或任何符合 x86-64 调用约定规则的函数)后,堆栈未对齐 8,因为返回地址现在在堆栈上。push RBP
从 RSP 中减去 8,堆栈现在再次在 16 字节边界上对齐。如果您在堆栈上压入偶数个参数以满足诸如dprintf
对齐之类的调用,则仍然完好无损。如果您传递一个奇数,您将再次错位。在这些情况下,您必须在推送参数之前从 RSP 中减去 8。如果你真的打算这样做:
dprintf (fd, format_str, 10, 9, 34, 47, 59)
在将额外的 1 参数压入堆栈之前,您必须从 RSP 中减去 8。代码看起来像:
push rax ; Push any register on stack or use `add rsp, -8` to align parameters push 59 xor rax, rax call _dprintf
如果您将 2 个额外参数传递给
dprintf
不需要这样的堆栈调整,因为被推送的偶数个参数不会破坏 16 字节对齐
推荐阅读
- python - 将复杂的 json 对象插入 sql 模式
- c# - 以安全的方式使用 SecureString
- vb.net - 如何强制 Integer 类型用作引用类型而不进行包装?
- javascript - 渲染路线,从产品id,同时传入道具
- python - 如何使用 SIM808 将带有 python 脚本的 post 请求从服务器发送到数据库?
- python - 如何将不同大小的numpy数组列表保存到磁盘?
- c++ - 从文件中读取 c++ 总是无法读取
- c++ - c++ 在模板中使用元组作为参数包
- r - 用 R 计算一个顶点(节点)的局部聚类系数(手动)
- time - 对于任何问题,GitLab 时间跟踪都不会显示在问题侧边栏上