Подтвердить что ты не робот

Базовое использование немедленных и квадратных скобок в сборке YASM/NASM x86

Предположим, у меня заявлено следующее:

section .bss
buffer    resb     1

И эти инструкции следуют в section .text:

mov    al, 5                    ; mov-immediate
mov    [buffer], al             ; store
mov    bl, [buffer]             ; load
mov    cl, buffer               ; mov-immediate?

Правильно ли я понимаю, что bl будет содержать значение 5, а cl будет содержать адрес памяти переменной buffer?

Я запутался в различиях между

  • перемещать немедленный в регистр,
  • перемещение регистра в немедленное (что входит, данные или адрес?) и
  • перемещение немедленного в регистр без скобок
    • Например, mov cl, buffer против mov cl, [buffer]

ОБНОВЛЕНИЕ: после прочтения ответов, я думаю, что следующее резюме является точным:

  • mov edi, array помещает адрес памяти индекса нулевого массива в edi. то есть адрес этикетки.
  • mov byte [edi], 3 помещает ЗНАЧЕНИЕ 3 в нулевой индекс массива
  • после add edi, 3, edi теперь содержит адрес памяти третьего индекса массива
  • mov al, [array] загружает данные в нулевом индексе в al.
  • mov al, [array+3] загружает данные в третьем индексе в al.
  • mov [al], [array] недопустим, потому что x86 не может кодировать 2 явных операнда памяти, а также потому, что al имеет только 8 битов и не может использоваться даже в 16-битном режиме адресации. Ссылка на содержимое ячейки памяти. (режимы адресации x86)
  • mov array, 3 недопустим, потому что вы не можете сказать: "Эй, мне не нравится смещение, при котором хранится array, поэтому я назову его 3". Непосредственным может быть только исходный операнд.
  • mov byte [array], 3 помещает значение 3 в нулевой индекс (первый байт) массива. Спецификатор byte необходим, чтобы избежать неоднозначности между байтом/словом/двойным словом для инструкций с памятью, непосредственными операндами. В противном случае это будет ошибка времени сборки (неоднозначный размер операнда).

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

4b9b3361

Ответ 1

В самом деле, ваша мысль правильная. То есть bl будет содержать 5 и cl адрес памяти буфера (на самом деле буфер метки является адресом памяти).


Теперь позвольте мне объяснить различия между упомянутыми вами операциями:

  • перемещение непосредственно в регистр может быть выполнено с помощью mov reg,imm. Что может сбить с толку, так это то, что метки, например буфер, являются непосредственными значениями, которые содержат адрес.

  • Вы не можете переместить регистр в непосредственный, так как немедленные значения - это константы, такие как 2 или FF1Ah. Что вы можете сделать, это переместить регистр в место, где постоянная указывает на. Вы можете сделайте это как mov [const], reg.

  • Вы также можете использовать косвенную адресацию, например, mov reg2,[reg1], если рег1 указывает на действительное местоположение, и оно перенесет значение, указанное reg1 в reg2.


Итак, mov cl, buffer переместит адрес из буфера в cl (который может или не может дать правильный адрес, так как cl - только один байт), тогда как mov cl, [buffer] получит фактическое значение.

Резюме

  • Когда вы используете [a], вы ссылаетесь на значение в том месте, где указаны точки. Например, если a является F5B1, тогда [a] ссылается на адрес F5B1 в ОЗУ.
  • Ярлыки - это адреса, то есть такие значения, как F5B1.
  • Значения, хранящиеся в регистрах, не обязательно должны быть указаны как [reg], потому что регистры не имеют адресов. Фактически, регистры можно рассматривать как непосредственные значения.

Ответ 2

Квадратные скобки по существу работают как оператор разыменования (например, как * в C).

Итак, что-то вроде

mov REG, x

перемещает значение x в REG, тогда как

mov REG, [x]

перемещает значение ячейки памяти, x указывает x в REG. Обратите внимание, что если x является меткой, его значение является адресом этой метки.

Что касается вашего вопроса:

Правильно ли я понимаю, что bl будет содержать значение 5, а cl будет содержать адрес памяти буфера переменных?

Да вы правы. Но имейте в виду, что, поскольку CL имеет ширину всего 8 бит, он будет содержать только младший байт адреса buffer.

Ответ 3

Вы получаете идею. Однако необходимо иметь в виду несколько деталей:

  • Адреса могут и обычно больше, чем 8 бит могут содержать (cl - 8 бит, cx - 16 бит, ecx - 32-разрядный, rcx - 64-разрядный). Таким образом, cl, вероятно, будет неравным с адресом переменной buffer. Он будет иметь наименее значимые 8 бит адреса.
  • Если существуют подпрограммы прерываний или потоки, которые могут вытеснить вышеуказанный код и/или получить доступ к buffer, значение в bl может отличаться от 5. Процедуры прерывания прерываний могут фактически влиять на любой регистр, когда они не могут сохранить значения регистров.

Ответ 4

Для всех инструкций с использованием непосредственных значений в качестве операнда для записи значения в место помех (или для вычисления внутри) мы должны указать, сколько байтов мы хотим получить. Поскольку наш сборник не может знать, хотим ли мы получить доступ только к одному байту, word или doppleword, если ближайшее значение ниже значение, как показано в следующих инструкциях.

array db 0FFh, 0FFh, 0FFh, 0FFh
mov byte [array], 3

результаты:

array db 03h, 0FFh, 0FFh, 0FFh

....

mov word [array], 3

результаты:

array db 03h, 00h, 0FFh, 0FFh

....

mov dword [array], 3

результаты:

array db 03h, 00h, 00h, 00h

Дирк