Базовое использование немедленных и квадратных скобок в сборке 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. И связал другие вопросы и ответы).
Ответы
Ответ 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
Дирк