免费注册 查看新帖 |

Chinaunix

  平台 论坛 博客 文库
12
最近访问板块 发新帖
楼主: 公用帐号
打印 上一主题 下一主题

x86-64的calling convention,和ia32有什么大区别? (汇编程序问题) [复制链接]

论坛徽章:
0
11 [报告]
发表于 2008-06-02 13:22 |只看该作者
版主,本人用一个简单的程序试过,在64位的机子上用as、ld生成的程序运行没有问题,但换成了gcc来生成程序运行就会出现“instruction fault“的提示。下面是程序代码(请留意一下注释的部分):
.section .data
msg:
       .asciz  "Hello, ubuntu! \n"
.section .text
.globl main
main:
                movq $msg, %rdi
                pushq %rdi
                call printf          #如果把这句话注释起来,在64位机子上用gcc生成的程序运行
                           #起来一切正常,但是加上这句话后在64位机子上用gcc生成的
                           #程序运行起来就会出错,问题出在call printf这个语句上
                movq $0, %rdi
                pushq %rdi
                call exit

[ 本帖最后由 bradpitt88 于 2008-6-2 13:40 编辑 ]

论坛徽章:
0
12 [报告]
发表于 2008-06-02 14:39 |只看该作者

回复 #11 bradpitt88 的帖子

不好意思,这个问题我也不懂,尝试在call printf之前加一句:

xorb %al, %al

或者,

movl $0, %eax

就没有段错误了。 根据ABI文档,我猜测可能是SSE寄存器(xmm)导致的。 调用函数时, %al里存放着使用的SSE寄存器的个数, 不知道为什么gcc编译的程序,在此时rax寄存器没有清零,导致出错。

论坛徽章:
0
13 [报告]
发表于 2008-06-03 09:13 |只看该作者
向“albcamus  (百無一用書生) ”表示感谢,我试着在“call printf” 之前加上"movl $0, %eax" 以后,果然没有出现“段错误”了。以后在这方面的问题还请多多指点。再次表示感谢!

论坛徽章:
0
14 [报告]
发表于 2008-06-03 09:32 |只看该作者
的确,在64位的机子上,gcc可能是存在某些bug的。我今天在单位的一台64位的ubuntu8.04上用gcc编译《Unix高级环境编程》里的一个程序,运行时就会莫名其妙的出现“段错误”的提示。 在家里的32位的ubuntu8.04上一点问题都没有。看来gcc在64位系统上还需改进。
程序如下:
#include <stdio.h>
#include <errno.h>
int main(int argc, char *argv[])
{
        printf("ENOENT: %s.\n", strerror(ENOENT));
        errno=EACCES;
        perror(argv[0]);
        return 0;
}

[ 本帖最后由 bradpitt88 于 2008-6-3 09:34 编辑 ]

论坛徽章:
0
15 [报告]
发表于 2008-06-03 09:51 |只看该作者
今天,我又试着在64位的机子上把上述代码作了修改, 并用g++来编译,运行起来居然没有问题,看来问题出在printf上。我曾经试着在printf语句之前把eax清零,然后用gcc编译,不过还是不行。
代码如下:
#include <iostream>
#include <errno.h>
using namespace std;
int main(int argc, char *argv[])
{       
        cout<<"Error: "<<strerror(ENOENT)<<endl;
        //printf("ENOENT: %s.\n", strerror(ENOENT));
        errno=EACCES;
        perror(argv[0]);
        return 0;
}

论坛徽章:
0
16 [报告]
发表于 2008-06-03 10:23 |只看该作者

回复 #14 bradpitt88 的帖子

加上#include <string.h>就好了。

PS,x86-64我不行,这里的mik版主才是高手,欢迎多讨论

论坛徽章:
0
17 [报告]
发表于 2008-06-03 11:24 |只看该作者
你们都是高手,多谢指点!
在下的qq号是30879973,不知mik版主和“书生”兄能否留下你们的qq号以便日后学习交流之用?

[ 本帖最后由 bradpitt88 于 2008-6-3 11:33 编辑 ]

论坛徽章:
0
18 [报告]
发表于 2008-06-05 00:38 |只看该作者
原帖由 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 中的用意是什么?

论坛徽章:
0
19 [报告]
发表于 2008-06-05 00:47 |只看该作者
原帖由 bradpitt88 于 2008-6-3 09:51 发表
今天,我又试着在64位的机子上把上述代码作了修改, 并用g++来编译,运行起来居然没有问题,看来问题出在printf上。我曾经试着在printf语句之前把eax清零,然后用gcc编译,不过还是不行。
代码如下:
#includ ...


C 与 C++ 下行为不一致,或者平台不一致所引起的吧。

在我上面的分析中,eax 的不确定性,也有可能不会出现故障,只要 eax 在 0 ~ 7 的值范围内的话


PS: 这种 BUG 真难找,谁会想到这一点

论坛徽章:
0
20 [报告]
发表于 2008-06-12 16:45 |只看该作者
如果要使用printf函数的话,64位的机子上需要加上#include <string.h>这句话,而32位的机子上则不用加入上述的头文件。我试过了。

[ 本帖最后由 bradpitt88 于 2008-6-12 16:46 编辑 ]
您需要登录后才可以回帖 登录 | 注册

本版积分规则 发表回复

  

北京盛拓优讯信息技术有限公司. 版权所有 京ICP备16024965号-6 北京市公安局海淀分局网监中心备案编号:11010802020122 niuxiaotong@pcpop.com 17352615567
未成年举报专区
中国互联网协会会员  联系我们:huangweiwei@itpub.net
感谢所有关心和支持过ChinaUnix的朋友们 转载本站内容请注明原作者名及出处

清除 Cookies - ChinaUnix - Archiver - WAP - TOP