Назначение регистров ESI и EDI?

119

Каково фактическое назначение и использование регистров EDI и ESI в ассемблере?

Я знаю, что они используются для строковых операций с одной стороны.

Может кто-нибудь также привести пример?

Тони Лев
источник
9
Проверьте это: swansontec.com/sregisters.html
Джеффпоурс,

Ответы:

78

Есть несколько операций, которые вы можете выполнять только с DI / SI (или их расширенными аналогами, если вы не изучали ASM в 1985 году). Среди них

REP STOSB
REP MOVSB
REP SCASB

Это, соответственно, операции для повторного (= массового) сохранения, загрузки и сканирования. Что вы делаете, так это настраиваете SI и / или DI так, чтобы они указывали на один или оба операнда, возможно, помещаете счет в CX, а затем позволяете разорвать. Это операции, которые работают с кучей байтов за раз, и они как бы переводят процессор в автоматический режим. Поскольку вы явно не кодируете циклы, они выполняют свою задачу более эффективно (обычно), чем цикл, кодируемый вручную.

На всякий случай вам интересно: в зависимости от того, как вы настроили операцию, повторное сохранение может быть чем-то простым, например, вставкой значения 0 в большой непрерывный блок памяти; Я думаю, что MOVSB ​​используется для копирования данных из одного буфера (ну, любой связки байтов) в другой; а SCASB используется для поиска байта, который соответствует некоторому критерию поиска (я не уверен, ищет ли он только равенство или что-то еще - вы можете найти его :))

Это большая часть того, для чего нужны эти регистры.

Карл Смотрич
источник
7
Совет по оптимизации из прошлого: rep stosw намного быстрее, чем rep stosb , поэтому, если копирование двух и двух байтов соответствует тому, что вы пытаетесь сделать, используйте это вместо этого в своем вручную оптимизированном 16-битном ассемблерном коде x86 ...
Александр
88

SI= Исходный индекс
DI= Целевой индекс

Как указывали другие, они имеют особое применение со строковыми инструкциями. Для реального программирования режима, то ESрегистр сегмента должен быть использован с , DIи DSс , SIкак и в

movsb  es:di, ds:si

SI и DI также могут использоваться в качестве индексных регистров общего назначения. Например, Cисходный код

srcp [srcidx++] = argv [j];

компилируется в

8B550C         mov    edx,[ebp+0C]
8B0C9A         mov    ecx,[edx+4*ebx]
894CBDAC       mov    [ebp+4*edi-54],ecx
47             inc    edi

где ebp+12содержит argv, ebxесть jи ediимеет srcidx. Обратите внимание, что в третьей инструкции используется ediумножение на 4 и добавление ebpсмещения на 0x54 (расположение srcp); скобки вокруг адреса указывают на косвенное обращение.


Хотя я не могу вспомнить, где я это видел, но это подтверждает большую часть этого, и это (слайд 17) другие:

AX= аккумулятор
DX= двойное слово аккумулятор
CX= счетчик
BX= базовый регистр

Они выглядят как регистры общего назначения, но есть ряд инструкций, которые (неожиданно?) Используют один из них - но какая? - неявно.

wallyk
источник
37

Коды операций, такие как MOVSB ​​и MOVSW, которые эффективно копируют данные из памяти, на которую указывает ESI, в память, на которую указывает EDI. Таким образом,

mov esi, source_address
mov edi, destination_address
mov ecx, byte_count
cld
rep movsb ; fast!
кошачья еда
источник
12

В дополнение к строковым операциям (MOVS / INS / STOS / CMPS / SCASB / W / D / Q и т. Д.), Упомянутым в других ответах, я хотел добавить, что есть также более «современные» инструкции по сборке x86, которые неявно используются в минимум EDI / RDI:

Инструкция SSE2 MASKMOVDQU(и предстоящий AVX VMASKMOVDQU) выборочно записывает байты из регистра XMM в память, на которую указывает EDI / RDI.

Phis
источник
6

В дополнение к регистрам, используемым для массовых операций, они полезны тем, что их свойство сохраняется посредством вызова функции (сохранение вызова) в 32-битном соглашении о вызовах. ESI, EDI, EBX, EBP, ESP сохраняют вызовы, тогда как EAX, ECX и EDX не сохраняют вызовы. Регистры с сохранением вызовов соблюдаются библиотечной функцией C, и их значения сохраняются через вызовы функций библиотеки C.

Джефф Дантеманн в своей книге на ассемблере имеет пример кода ассемблера для печати аргументов командной строки. Код использует esi и edi для хранения счетчиков, поскольку они не будут изменены функцией printf библиотеки C. Для других регистров, таких как eax, ecx, edx, нет гарантии, что они не будут использоваться функциями библиотеки C.

https://www.amazon.com/Assembly-Language-Step-Step-Programming/dp/0470497025

См. Раздел 12.8 «Как C видит аргументы командной строки».

Обратите внимание, что 64-битные соглашения о вызовах отличаются от 32-битных соглашений о вызовах, и я не уверен, сохраняются ли эти регистры с сохранением вызовов или нет.

Джей Раджпут
источник
Я никогда не слышал, чтобы слово «священный» использовалось для описания того, что большинство людей называют «энергозависимым» / «энергонезависимым» или «сохраненным вызываемым» против «сохраненным вызывающим абонентом». Мне нравится "сохраненный вызов" / "закрытый вызов", поскольку это не означает, что они действительно где-либо сохраняются. В любом случае, вызовы ESI / RSI и EDI / RDI не сохраняются в x86-64 System V ABI.
Питер Кордес,
Кроме того, вы забыли указать EBP и ESP как сохраненные вызовы в общих 32-битных соглашениях о вызовах.
Питер Кордес,
1
В любом случае, это неплохой момент. В реальном коде вы с большей вероятностью выберете EDI / ESI для чего-то, основанного на причинах соглашения о вызовах, чем потому, что они являются специальными для любых инструкций.
Питер Кордес,
Мне нравится звонок-сохранен. Я обновил ответ таким же образом. Спасибо за обзор.
Джей Раджпут,