免费注册 查看新帖 |

Chinaunix

  平台 论坛 博客 文库
最近访问板块 发新帖
查看: 4261 | 回复: 9

[C] 为什么修改eax值会导致printf函数失败? [复制链接]

论坛徽章:
0
发表于 2014-01-13 15:31 |显示全部楼层

  1. .data
  2. foo:
  3.         .int -40
  4. out:
  5.         .asciz "%d\n"
  6. .text
  7. .globl main
  8. main:
  9.         xor %rax,%rax
  10.         xor %rcx,%rcx
  11.         movq $-20, %rax
  12.         addq $-40, %rax
  13.         #movq $-40, %rcx
  14.         movq %rax, %rsi
  15.         movq $out, %rdi
  16.         call printf
  17.         movq $1, %rax
  18.         movq $0, %rbx
  19.         int $0x80
复制代码
上面的代码一运行就会导致段错误,printf不能打印出信息

将rax的操作改成对rcx的操作以后就没问题了,下面的代码是可以正常工作 的,这是为什么呢?运行环境是x64 opensuse13.1

Thread model: posix
gcc version 4.8.1 20130909 [gcc-4_8-branch revision 202388] (SUSE Linux)

  1. .data
  2. foo:
  3.         .int -40
  4. out:
  5.         .asciz "%d\n"
  6. .text
  7. .globl main
  8. main:
  9.         xor %rax,%rax
  10.         xor %rcx,%rcx
  11.         movq $-20, %rcx
  12.         addq $-40, %rcx
  13.         #movq $-40, %rcx
  14.         movq %rcx, %rsi
  15.         movq $out, %rdi
  16.         call printf
  17.         movq $1, %rax
  18.         movq $0, %rbx
  19.         int $0x80
复制代码

论坛徽章:
0
发表于 2014-01-13 15:50 |显示全部楼层
本帖最后由 李营长 于 2014-01-14 13:34 编辑

解决了。原因是printf函数是变参函数,eax值是被printf函数使用的,是被传入的。而且printf函数还可能修改ecx的值。在这个例子里只需要把eax清零就好了
  1. .data   
  2. foo:
  3.         .int -40
  4. out:
  5.         .asciz "%d\n"
  6. .text
  7. .globl main
  8. main:
  9.         push %rbp
  10.         movq %rsp, %rbp
  11.         xor %rax,%rax
  12.         xor %rcx,%rcx
  13.         movq $-20, %rax
  14.         addq foo, %rax
  15.         movq %rax, %rsi
  16.         movq $out, %rdi
  17.         call printf
  18.         movq $1, %rax
  19.         movq $0, %rbx
  20.         leave
  21.         ret
复制代码

论坛徽章:
3
15-16赛季CBA联赛之山东
日期:2016-10-30 08:47:3015-16赛季CBA联赛之佛山
日期:2016-12-17 00:06:31CU十四周年纪念徽章
日期:2017-12-03 01:04:02
发表于 2014-01-13 19:46 |显示全部楼层
嗯, 请问LZ, 64位的话还是通过 int $0x80 软中断陷入内核么? 不是改成 sysenter 了么.
另外 64 位的调用惯例也和 32 位的完全不一样, 虽然确实没有看到 LZ  push 参数而是用 %rsi 和 %rdi, 不过好久没 care, 不知道 LZ 是否有违背调用约定~

论坛徽章:
3
15-16赛季CBA联赛之山东
日期:2016-10-30 08:47:3015-16赛季CBA联赛之佛山
日期:2016-12-17 00:06:31CU十四周年纪念徽章
日期:2017-12-03 01:04:02
发表于 2014-01-13 19:56 |显示全部楼层
想烦请LZ简略叙述一下 64 位的调用约定, 传参惯例, 主调方需要保存的寄存器以及被调方不能破坏的寄存器~ TKS

论坛徽章:
0
发表于 2014-01-14 10:35 |显示全部楼层
captivated 发表于 2014-01-13 19:46
嗯, 请问LZ, 64位的话还是通过 int $0x80 软中断陷入内核么? 不是改成 sysenter 了么.
另外 64 位的调用惯 ...


64位仍然可以使用int 0x80来做32位的call,只是比较怪罢了。我不知道在其它系统上是怎么样,但是在linux x64上,陷入内核是使用syscall指令的时候才正常,如果使用sysenter就会段错误。不知道sysenter是什么情况。我写了一段非常简短的代码演示了一下如何在汇编中直接调用syscall。应用层的call约定和内核层是不同的,具体请参考abi文档。

  1. .data
  2. output:
  3.         .asciz "silly, stupid, tiny asm\n"
  4. outputlen:
  5.         .int 24
  6. .text
  7.         .globl main
  8.         .type main, @function

  9. main:
  10.         push %rbp
  11.         mov %rsp, %rbp
  12.         mov $1, %rax
  13.         mov $0, %rdi
  14.         mov $output, %rsi
  15.         mov outputlen, %rdx
  16.         syscall
  17.         mov $60, %rax
  18.         mov $0, %rdi
  19.         syscall
  20.         ret
复制代码

论坛徽章:
1
2015年迎新春徽章
日期:2015-03-04 09:49:45
发表于 2014-01-14 11:30 |显示全部楼层
如果我没记错的话,在x64环境下,调用可变参数表的函数时,ax里保存的是参数个数。

论坛徽章:
1
2015年迎新春徽章
日期:2015-03-04 09:49:45
发表于 2014-01-14 11:38 |显示全部楼层
本帖最后由 koolcoy 于 2014-01-14 11:44 编辑

参见 http://www.x86-64.org/documentation_folder/abi.pdf 的21页

For calls that may call functions that use varargs or stdargs (prototype-less
calls or calls to functions containing ellipsis (. . . ) in the declaration) %al is used
as hidden argument to specify the number of vector registers used. The contents
of %al do not need to match exactly the number of registers, but must be an upper
bound on the number of vector registers used and is in the range 0–8 inclusive.

%rax  temporary register; with variable arguments
passes information about the number of vector
registers used; 1 st return register

论坛徽章:
2
2015年辞旧岁徽章
日期:2015-03-03 16:54:152015年迎新春徽章
日期:2015-03-04 09:53:17
发表于 2014-01-14 13:05 |显示全部楼层
> but must be an upper bound on the number of vector registers used and is in the range 0–8 inclusive.

这是新版吧,我手里的:

> but must be an upper bound on the number of SSE registers used and is in the range 0–8 inclusive.

所以我还是不知道, 这个%al怎么用。

论坛徽章:
0
发表于 2014-01-14 13:31 |显示全部楼层
本帖最后由 李营长 于 2014-01-14 13:32 编辑

回复 6# koolcoy


    你说的是对的,是我eax没有清零造成的。不过eax里指定的不是变参数目,而是vector寄存器的使用数目,最常见的例子就是传入浮点数的数目。

论坛徽章:
0
发表于 2014-01-18 20:56 |显示全部楼层
营长,你到底在研究神马呀,感觉乱乱的。
您需要登录后才可以回帖 登录 | 注册

本版积分规则 发表回复

  

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

清除 Cookies - ChinaUnix - Archiver - WAP - TOP