- 论坛徽章:
- 0
|
原帖由 albcamus 于 2008-6-2 14:39 发表
不好意思,这个问题我也不懂,尝试在call printf之前加一句:
xorb %al, %al
或者,
movl $0, %eax
就没有段错误了。 根据ABI文档,我猜测可能是SSE寄存器(xmm)导致的。 调用函数时, %al里存放着 ...
al 果然一针见血,我贴出 printf 的实现代码来分析一下,一起来参详参详。 在 /lib64/libc.so.6 里的
0000000000400ed0 <_IO_printf>:
400ed0: 48 81 ec d8 00 00 00 sub $0xd8,%rsp
400ed7: 48 89 54 24 30 mov %rdx,0x30(%rsp)
400edc: 0f b6 d0 movzbl %al,%edx
400edf: 48 89 74 24 28 mov %rsi,0x28(%rsp)
400ee4: 48 8d 04 95 00 00 00 lea 0x0(,%rdx,4),%rax
400eeb: 00
400eec: ba 30 0f 40 00 mov $0x400f30,%edx
400ef1: 48 89 4c 24 38 mov %rcx,0x38(%rsp)
400ef6: 4c 89 44 24 40 mov %r8,0x40(%rsp)
400efb: 4c 89 4c 24 48 mov %r9,0x48(%rsp)
400f00: 48 89 fe mov %rdi,%rsi
400f03: 48 29 c2 sub %rax,%rdx
400f06: 48 8d 84 24 cf 00 00 lea 0xcf(%rsp),%rax
400f0d: 00
400f0e: ff e2 jmpq *%rdx
400f10: 0f 29 78 f1 movaps %xmm7,-0xf(%rax)
400f14: 0f 29 70 e1 movaps %xmm6,-0x1f(%rax)
400f18: 0f 29 68 d1 movaps %xmm5,-0x2f(%rax)
400f1c: 0f 29 60 c1 movaps %xmm4,-0x3f(%rax)
400f20: 0f 29 58 b1 movaps %xmm3,-0x4f(%rax)
400f24: 0f 29 50 a1 movaps %xmm2,-0x5f(%rax)
400f28: 0f 29 48 91 movaps %xmm1,-0x6f(%rax)
400f2c: 0f 29 40 81 movaps %xmm0,-0x7f(%rax)
400f30: 48 8d 84 24 e0 00 00 lea 0xe0(%rsp),%rax
400f37: 00
400f38: 48 8b 3d 49 72 28 00 mov 0x287249(%rip),%rdi # 688188 <_IO_stdout>
400f3f: 48 89 e2 mov %rsp,%rdx
400f42: c7 04 24 08 00 00 00 movl $0x8,(%rsp)
400f49: c7 44 24 04 30 00 00 movl $0x30,0x4(%rsp)
400f50: 00
400f51: 48 89 44 24 08 mov %rax,0x8(%rsp)
400f56: 48 8d 44 24 20 lea 0x20(%rsp),%rax
400f5b: 48 89 44 24 10 mov %rax,0x10(%rsp)
400f60: e8 4b d3 00 00 callq 40e2b0 <_IO_vfprintf>
400f65: 48 81 c4 d8 00 00 00 add $0xd8,%rsp |
1、eax 确实是存放多少个需要解压的 xmm 寄存器的个数。 我没仔细看 ABI 文档,不知这里用意是什么,单从这里很难看出
2、
400edc: 0f b6 d0 movzbl %al,%edx
... ...
400ee4: 48 8d 04 95 00 00 00 lea 0x0(,%rdx,4),%rax
... ...
400eec: ba 30 0f 40 00 mov $0x400f30,%edx
... ...
400f03: 48 29 c2 sub %rax,%rdx
... ...
400f0e: ff e2 jmpq *%rdx
... ...
上面这几条指令, eax 作用是一个 index 定位以地址 0x400f30 为基地址进行索引,所需执行多少条 movaps 指令。
由于每条 movaps xmm, XX(%rax) 指令的长度为4,
所以,lea (, %rdx, 4), %rax 才可以准确以 4 为 scalar 定位。
最后,跳转到 rdx 指针里执行。
3、这里引发另一个问题:
若手工写汇编程序,不是很熟 ABI 的人,不太可能会想到在 call printf 前面加上 movl $0, eax 指令
导致程序出现 segmention fault 。
另一个极可能出现的错误是:illegal instruction (无效指令) 的错误,因为 eax 的不确定性,导致 rdx 计算结果出现越指令边界
4、这里执行解压xmm 寄存器到 stack 中的用意是什么? |
|