Суббота
18.05.2024
09:01
Форма входа
Категории раздела
Макроинструкции [3]
Управление данными [4]
Макросы [0]
ПК и железо [0]
Осиписание. :) [1]
Разное [4]
Поиск
Друзья сайта
  • Официальный блог
  • Сообщество uCoz
  • FAQ по системе
  • Инструкции для uCoz
  • Статистика

    Онлайн всего: 1
    Гостей: 1
    Пользователей: 0

    OPEN SOURCE PROJECT

    Каталог статей

    Главная » Статьи » Разное

    Адресация памяти.
    Каждая ячейка памяти имеет свой адрес - 32 битное смещение (в байтах) от начала сегмента. Сегмент определяется сегментным регистром (cs, ds, ss, es, fs, gs) и может указываться в командах при работе с памятью. Некоторые команды не поддерживают префикс замены сегмента.
    Рассмотрим пример на основе команды mov.

    Пример:

    mov eax,fs:[0] - поместить в регистр eax число из сегмента, селектор которого находится в регистре fs, со смещением от начала сегмента - 0.

    Т.к eax - 32 битный регистр, то из памяти считывается 32 бита.
    Нельзя использовать более одного операнда "память" в команде.

    -------------------------------

    Смещение указывается в квадратных скобках, и может быть следующего формата: [Base+Index*{1,2,4,8}+число.] где Base - любой 32 битный регистр общего назначения, а Index - любой 32 битный регистр общего назначения кроме esp. Каждое из слагаемых может отсутствовать.

    Пример:

    mov ecx,dword ptr [eax+ecx*4-10] ;поместить в ecx двойное слово по адресу eax+ecx*4-10
    mov cx,word ptr [edx+43]
    mov byte ptr [ecx+edx],al ;записать в память по адресу ecx+edx значение регистра al

    В документации смещение в памяти часто называют указателем (pointer) или адресом.
    Разные команды работают с разными сегментами памяти по умолчанию.
    Windows устроен так, что вы можете использовать все сегменты как один и тот же (кроме FS, используемый для SEH). Пока не указывайте префиксы замены сегмента, при адресации ячейки памяти обращайте внимание только на смещение.

    -------------------------------

    Обозначение памяти в программе.

    Для обозначения строки (массива) байт, слов или двойных слов используются операторы db, dw и dd соответственно.Текстовые строки заключаются в двойные или одинарные кавычки.

    Пример:

    AnyLabel db 10 ;Определить 1 байт, равный 10

    MsgString db ′Текстовая строка′,0 ;определить текстовую строку, с последним байтом равным нолю (ASCIIZ формат. Часто используется функциями Windows. Ноль обозначает конец строки. В документации упоминается как "null-terminated string")

    SomeDwords dd 18,30h,′axyz′ ;определить массив двойных слов.

    TenX db 10 dup (′X′),′YZ′ ;определить 10 байт, равных символу "X", при помощи оператора dup и два последних байта "YZ"

    UnDefWord dw ? ;определить слово, изначальное значение которого нам неважно.

    -------------------------------

    Типы данных word и dword хранятся в памяти в перевернутом виде. При считывании двойного слова из строки байт MsgString получим значение "скеТ"
    Для обозначения меток в программе используют следующую форму записи: AnyLabel:
    Ими обычно обозначаются участки программы, на которые передается управление при помощи команд перехода. Метки и названия переменных не могут начинаться с цифры, состоят из любой комбинации английских букв и символов "_", "$", "@", "?". Последние три символа лучше не использовать.

    Для получения адреса в памяти метки используется оператор offset.
    Чтобы узнать размер массива данных используйте оператор size
    Для переопределения типа данных используется оператор ptr.
    Оператор $ используется для получения смещения текущего байта.

    Пример:

    mov ecx,offset SomeDwords+4 ;поместить в регистр ecx адрес в памяти строки SomeDwords +4.
    mov cl,size TenX ;поместить в cl размер массива TenX (12).
    mov edx,dword ptr [MsgString] ;поместить в edx двойное слово (4 байта - 4 символа) из строки MsgString.
    Т.к edx - 32 битный регистр, а строка MsgString определена как строка байт, то нужно использовать оператор переопределения типа.

    Символы - это 8 битные числа. Для определения числового значения символа можно использовать таблицу символов из Windows.

    -------------------------------

    Сегменты в программе.

    Данные указываются в сегменте данных, обозначаемым как .data
    Соответсвтенно код (команды процессора) надо писать в сегменте кода, т.е после .code
    Каждая страница памяти (в Windows для пользовательских программ как правило ее размер 4 кб) может иметь свои атрибуты. Попытка записи в сегмент кода приведет к ошибке программы.

    -------------------------------

    Стэк (Stack)

    Стэк - это область оперативной памяти, начало которой находится по адресу ss:esp
    Значение регистра esp называется адресом вершины стэка.
    Для помещения числа в стэк используется команда push, для извлечения - pop.
    При помещении 32 битного числа в стэк (push), происходит следующее:

    1)уменьшение значения регистра esp на 4 ( размер dword′а).
    2)запись числа по адресу ss:esp
    Таким образом стэк "растет" вниз, от больших адресов памяти к меньшим.

    Пример:

    push eax ;поместить значение регистра eax в стэк
    В стэк желательно помещать только 32 битные значения.
    pop ecx ;извлечь из стэка число в регистр ecx
    Команда pop ecx работает следующим образом:
    mov ecx,dword ptr ss:[esp]
    add esp,4

    После выполнения этих команд (или команды pop ecx) значение ячейки памяти по адресу [esp-4] не изменится, но считается недействительным т.к. следующая команда push, другие команды работы со стэком, или возникшее прерывание перезапишут это значение, а также другие, с еще меньшим смещением.

    -------------------------------

    Строчкой .model flat,stdcall задается модель памяти (flat для программ под Windows), и алгоритм работы макроса вызова процедур (stdcall для функций Windows).

    -------------------------------


    .386 ;используем команды 386 процессора
    ;все последующие процессоры их также поддерживают.
    .model flat,stdcall ;программа под Windows (см выше).
    MAX_COMPUTERNAME_LENGTH equ 15
    UNLEN equ 256
    extrn GetComputerNameA:proc ;используемые внешние функции
    extrn GetUserNameA:proc
    extrn MessageBoxA:proc
    extrn ExitProcess:proc
    .data ;сегмент данных
    MTitle db ′Computer / User name′,0 ;ASCIIZ строка - заголовок сообщения
    CompNameSize dd MAX_COMPUTERNAME_LENGTH+1
    UserNameSize dd UNLEN+1
    MBuffer db MAX_COMPUTERNAME_LENGTH+UNLEN+1+3 dup (?) ;неопределенный массив.
    ;В нем будет формироваться строка с именем компьютера и пользователя
    .code ;сегмент кода
    start: ;метка начала программы
    ;функция GetComputerNameA возвращает имя компьютера по адресу из первого параметра,
    ;и количество символов в имени по адресу из второго параметра.
    call GetComputerNameA,offset MBuffer,offset CompNameSize
    mov eax,offset MBuffer ;eax= адресу массива MBuffer
    ;(в котором уже находится имя компьютера)
    add eax,dword ptr [CompNameSize] ;добавим к eax количество символов в
    ;имени компьютера. Получим адрес конца текстовай строки.
    mov dword ptr [eax],′X / ′ ;добавим к концу строки 4 символа (X для теста).
    add eax,3 ;прибавим к смещению конца строки 3
    ;(по адресу eax будет символ X)
    call GetUserNameA,eax,offset UserNameSize ;передадим в качестве адреса
    ;для возврата имени пользователя конец строки, по которому
    ;находится символ X, он будет перезаписан)
    call MessageBoxA,0,offset MBuffer,offset MTitle,0 ;отобразим строку,
    ;состоящую из имени компьютера, разделителя и имени пользователя.
    call ExitProcess,0 ;вызовем функцию завершения программы.
    ;если этого не сделать, выполнение пойдет дальше
    ;и Windows выведет сообщение об ошибке.
    ends ;конец сегментов (можно и не писать)
    end start ;конец программы, точка входа

    Категория: Разное | Добавил: fasm (19.07.2008)
    Просмотров: 1264 | Рейтинг: 0.0/0
    Всего комментариев: 0
    Добавлять комментарии могут только зарегистрированные пользователи.
    [ Регистрация | Вход ]