免费注册 查看新帖 |

Chinaunix

  平台 论坛 博客 文库
最近访问板块 发新帖
查看: 2547 | 回复: 6
打印 上一主题 下一主题

[其他] 服劲了 [复制链接]

论坛徽章:
11
未羊
日期:2013-12-16 12:45:4615-16赛季CBA联赛之青岛
日期:2016-04-11 19:17:4715-16赛季CBA联赛之广夏
日期:2016-04-06 16:34:012015亚冠之卡尔希纳萨夫
日期:2015-11-10 10:04:522015亚冠之大阪钢巴
日期:2015-07-30 18:29:402015亚冠之城南
日期:2015-06-15 17:56:392015亚冠之卡尔希纳萨夫
日期:2015-05-15 15:19:272015亚冠之山东鲁能
日期:2015-05-14 12:38:13金牛座
日期:2014-12-04 15:34:06子鼠
日期:2014-10-16 13:40:4715-16赛季CBA联赛之八一
日期:2016-07-22 09:41:40
跳转到指定楼层
1 [收藏(0)] [报告]
发表于 2014-08-29 15:09 |只看该作者 |倒序浏览
本帖最后由 zylthinking 于 2014-08-29 15:11 编辑

Visual studio 下发现一个函数一旦优化, 就出现 crash, 最终证明发生在 myref_get 中:
  1. static inline void* handle_get_with(my_handle* handle, int detach)
  2. {
  3.     printf("handle->statck = %p\n", &handle->stack);
  4.     int n = myref_get(&handle->stack);
  5.     int b = __sync_bool_compare_and_swap((void **) &handle->detached, (void *) 0, (void *) detach);
  6.     if (!b) {
  7.         handle_put(handle);
  8.         return NULL;
  9.     }

  10.     void* ptr = handle->ptr;
  11.     assert(n > 1 && ptr != NULL);
  12.     return ptr;
  13. }
复制代码
其中:

  1. static inline int myref_get(myref_t* refp)
  2. {
  3.     return (int) __sync_add_and_fetch(&refp->val, 1);
  4. }
复制代码
而后 __sync_add_and_fetch 实现如下, 就是 gcc 产生的代码的移植,

  1. static int __sync_add_and_fetch(void* lkp, int val)
  2. {
  3.     __asm {
  4.         mov ecx, val
  5.         mov edx, dword ptr [lkp]
  6.         mov eax, ecx
  7.         lock xadd dword ptr [edx], eax
  8.         add eax, ecx
  9.         leave
  10.         ret
  11.     };
  12.     return 0;
  13. }
复制代码
百思不得其解, 最终没办法直接反汇编调试, 发现 VC 给我把 myref_get 给 inline 了, 可是。。。。可是。。。。。, 白痴的是, 它把那段内嵌汇编原样拷贝了进去, 天知道我那个是为了从 __sync_add_and_fetch 返回用的。。。。。。。。, 这一搞直接是程序跑飞, 我真服劲了。。。。。。。

