Я бы даже не использовал слово «переменная» в сборке.
Конечно, вы можете так думать, и это будет в основном работать, но технически это более низкий уровень.
var1 DWORD 12345678h
будет компилировать значение 12345678h
в четыре байта (на x86 прямой порядок байтов байты будут 78 56 34 12
), те будут «земли» где-то в .data
сегмент, который станет содержимое памяти после загрузки исполняемого файла ОС. ОС загрузит некоторую свободную память для ее загрузки, поэтому он также предоставит начальный адрес сегмента .data
и настроит загруженный код, чтобы отразить реальный адрес после завершения загрузки двоичного файла, перед его выполнением.
Это означает, что байты с 78 56 34 12
будут доступны по определенному адресу (память на x86 адресуется байтами).
И var1
станет символом в таблице символов, обозначающим адрес первого байта из четырех.
Затем вы можете написать в инструкции Ассамблеи как mov cl,[var1]
, что означает «нагрузку cl
с байтом из памяти по адресу символа var1
», эта команда отмечена в исполняемом и OS будет корректировать его с реальным значением таблицы символов, поэтому во время это будет указывать на правильную память, где был загружен сегмент .data.
. При использовании относительной адресации x86_64 инструкция mov
скомпилирована как mov cl,[rip+offset_between_next_instruction_and_var1]
, тогда ОС не нуждается в настройке инструкции вообще, поскольку она будет работать в любом месте памяти, смещение относительно.
Загрузка содержимого памяти с адреса [var1]
размера BYTE будет загружена 78h
- пример нетривиальной манипуляции с переменным мышлением. И загрузка WORD из [var1+1]
будет загружать значение WORD 3456h
из памяти (на платформе, отличной от x86, доступ к неограниченному доступу к памяти может привести к поломке исполнения, на x86 он будет работать, только производительность будет наказываться).
Тогда var1 DWORD 1,2,3,4
просто означает, что вы скомпилируете больше байтов за этим адресом var
, например 01 00 00 00 02 00 00 00 ....
. И вы можете работать с ними, обратившись к ним, поскольку mov eax,[var1 + 2*4]
-> загрузит значение var1[2]
(Java like array) в eax
, что составляет 3
.
Обратите внимание, что var1
- это просто адрес памяти, поэтому вы можете фактически адресовать даже данные из var2
, если вы добавите к нему правильное смещение. следовательно, непреднамеренная перезапись других переменных в сборке настолько проста, например, достаточно написать ошибку DWORD в BYTE по ошибке, и вы уже перезаписали 3 байта некоторой памяти за пределами переменной, вероятно, используемой какой-либо другой переменной.
Также обратите внимание, как вы всегда должны делать * 1, * 2, * 4, .. индекса при доступе к массивам вручную! Поэтому вы должны всегда знать размер элемента массива.
Основная мощность двух размеров могут быть непосредственно закодирована в расширенной адресации режиме обучения x86, как mov eax,[ebx + esi*4 - 44]
для решения какой-то DWord массив в EBX адрес с индексом «еси-11», так что Java-как она будет напоминать eax = ebx[esi-11];
, экономя вы можете рассчитывать умножение отдельно.
Это еще один распространенный источник ошибок, забыв, что «индекс» равен «смещению байта памяти» только тогда, когда элемент массива имеет размер одного байта, во всех остальных случаях вам нужно умножить индекс на размер элемента, чтобы получить байт-смещение для адресации памяти.
Наконец, когда вы пишете эти вещи в .data
сегмент, они компилируются последовательно, в качестве каскадного потока байт (проверьте характеристики Assembler, чтобы узнать о каком-либо автоматическом заполнении конкретных директив, как dword
, вставив отступы байт вперед по мере необходимости выровнять полученные данные). Таким образом, вам на самом деле не нужен var1
, если вы хотите пойти на хардкор, рассчитать все смещения по своему усмотрению и адресовать эти байты через .data + offset
, это возможно (это просто умственное упражнение, чтобы показать вам, что значит писать »больше значений «на линии, а не рекомендация :)).
Редактировать: "irvine" ... так что вы, вероятно, используете в качестве ассемблера MASM? Во время компиляции хранится не только символ адреса, но и запоминается первый размер объявления (например, «DWORD»), поэтому он попытается охватить некоторые варианты использования с более «переменным» подходом к компиляции.
Я лично предлагаю вам игнорировать это и думать о них только как о адресах и избегать всех синтаксисов приманок MASM, так как 1) он не работает в других ассемблерах x86 2) может быть довольно запутанным в более крупном источнике, один раз вы привыкаете к сборке низкого уровня.
Я имею в виду, что в MASM mov eax,var1
скомпилирован в машинный код как mov eax,[address_of_var1]
(загрузите eax с содержимым памяти в var1, то есть «load eax с переменной var1» с человеческой точки зрения).
Но когда я прочитал в исходной инструкции без видимых []
, я привык думать, что он не обращается к памяти и работает только с немедленным (как в случае с mov eax,esi
против mov eax,[esi]
). Даже в MASM вы можете написать mov eax,[var1]
, он тоже будет работать. Но для извлечения адреса самого var1 требуется дополнительный синтаксический сахар, например mov eax,OFFSET var1
IIRC.
Конечная нота: те WORD 1,2,3,4
определения, как правило, используются в тех местах, где в Java вы могли бы использовать массив, как short wordArrayVar[] = {1, 2, 3, 4};
. Это одна из возможных интерпретаций этих многозначных определений. Но в некоторых случаях он используется даже на более низком уровне, просто определяя конкретные байтовые значения в сегменте .data, даже не для использования в качестве массива, но каким-то другим способом.
Еще один общий шаблон - инициализация экземпляра «структура», в Java нет хорошего примера, поскольку переменные-члены класса не гарантируются в памяти один за другим? Но в C++ все переменные-члены класса/структуры, записанные в источнике, можно представить в виде байта по байтовой части памяти, причем каждая переменная-член имеет особое смещение и выравнивание, определяемые по типу и положению в источнике. В этот момент вы можете создать предварительно инициализированный экземпляр такой структуры, указав значения для каждого байта в блоке размера полной структуры.
Это означает, что этот список байтов или список DWORDs в выходной файл. Может быть, вам следует продолжать читать книгу, содержащую пример, так как это, вероятно, объясняет это очень скоро. –