正确调用 printf 的堆栈对齐?
Correct stack alignment for call to printf?
我见过调用printf
之前堆栈指针/esp
递减4
并在调用[=14=之后重新调整12
的例子]:
section .text
global main
extern printf
main:
sub esp, 4
push msg
push format_str
call printf
add esp, 12
ret
section .data:
msg db "print me!", 0
format_str db "%s", 0
而且我已经看到堆栈指针/esp
在调用 printf
之前递减 8
并在调用 [=14] 之后由 16
重新调整的示例=]:
section .text
global main
extern printf
main:
sub esp, 8
push msg
push format_str
call printf
add esp, 16
ret
section .data:
msg db "print me!", 0
format_str db "%s", 0
据我所知,在从 libc 调用任何函数之前,esp
应该递减 8
,然后 re-adjusted/incremented 递减 16
。
这些例子的差异让我很困惑,哪个堆栈对齐例子是正确的,为什么? incrementing/decrementing 的这个过程可以解释一下吗?
I have seen examples where the stack pointer/esp is decremented by 4 before calling printf and re-adjusted by 12 after calling printf:
根据 another question 中的评论,堆栈在可以使用 SSE 指令的系统(例如库、操作系统)上应以 16 字节对齐。
假设调用函数(main
)时堆栈指针正确对齐,call
指令从esp
中减去4个字节,所以sub
和push
指令必须从 esp
中减去 12、28、40 ... 字节以保持堆栈指针正确对齐。
sub esp, 8
显然,在这种情况下,编译器没有被告知要关心 16 字节堆栈对齐。
显然,在这种情况下,编译器分配的堆栈多于所需。
我刚刚告诉编译器为堆栈生成 8 字节和 16 字节对齐;所有其他编译器选项(当然还有源代码)都是相同的。
不同之处在于,在8字节对齐的情况下,编译器生成sub esp, 4
,在16字节对齐的情况下,sub esp, 20
。
很明显,这是编译器优化的问题:
如果sub esp,20
将堆栈对齐到16字节,sub esp, 4
也会对齐到16字节。
并且使用“对齐到 8 字节”选项表明绝对可以执行 sub esp, 4
而不是 sub esp, 20
。
这表明某些编译器为某些未知目的保留了比所需更多的堆栈。
我见过调用printf
之前堆栈指针/esp
递减4
并在调用[=14=之后重新调整12
的例子]:
section .text
global main
extern printf
main:
sub esp, 4
push msg
push format_str
call printf
add esp, 12
ret
section .data:
msg db "print me!", 0
format_str db "%s", 0
而且我已经看到堆栈指针/esp
在调用 printf
之前递减 8
并在调用 [=14] 之后由 16
重新调整的示例=]:
section .text
global main
extern printf
main:
sub esp, 8
push msg
push format_str
call printf
add esp, 16
ret
section .data:
msg db "print me!", 0
format_str db "%s", 0
据我所知,在从 libc 调用任何函数之前,esp
应该递减 8
,然后 re-adjusted/incremented 递减 16
。
这些例子的差异让我很困惑,哪个堆栈对齐例子是正确的,为什么? incrementing/decrementing 的这个过程可以解释一下吗?
I have seen examples where the stack pointer/esp is decremented by 4 before calling printf and re-adjusted by 12 after calling printf:
根据 another question 中的评论,堆栈在可以使用 SSE 指令的系统(例如库、操作系统)上应以 16 字节对齐。
假设调用函数(main
)时堆栈指针正确对齐,call
指令从esp
中减去4个字节,所以sub
和push
指令必须从 esp
中减去 12、28、40 ... 字节以保持堆栈指针正确对齐。
sub esp, 8
显然,在这种情况下,编译器没有被告知要关心 16 字节堆栈对齐。
显然,在这种情况下,编译器分配的堆栈多于所需。
我刚刚告诉编译器为堆栈生成 8 字节和 16 字节对齐;所有其他编译器选项(当然还有源代码)都是相同的。
不同之处在于,在8字节对齐的情况下,编译器生成sub esp, 4
,在16字节对齐的情况下,sub esp, 20
。
很明显,这是编译器优化的问题:
如果sub esp,20
将堆栈对齐到16字节,sub esp, 4
也会对齐到16字节。
并且使用“对齐到 8 字节”选项表明绝对可以执行 sub esp, 4
而不是 sub esp, 20
。
这表明某些编译器为某些未知目的保留了比所需更多的堆栈。