- 此问题在此处已有答案**:
glibc scanf Segmentation faults when called from a function that doesn't align RSP(1个答案)
昨天关门了。
我试图通过调用sprintf
将汇编(NASM)中的整数字符串化。
我有下面的汇编代码可以做到这一点:
sprintf_Int_str db "%lld",
dq 0
...
Int.str:
push rbp
mov rbp, rsp ; creates stack frame
; allocate string
mov rdi, 64 ; much larger than needed
call malloc
push rax ; save char*
; write string to allocated memory using `sprintf(buf, "%lld", n)`
mov rdi, rax
mov rsi, sprintf_Int_str
mov rdx, qword [rbp + 16] ; the location of the number on the stack
; (trust me - it's pushed before Int.str is called,
; meaning it's 2 (64-bit) places before the start
; of the stack frame)
mov rcx, rsi
mov r8, 0
mov r9, 0 ; clearing other registers for sake of it
mov rax, 0 ; (doesn't make a difference if I do this or not)
call sprintf
pop rax ; pop return value which is saved after call to malloc
mov rsp, rbp
pop rbp
ret
这段代码在我的机器(Ubuntu 22.10)上运行良好,但我注意到我的自动测试在GitHub Actions(Ubuntu VM)上失败了。我在Docker中设置了一些测试在我的机器上运行,它们在Alpine、Debian和Arch容器中运行良好,但在Ubuntu中再次失败。我使用GDB分析了失败代码的核心转储,它给了我以下信息:
这不是很有帮助。我已经尝试了各种方法传递参数到sprintf
,因为我看到了冲突的信息在线,但GCC给出了以下输出从以下C++代码:
x一个一个一个一个x一个一个二个x
它运行良好,并且似乎与我的代码相同,就调用sprintf
时哪些寄存器包含哪些内容而言。
尤其令我不解的是,它很少失败:我唯一的想法是,我正在做一些未定义行为的事情,这些行为碰巧总是在我的机器上工作,因为我的机器有更大的RAM或更有弹性的 * 东西 *,但是,在更轻量级的VM上,这是不允许的(尽管添加--max-ram="1g"
没有帮助)。
我的集合命令是
nasm -f elf64 <file.asm> -o out.o
我的连接命令是
gcc -Wall -no-pie out.o -e main -o a.out
我的Ubuntu停靠文件是:
FROM ubuntu:latest
WORKDIR /app
COPY . .
SHELL ["/bin/bash", "-c"]
RUN apt-get update && apt-get install -y nasm curl build-essential bc
RUN curl --proto '=https' --tlsv1.2 -sSf https://sh.rustup.rs | sh -s -- -y
ENV PATH="/root/.cargo/bin:${PATH}"
CMD ["/bin/bash", "bin/test"]
它运行一个执行程序集的自定义bash脚本(./bin/test
)。
在我的机器上运行ldd --version
(运行良好),得到:ldd (Ubuntu GLIBC 2.36-0ubuntu4) 2.36
在本地Docker容器上运行它(它所在的地方),得到:ldd (Ubuntu GLIBC 2.35-0ubuntu3.1) 2.35
但是我不能想象一个小的版本更新会碰巧解决这个问题?无论如何,运行apt install libc-bin
表明软件包在这两个版本上都是最新的。
我的项目的repo在这里是https://github.com/revers3ntropy/oxynium
,尽管它有很多围绕该程序集的 Package 器。
如果你能帮我的话,非常感谢!
1条答案
按热度按时间gc0ot86w1#
我唯一的想法是我在做一些行为未定义的事情
是的。特别是,
x86_64
ABI * 要求 * 在16字节边界上保持堆栈对齐,而您 * 没有 * 这样做。在使用
-msse2
构建GLIBC的计算机上,调用堆栈未对齐的libc
例程 * 可能 * 崩溃。检查崩溃的指令(使用
x/i $pc
GDB命令)--可能是MOVDQA
或类似指令,源地址或目的地址未对齐。