2016-03-09 3 views
1

В последнее время я писал некоторые монтажные инъекции x86 для игрового мода, но поскольку большая часть моего рабочего процесса связана с написанием и сбором пользовательских подпрограмм вручную, я был стремясь перейти к более надежному решению.MASM Mov с/на адрес оперативной памяти

Встроенный ассемблер Microsoft выглядит как хороший выбор, но я столкнулся с чем-то вроде ограничения, которое, похоже, имеет.

Всякий раз, когда я пишу инструкцию, которая включает в себя адрес прямой памяти (игра использует макет фиксированного адресного пространства), ассемблер молча преобразует его в непосредственное значение.

Например, в MASM:

mov ecx, 0xCCCCCCCC => B9 CC CC CC CC 
mov ecx, [0xCCCCCCCC] => B9 CC CC CC CC* 

* Should be: 8B 0D CC CC CC CC 

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

Обратите внимание, что можно использовать переменную с именем таким образом:

mov ecx, [myInt] 

Которая будет собираться в инструкцию выборки памяти 8B 0D, но также добавляет операнд в таблицу перемещения модуля и не позволяет специфицировать произвольные адреса.

Попытка обмануть ассемблер с чем-то вроде

mov ecx, [myInt-myInt+0xCCCCCCCC] 

приводит также в адрес рассматривается как непосредственное значение.

Вполне возможно можно пойти с:

mov ecx, 0xCCCCCCCC 
mov ecx, [ecx] 

Какие будут собираться правильно и демонстрировать правильное поведение, но теперь я раздутой мой размер впрыска от 2 лишних байтов. Поскольку я работаю при довольно жестких пространственных ограничениях, это неприемлемо, и я бы предпочел не использовать пещеру кода, где мне не нужно.

Самое смешное, что что-то в C нравится:

register int x; 
x = *(int*)(0xCCCCCCCC) 

Счастливо компилирует

mov ecx, [0xCCCCCCCC] => 8B 0D CC CC CC CC 

Это немного странно видеть более низкий уровень языка имеют больше ограничений, установленных на нем, чем выше уровня. То, что я пытаюсь сделать, выглядит довольно разумным для меня, так же как и кто-нибудь знает, имеет ли MASM скрытый способ использования фиксированных адресов памяти при чтении из памяти?

+0

MASM не выполняет арифметику между метками? Это только внутри эффективного адреса, или оно также применяется в выражении, используемом как немедленное? Я мог представить, что это не работает, если метки были «extern», поэтому разница была доступна только как время ссылки, а не время сборки. Вы должны иметь возможность использовать локальные метки или любую существующую метку (например, имя текущей функции). –

+1

Извините, это была моя ошибка. Я проводил немного тестирования взад и вперед между MASM и встроенным ассемблером VS. Встроенный ассемблер более ограничен, поэтому он не поддерживает арифметику меток, но сам MASM в порядке. Тем не менее, эффективный адрес по-прежнему заканчивается тем, что рассматривается как немедленное значение. –

+1

Я думаю, что Ross Ridge дает довольно хороший ответ на аналогичный вопрос MASM в этом SO-ответе: http://stackoverflow.com/a/25130189/3857942 –

ответ

1

Я не уверен, если это работает за пределами плоской модели памяти, но я обнаружил, что MASM отличает непосредственные адреса и непосредственные значения следующим образом:

mov ecx, 0xCCCCCCCC  => B9 CC CC CC CC 
mov ecx, [0xCCCCCCCC] => B9 CC CC CC CC 
mov ecx, ds:[0xCCCCCCCC] => 8B 0D CC CC CC CC 

Первые 2 инструкции нагрузки ECX с непосредственным значением 0xCCCCCCCC. Последняя команда загружает ecx со значением по адресу 0xCCCCCCCC.

+0

Как насчет 'mov ecx, DWORD PTR [0xCCCCCCCC]'? – Michael

+0

Добавление DWORD PTR не влияет на поведение в любом случае. –

+1

Huh. И 'mov al, byte ptr [12345678h]' дает вам 'mov al, 78h'. Если кто-то сознательно реализовал его так, было бы интересно услышать мотивацию: P – Michael

1

В синтаксисе NASM,

mov  ecx, 0xCCCCCCCC     ; B9 CC CC CC CC  mov ecx, imm32 
    mov  ecx, [0xCCCCCCCC]    ; 8b 0d cc cc cc cc mov r32, [disp32] 
    mov  ecx, [_start-_start + 0xCCCCCCCC]; 8b 0d cc cc cc cc same 

Испытано с nasm -felf и yasm -felf, на моем рабочем столе GNU/Linux.

Интересно, является ли это ошибкой, что MASM собирает [0xCCCCCCCC] для немедленного использования вместо эффективного адреса. Выполняет ли это то же самое, если это операнд для других инструкций? например это ошибка с LEA?

+1

Спасибо за ответ. Такое же поведение проявляется в любой инструкции, которая может читать/записывать в ближайшее место памяти (cmp, inc, push и т. Д.). Для LEA, пытающегося собрать что-то вроде lea ecx, [0xCCCCCCCC] - ошибка (неправильный тип операнда). Но включение префикса сегмента приведет к правильному поведению. Трудно сказать, было ли это ошибкой или предназначено, но я склоняюсь к тому, что это ошибка. –