Погрузитесь в сборку - PullRequest
1 голос
/ 21 мая 2011

Функция в 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, который указывает компилятору делать это таким образом, верно?

1 Ответ

2 голосов
/ 21 мая 2011

Нет, скрытой индикации нет.

Это типичная стратегия для генерации инструкций 80x86, используемых во многих реализациях компилятора, C и других.Например, компилятор Intel Fortran-77 1980-х годов, когда была включена оптимизация, делал то же самое.

То есть использует eax и ecx преимущественно, вероятно, является артефактом отказа от использования esiи edi, поскольку эти регистры нельзя напрямую использовать для загрузки байтовых операндов.

Почему бы не 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, чтобы завершить предыдущие циклы памяти, в 80x86 с 80586 (может быть, 80486 - это слишком давно, чтобы быть уверенным в головах).

Архитектура x86 - странный зверь.Каждый регистр, хотя Intel и называет его «универсальным», имеет свои причуды (cx / ecx связан, например, с инструкцией loop, а eax:edx связан с инструкцией умножения).Это в сочетании с особыми способами оптимизации выполнения во избежание промахов кэша и остановок конвейера часто приводит к непостижимому генерируемому коду с помощью генератора кода, который учитывает все это.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...