2016-10-25 4 views
0

Я пытаюсь изучить язык ассемблера. Я заметил, что это совершенно другое по сравнению с высокоуровневыми языками программирования, такими как Java.Сборка Значения переменных сегмента данных языка

Так что я читал, что команда передачи данных следует следующий синтаксис:

mnemonic destination, source 

, который я вижу, как destination = source Другими словами, присвоение значения в памяти.

Я видел пример в этой декларации сегмента данных.

.data 
var1 SBYTE -4,-2,3,1 
var2 WORD 1000h,2000h,3000h,4000h 
var3 SWORD -16,-42 
var4 DWORD 1,2,3,4,5 

Как есть переменные? 1 значение? Что это значит?

Буду признателен за любые объяснения.

Спасибо.

+0

Это означает, что этот список байтов или список DWORDs в выходной файл. Может быть, вам следует продолжать читать книгу, содержащую пример, так как это, вероятно, объясняет это очень скоро. –

ответ

1

Для определения нескольких переменных WORD размера в сборке мы можем использовать

var1 WORD 1000h 
var2 WORD 2000h 
var3 WORD 3000h 
var4 WORD 4000h 

Часто программисту не нужно называть каждую переменную, только первый, а затем использовать арифметику указателей, чтобы добраться до других ,
В этом случае мы можем использовать

var1 WORD 1000h 
    WORD 2000h 
    WORD 3000h 
    WORD 4000h 

Это особенно удобно, когда некоторые переменные могут иметь различные размеры, в противном случае повторение ключевого слова WORD раздражает и может быть упрощена в окончательном виде

var1 WORD 1000h, 2000h, 3000h, 4000h 

Это эквивалентно второй форме и (имена в стороне) для первой формы.

+0

Спасибо за пример и объяснение. Это немного отличается от языка, такого как Java, который я изначально узнал, где большая часть переменных времени дается своим собственным именем. Как и ваш первый пример. Я ценю это. Благодарю. :) – p3ace

+0

Я понимаю это сейчас. – p3ace

0

Я бы даже не использовал слово «переменная» в сборке.

Конечно, вы можете так думать, и это будет в основном работать, но технически это более низкий уровень.

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++ все переменные-члены класса/структуры, записанные в источнике, можно представить в виде байта по байтовой части памяти, причем каждая переменная-член имеет особое смещение и выравнивание, определяемые по типу и положению в источнике. В этот момент вы можете создать предварительно инициализированный экземпляр такой структуры, указав значения для каждого байта в блоке размера полной структуры.