c - 深入 assembly

标签 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 中一定有一些隐藏的指示告诉编译器这样做,对吧?

最佳答案

不,没有隐藏的指示。

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

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

为什么不是 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 以来的 80x86 秒(可能是 80486——太久远了,我无法确定)。

x86 架构是一个奇怪的野兽。每个寄存器,虽然被 Intel 提升为“通用”,但都有其怪癖(例如,cx/ecxloop 指令相关联,并且 eax:edx 与乘法指令相关联)。这与优化执行以避免缓存未命中和管道停顿的特殊方法相结合,通常会导致代码生成器生成难以理解的代码,而代码生成器会将所有这些因素都考虑在内。

关于c - 深入 assembly ,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/6079543/

相关文章:

c++ - 查找特定总和的数字的所有组合

c - 程序集中的 Printf 调用在输出期间未将 IEEE-754 浮点值格式化为十六进制

assembly - 我的 LC-3 输入代码没有按预期工作

c++ - 我可以使用输出作为 #define 中的参数吗

c - 将数组传递给函数时的异常行为

c - 为什么我的共享库在编译为位置无关代码时要大得多?

memory - x86 mov/add 指令和内存寻址

c++ - 不良状态登记?

assembly - 汇编器 8086 将 32 位数除以 16 位数

C++ 函数在 double 组中查找最大值?