Различия в присвоении значений регистрам сборки? - PullRequest
0 голосов
/ 14 мая 2018

Я изучаю ассемблер в синтаксисе nasm для архитектуры x86.Я нашел несколько примеров программы HelloWorld, а также скачал несколько других примеров, таких как Caculator.- Я запутался в чем-то, что нашел, например, в чем разница между двумя примерами, упомянутыми ниже:

  mov eax, 4 ; sys_write
  mov ebx, 1
  mov ecx, string ; string in .data section
  mov edx, str_len ; string length
  int 80h

Теперь посмотрим на другой пример (фокус на регистры):

  mov eax, str_len
  mov ebx, string
  mov ecx, 4
  mov edx, 1
  int 80h

Вы можете видеть в приведенных выше двух примерах, сосредоточиться на regesters.Какая разница, если я назначу «eax, 4» или «edx, 4» или что если я назначу «ecx, 4».В чем разница?

Являются ли регистры "специфичными" для определенного типа значения, или я могу присвоить любое значение любому регистру?

Примечание: я изучаю NASM, если вы нашли этот вопрос глупымПожалуйста, не кусайте.Я даже не могу понять эту разницу в сборке.

Примечание. Моя целевая платформа - 32-разрядная версия Linux.

1 Ответ

0 голосов
/ 14 мая 2018

Являются ли регистры "специфичными" для определенного типа значения, или я могу присвоить любое значение любому регистру?

На x86 регистры ЦП в основном "общего назначения", то есть в вашем собственном коде вы можете использовать eax против edx довольно свободно, за исключением нескольких инструкций, использующих неявные регистры (div, mul, stos, movs, ...).

Затем существуют специальные регистры (сегмент, управление, флаг, eip).

Таким образом, вы обычно можете присвоить любое значение любому [общему] регистру.

Какая разница, если я назначу "eax, 4" или "edx, 4" или что если я назначу "ecx, 4".

Разница в том, что значение 4 будет сохранено либо в eax, либо в регистре edx. Оба они являются 32-битными регистрами x86 «общего назначения», оба хранят только тридцать два 0 или 1 значения, ничего более (также они не хранят никакой информации о «типе» или о том, как значение возникло в регистре, как он был отформатирован в источнике и т. д. * mov eax,16 идентичен mov eax,0x10, процессор видит только конечный двоичный машинный код, который идентичен для обоих вариантов исходного кода, и загружает двоичное значение 00..0010000 (16 ) в реестр eax). То есть пока что особой разницы нет, кроме ваших личных предпочтений.

Часть, где выбор eax против edx начнет иметь значение при использовании этих регистров (интерпретация значений битов определенным образом), и это в вашем примере происходит с int 80h.

Эта инструкция вызывает 32-битные службы ядра Linux, то есть за ней скрываются тысячи строк кода, которые выполняют различные функции для приложений, и эти строки уже были скомпилированы поставщиком дистрибутива (или вами), и они являются частью двоичное ядро.

И разработчики Linux уже решили, что eax содержит id-номер запрашиваемой службы, а другие регистры содержат аргументы для этой конкретной службы.

eax = 4 равно sys_write, в то время как ваш второй пример с eax = str_len вызовет какую-то другую службу, в зависимости от длины строки ("Hello world." имеет длину 12 символов, поэтому ядро ​​linux будет пытаться обслуживать sys_chdir сервис для eax = 12 аргумента).

Таким образом, ваш второй пример не выводит «Hello world», и, судя по контексту, это просто недопустимый пример.

Когда вы вызываете какой-то внешний код, не принадлежащий вам, вы должны искать в документации, как правильно его назвать, и где / как передаются аргументы и какие условия должны быть выполнены (например, в 64-битном режиме при вызове функций C вы должны также выровнять адрес стека rsp по границам 16B).

Для 32-битного ядра Linux системная служба документов ... не знаю, какие документы являются лучшими и надежными, эта ссылка из информации тега x86, как представляется, содержит подробную и полную информацию о том, как выполнять такие вызовы службы: https://blog.packagecloud.io/eng/2016/04/05/the-definitive-guide-to-linux-system-calls/

Хотя в этой ссылке от Google https://syscalls.kernelgrok.com/ перечислены конкретные службы и ожидаемые аргументы (в сочетании с проверкой руководства по Linux для sys_write и других должно быть достаточно).

Конкретный sys_write из вашего примера ожидает аргументы как:

  • eax = 4
  • ebx = дескриптор файла (1 = стандартный вывод)
  • ecx = данные для записи (адрес памяти первого байта данных)
  • edx = длина данных для записи (в байтах).
...