static inline void* handle_get_with(my_handle* handle, int detach)
{
10004380  push        ecx  
10004381  push        esi  
10004382  push        edi  
10004383  mov         esi,eax
    printf("handle->statck = %p\n", &handle->stack);
10004385  lea         edi,[esi+4]
10004388  push        edi  
10004389  push        offset string "handle->statck = %p\n" (1004FC14h)
1000438E  call        printf (1003960Ah)
10004393  add         esp,8
    int n = myref_get(&handle->stack);
10004396  mov         dword ptr [esp+8],edi
1000439A  mov         ecx,1
1000439F  mov         edx,dword ptr [esp+8]
100043A3  mov         eax,ecx
100043A5  lock xadd   dword ptr [edx],eax
100043A9  add         eax,ecx
100043AB  leave            
100043AC  ret      
      
    int b = __sync_bool_compare_and_swap((void **) &handle->detached, (void *) 0, (void *) detach);
100043AD  mov         eax,dword ptr [esp+10h]
100043B1  push        0   
100043B3  push        eax  
100043B4  lea         ecx,[esi+8]
100043B7  push        ecx  
100043B8  call        dword ptr [__imp__InterlockedCompareExchange@12 (1004E054h)]
100043BE  test        eax,eax
    if (!b) {
100043C0  je          handle_get_with+7Ch (100043FCh)
        handle_put(handle);
100043C2  mov         dword ptr [esp+8],edi
100043C6  mov         ecx,0FFFFFFFFh
100043CB  mov         edx,dword ptr [esp+8]
100043CF  mov         eax,ecx
100043D1  lock xadd   dword ptr [edx],eax
100043D5  add         eax,ecx
100043D7  leave            
100043D8  ret              
100043D9  push        0   
100043DB  lea         edx,[esi+0Ch]
100043DE  push        edx  
100043DF  call        dword ptr [__imp__InterlockedExchange@8 (1004E020h)]
100043E5  mov         esi,dword ptr [esi+10h]
100043E8  test        esi,esi
100043EA  je          handle_get_with+76h (100043F6h)
100043EC  test        eax,eax
100043EE  je          handle_get_with+76h (100043F6h)
100043F0  push        eax  
100043F1  call        esi  
100043F3  add         esp,4
100043F6  pop         edi  
        return NULL;
100043F7  xor         eax,eax
100043F9  pop         esi  
    }

论坛徽章:
14
巨蟹座
日期:2013-11-19 14:09:4615-16赛季CBA联赛之青岛
日期:2016-07-05 12:36:0515-16赛季CBA联赛之广东
日期:2016-06-29 11:45:542015亚冠之全北现代
日期:2015-07-22 08:09:472015年辞旧岁徽章
日期:2015-03-03 16:54:15巨蟹座
日期:2014-12-29 08:22:29射手座
日期:2014-12-05 08:20:39狮子座
日期:2014-11-05 12:33:52寅虎
日期:2014-08-13 09:01:31巳蛇
日期:2014-06-16 16:29:52技术图书徽章
日期:2014-04-15 08:44:01天蝎座
日期:2014-03-11 13:06:45
2 [报告]
发表于 2014-08-29 16:02 |只看该作者
VC对于内嵌汇编是不做任何修改或优化的(这是VC自己说的)
你只要将汇编的ret(以及相关的代码)去掉就行,也就是把eax的值用return返回。
还有一个办法,就是整个函数都用汇编写,但我忘了VC中怎么声明了

论坛徽章:
3
2015年迎新春徽章
日期:2015-03-04 09:56:11数据库技术版块每日发帖之星
日期:2016-08-03 06:20:00数据库技术版块每日发帖之星
日期:2016-08-04 06:20:00
3 [报告]
发表于 2014-08-29 16:05 |只看该作者
......

论坛徽章:
14
巨蟹座
日期:2013-11-19 14:09:4615-16赛季CBA联赛之青岛
日期:2016-07-05 12:36:0515-16赛季CBA联赛之广东
日期:2016-06-29 11:45:542015亚冠之全北现代
日期:2015-07-22 08:09:472015年辞旧岁徽章
日期:2015-03-03 16:54:15巨蟹座
日期:2014-12-29 08:22:29射手座
日期:2014-12-05 08:20:39狮子座
日期:2014-11-05 12:33:52寅虎
日期:2014-08-13 09:01:31巳蛇
日期:2014-06-16 16:29:52技术图书徽章
日期:2014-04-15 08:44:01天蝎座
日期:2014-03-11 13:06:45
4 [报告]
发表于 2014-08-29 16:05 |只看该作者
__declspec(naked)  你试试,不知道有没有效果

论坛徽章:
11
未羊
日期:2013-12-16 12:45:4615-16赛季CBA联赛之青岛
日期:2016-04-11 19:17:4715-16赛季CBA联赛之广夏
日期:2016-04-06 16:34:012015亚冠之卡尔希纳萨夫
日期:2015-11-10 10:04:522015亚冠之大阪钢巴
日期:2015-07-30 18:29:402015亚冠之城南
日期:2015-06-15 17:56:392015亚冠之卡尔希纳萨夫
日期:2015-05-15 15:19:272015亚冠之山东鲁能
日期:2015-05-14 12:38:13金牛座
日期:2014-12-04 15:34:06子鼠
日期:2014-10-16 13:40:4715-16赛季CBA联赛之八一
日期:2016-07-22 09:41:40
5 [报告]
发表于 2014-08-29 18:32 |只看该作者
bruceteen 发表于 2014-08-29 16:05
__declspec(naked)  你试试,不知道有没有效果


我不想纠缠了, 发现另一个办法
#define __sync_add_and_fetch(lkp, val) \
    (val + ((int) InterlockedExchangeAdd((LONG *) (lkp), (LONG) val)))

InterlockedExchangeAdd 实现看了一下, 其实就等于那段汇编, 只是没有最后的相加动作, 所以根本用不着搞什么鸟汇编

论坛徽章:
11
未羊
日期:2013-12-16 12:45:4615-16赛季CBA联赛之青岛
日期:2016-04-11 19:17:4715-16赛季CBA联赛之广夏
日期:2016-04-06 16:34:012015亚冠之卡尔希纳萨夫
日期:2015-11-10 10:04:522015亚冠之大阪钢巴
日期:2015-07-30 18:29:402015亚冠之城南
日期:2015-06-15 17:56:392015亚冠之卡尔希纳萨夫
日期:2015-05-15 15:19:272015亚冠之山东鲁能
日期:2015-05-14 12:38:13金牛座
日期:2014-12-04 15:34:06子鼠
日期:2014-10-16 13:40:4715-16赛季CBA联赛之八一
日期:2016-07-22 09:41:40
6 [报告]
发表于 2014-08-29 18:45 |只看该作者
本帖最后由 zylthinking 于 2014-08-29 18:48 编辑
bruceteen 发表于 2014-08-29 16:05
__declspec(naked)  你试试,不知道有没有效果


嗯, 你说的这个办法是可能有效的, 只要编译器别又拿着这段  naked 函数搞 inline, 然后还是玩原样拷贝的把戏, 否则恐怕照样玩不转, 因为这函数看上去是将数据压栈这些接管了, 返回地址压栈貌似还是编译器在做, 说白了, 只要被 inline 的内联汇编带着 ret, 而编译器来个原样拷贝, 那什么设置都搞不定

论坛徽章:
9
摩羯座
日期:2013-08-15 15:18:48狮子座
日期:2013-09-12 18:07:47金牛座
日期:2013-09-16 13:23:09辰龙
日期:2013-10-09 09:03:27白羊座
日期:2013-10-17 13:32:44子鼠
日期:2014-04-23 15:09:38戌狗
日期:2014-09-17 11:37:542015年亚洲杯之韩国
日期:2015-03-26 10:16:442015亚冠之武里南联
日期:2015-08-18 14:55:52
7 [报告]
发表于 2014-09-01 09:30 |只看该作者
本帖最后由 w_anthony 于 2014-09-01 09:40 编辑

LZ,你的函数不是naked,竟然也敢在中间ret掉?万一编译器把esp挪一下做什么缓冲区检测也是很有可能的(不好意思,漏看你的leave,不过万一编译优化后,函数起初没有mov ebp,esp怎么 办?而且对于通常情况而言,仍然不能保证esi、edi和ebx恢复初始值了),你这样ret不怕出问题吗?
而且既然你的函数不是naked的,那么编译器很可能认为不会在asm中途出现ret指令(因为这样是很容易出错的),所以就可能直接内联了,否则应该不会内联它。
-----------------------
如果一定要用内联汇编,而又不想用naked的,那么从规矩上讲,就不应该在asm中途ret,应该定义一个变量再把值赋给它,最后把它return出来;
如果要用内联汇编,那么asm里面可以有也必须有ret,并且函数参数名称不能直接使用,需要用[esp+偏移量]表示。
您需要登录后才可以回帖 登录 | 注册

本版积分规则 发表回复

  

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

清除 Cookies - ChinaUnix - Archiver - WAP - TOP