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个参数推送到堆栈并调用它。
但我的疑问是,在众多寄存器中,编译器如何决定使用eax
,ecx
和esi
(这是特殊的,因为它在使用之前已经恢复,为什么? )作为携带到堆栈的中间体?
c中必须有一些隐藏的指示告诉编译器这样做,对吧?
答案 0 :(得分:2)
不,没有隐藏的迹象。
这是生成许多编译器实现C
使用的80x86指令的典型策略。例如,20世纪80年代英特尔Fortran-77编译器在启用优化时也做了同样的事情。
这是使用eax
和ecx
优先可能是避免使用esi
和edi
的工件,因为这些寄存器不能直接用于加载字节操作数。 / p>
为什么不ebx
和edx
?那么,许多代码生成器首选这些代码生成器用于在评估复杂结构评估时保留中间指针,也就是说,根本没有太多理由。编译器只查找了两个可用的寄存器,并将其覆盖以缓冲值。
为什么不像这样重用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
/ ecx
与loop
指令相关联,并且eax:edx
被绑定到乘法指令)。结合优化执行以避免缓存未命中和流水线停顿的特殊方法,通常会导致代码生成器生成难以置信的代码,这会影响所有内容。