潜入大会

时间:2011-05-21 04:10:24

标签: c assembly x86

c中的功能:

PHPAPI char *php_pcre_replace(char *regex,   int regex_len,
                              char *subject, int subject_len,
                              zval *replace_val, int is_callable_replace,
                              int *result_len, int limit, int *replace_count TSRMLS_DC)
{
    pcre_cache_entry    *pce;               /* Compiled regular expression */

    /* Compile regex or get it from cache. */
    if ((pce = pcre_get_compiled_regex_cache(regex, regex_len TSRMLS_CC)) == NULL) {
        return NULL;
    }

    ....
}

它的组装:

php5ts!php_pcre_replace:
1015db70 8b442408        mov     eax,dword ptr [esp+8]
1015db74 8b4c2404        mov     ecx,dword ptr [esp+4]
1015db78 56              push    esi
1015db79 8b74242c        mov     esi,dword ptr [esp+2Ch]
1015db7d 56              push    esi
1015db7e 50              push    eax
1015db7f 51              push    ecx
1015db80 e8cbeaffff      call    php5ts!pcre_get_compiled_regex_cache (1015c650)
1015db85 83c40c          add     esp,0Ch
1015db88 85c0            test    eax,eax
1015db8a 7502            jne     php5ts!php_pcre_replace+0x1e (1015db8e)

php5ts!php_pcre_replace+0x1c:
1015db8c 5e              pop     esi
1015db8d c3              ret

c函数调用pcre_get_compiled_regex_cache(regex, regex_len TSRMLS_CC)对应于1015db7d~1015db80,它将3个参数推送到堆栈并调用它。

但我的疑问是,在众多寄存器中,编译器如何决定使用eaxecxesi(这是特殊的,因为它在使用之前已经恢复,为什么? )作为携带到堆栈的中间体?

c中必须有一些隐藏的指示告诉编译器这样做,对吧?

1 个答案:

答案 0 :(得分:2)

不,没有隐藏的迹象。

这是生成许多编译器实现C使用的80x86指令的典型策略。例如,20世纪80年代英特尔Fortran-77编译器在启用优化时也做了同样的事情。

这是使用eaxecx优先可能是避免使用esiedi的工件,因为这些寄存器不能直接用于加载字节操作数。 / p>

为什么不ebxedx?那么,许多代码生成器首选这些代码生成器用于在评估复杂结构评估时保留中间指针,也就是说,根本没有太多理由。编译器只查找了两个可用的寄存器,并将其覆盖以缓冲值。

为什么不像这样重用eax?:

   push    esi
   mov     eax,dword ptr [esp+2Ch]
   push    eax
   mov     eax,dword ptr [esp+8]
   push    eax
   mov     eax,dword ptr [esp+4]
   push    eax

因为这会导致等待eax完成先前内存周期的管道停顿,自80586以来的80x86s(可能是80486-它已经很久以前确定不了我的头脑)。

x86架构是一个奇怪的野兽。每个寄存器虽然被英特尔宣传为“通用”,但它的怪癖(cx / ecxloop指令相关联,并且eax:edx被绑定到乘法指令)。结合优化执行以避免缓存未命中和流水线停顿的特殊方法,通常会导致代码生成器生成难以置信的代码,这会影响所有内容。