Сегментная модель памяти
1. Когда испольняемый файл грузится в память, у него есть свое виртуальное адресное пространство. Это можно понимать как то, что больше некоторого набора сегментов это приложение под себя забрать не сможет?
2. Обращаться к байтам используя прямую адресацию мы можем как seg:off. Я могу к одному и тому же байту обратится двумя разными способами: например seg_1:offset_1 и seg_2:offset_2
3. После загрузки в память жтого .EXE я могу получить доступ к любыму байту из 64кбайт сегмента данных и могу ли я руками инициализировать новый сегмент под что-нибудь?
Сегментация неплохо описана в Юров "Assembler".
Почитал главу про сегментированную модель, вот такая строчка там есть: Каждая программа может состоять из любого числа сегментов, но непосредственный доступ она имеет только к трем основным... Собсственно, а нафига нужны еще сегменты, хотелось бы посмотреть на примере, а то совершенно не понятен смымл этого
Насчет примера, честно говоря, мне слабо. Мне даже 64kB исчерпать не удавалось :)
P.S. Совсем забыл про 64-битные системы упомянуть.
У меня осталось еще несколько вопросов. Пусть есть экзешник с моделью small.
1.После запуска спекрва загружается сегмент кода а потом данные или они как-то параллелньо грузятся?
2.
Код:
mov ax,@data
mov ds,ax
mov ds,ax
По 2-му вопросу.
Код:
mov ax,@data
mov ds,ax
mov ds,ax
PSP мы не теряем, мы к ней можем обратиться, вычтя те-же 100h от адреса первого сегмента, либо (мне кажется удобней) - просто сохранить ее сегментный адрес , например, выпихнув в стек DS в самом начале кода. После этого лучше все-таки DS перенастроить на сегмент данных.
PS. В развитие темы я тут написал один примерчик. Там то, о чем говорили, и еще про то, как можно вывести строку, определенную в коде, а не в данных. Использую для разнообразия альтернативный способ перенастройки адреса. Чтобы русский отображался надо исходник в досовской кодировке писать. Код на Masm, думаю, что в tasm тоже годится.
Код:
.model small
;.stack 128 ;стек (минимум 128 байт надо), но эта программа будет работать и так
.data
Msg db 'Привет, Мир!!! === $'
.code
Entry:
;Сегментную составляющую адреса Msg -- в ds:
mov ax, seg Msg
mov ds, ax
;смещение относительно начала сегмента, где Msg определено (сег. данных):
mov dx, offset Msg; либо lea dx, Msg
;Теперь в паре ds:dx адрес Msg и можно вывести на печать:
mov ah, 09h
int 21h
;Аналогично, для данных в коде:
jmp dat_end ;прыжок через данные, оред. в коде
msg2 db 'Hi$' ;данные в кодовом сегменте
dat_end:
mov ax, seg msg2
mov ds, ax
mov dx, offset msg2; либо lea dx, msg2
mov ah, 09h
int 21h
mov ah, 4ch
int 21h
end Entry
;.stack 128 ;стек (минимум 128 байт надо), но эта программа будет работать и так
.data
Msg db 'Привет, Мир!!! === $'
.code
Entry:
;Сегментную составляющую адреса Msg -- в ds:
mov ax, seg Msg
mov ds, ax
;смещение относительно начала сегмента, где Msg определено (сег. данных):
mov dx, offset Msg; либо lea dx, Msg
;Теперь в паре ds:dx адрес Msg и можно вывести на печать:
mov ah, 09h
int 21h
;Аналогично, для данных в коде:
jmp dat_end ;прыжок через данные, оред. в коде
msg2 db 'Hi$' ;данные в кодовом сегменте
dat_end:
mov ax, seg msg2
mov ds, ax
mov dx, offset msg2; либо lea dx, msg2
mov ah, 09h
int 21h
mov ah, 4ch
int 21h
end Entry
Цитата: sadovoya
Вообще-то смещением принято считать добавку к адресу начала сегмента. Того сегмента, где описано искомое. Непонятно как вы хотите реализовать вариант "seg_1:offset_1 и seg_2:offset_2" , кроме как при seg_1=seg_2 и offset_1=offset_2 ?
Юров пишет, что реальный режим допускает перекрывание сегментов, разве это не означает, что мы (гипотетически) можем к одному байту обращаться двумя вариантами "seg_1:offset_1 и seg_2:offset_2"?
PS. Чаще всего, говоря о смещении имеется ввиду смещение внутри сегмента, где адресуемое находится. Но может и вольно где-то трактоваться. Надо в контексте смотреть, обычно можно понять о чем речь.
А кем назначается физический адрес? Допустим мы инициализируем байт, он сперва получит физический адрес или логический, где эти адреса находятся (они же должны где-то находится чтобы получать доступ к байтам по его адресу)?
не смог удержаться, чтобы не написать, т.к. заметил несколько откровенных заблуждений относительно реального положения дел.
1. Не нужно объединять воедино виртуальную память и сегментацию памяти в реальном режиме. Это совершенно разные вещи. Вы вообще уверены, что вам нужно знать, как писать программы под DOS? Может, лучше сразу будете учиться программированию под современные ОС, например, Win32/64? Именно в них используется виртуальная память. А модель памяти называется flat.
2. Можно, но альтернативный адрес нужно формировать вручную, т.к. компиляторы не предполагают наличие пересекающихся сегментов в исполняемом образе - сегменты (группы сегментов) в образе размещаются последовательно с выравниванием на 16 байт.
3. Можно определить сегменты (их нужно разместить в конце образа), данные которых не будут сохраняться в исполняемом файле, но память под них будет автоматически резервироваться при загрузке. Это называется heap. Также резервируется пространство и под стек. Это возможно благодаря спец. полю MINMEMSIZE исполняемого файла. Картина примерно такая:
1) образ, загруженный из файла;
2) резерв памяти, который должен обязательно присутствовать;
3) резерв памяти, которого может и не быть. Данное резервирование возможно благодаря полю MAXMEMSIZE исполняемого файла (обычно устанавливается спец. значение, которое говорит DOS зарезервировать всю память до конца непрерывного блока, выделенного программе - часто это вообще вся доступная базовая память выше базового адреса загрузки). Если установить значение MAXMEMSIZE, равным MINMEMSIZE, то вся не нужная программе изначально память может быть оставлена системе - с этой памятью можно работать при помощи системных функций распределения памяти.
sadovoya, PSP формирует не ассемблер, и не компоновщик, а операционная система. В исполняемом файле нет информации о PSP.
Вспомните assume, привязку сегментов к сегментным регистрам. Оператор seg и т.д.
Цитата: brudor
А кем назначается физический адрес? Допустим мы инициализируем байт, он сперва получит физический адрес или логический, где эти адреса находятся (они же должны где-то находится чтобы получать доступ к байтам по его адресу)?
Перед тем как твоя программа получит управление, DOS настроит в ней все сегментные адреса (@code, @data и т.п.) на основе таблицы релокации, которая хранится в исполняемом файле. Т.е. смещения не изменятся, но благодаря подстройке сегментных адресов у тебя получатся правильные физические адреса, соответствующие реальному местоположению программы в памяти.
Phantom-84, спасибо за замечание по PSP.
Цитата: Phantom-84
2. Можно, но альтернативный адрес нужно формировать вручную, т.к. компиляторы не предполагают наличие пересекающихся сегментов в исполняемом образе - сегменты (группы сегментов) в образе размещаются последовательно с выравниванием на 16 байт.
Можете привести пример кода, где происходит формирование алдьтернативного адреса. Интересно, в каком регистре будет находится адрес сегмента и смещение.
Код:
mov dx, offset msg+100h
sadovoya, тогда я навеное не правильно понял, что значит альтернативный адрес. Я думал действовать так: У нас есть адрес байта xxxx:yyyy. Ему соответствует физический (по той формуле, что Вы описывали-- xxxx*10_{16}+yyyy). Далее я думал запихать (например, в es) zzzz и найти смещение tttt, такое что zzzz:tttt=xxxx:yyyy.
Код:
;==========================================================
; Использование альтернативных адресов
;==========================================================
;Кодировка файла DOS Rus (для русского сообщения)
;Компилировать как exe для Dos
.model small
;стек этой программе не нужен
.data
org 16 ; нужно, что-бы в минус не залезть при вычитании (ясно будет далее)
Msg db 'Привет, Мир!!!$'
.code
Entry:
;настраиваем на данные ds:
mov ax, @data
mov ds, ax
;смещение помещаем в dx:
mov dx, offset Msg
;Функция 09h прерывания 21h
;ждет от нас адрес в паре регистров DS и DX.
;У нас в DS сейчас адрес сегмента данных (@data)
;а в DX - смещение строки в данных.
;Т.е. логический адрес @data:offset Msg.
;Адрес наш верен, выводим строку:
mov ah, 09h
int 21h
;Увеличим DS на 1 (десятич.)
mov ax, @data+1
mov ds, ax
;это изменило физический адреc на 16 (десятич.)
;компенсируем это в смещении:
mov dx, offset Msg - 16; (здесь от отриц. смещ. нас страхует org 16 (см. выше))
;теперь наш альтернативный адрес @data+1:offset Msg - 16
;(физический будет тот-же)
;Проверяем:
mov ah, 09h
int 21h
mov ah, 4ch
int 21h
end Entry
; Использование альтернативных адресов
;==========================================================
;Кодировка файла DOS Rus (для русского сообщения)
;Компилировать как exe для Dos
.model small
;стек этой программе не нужен
.data
org 16 ; нужно, что-бы в минус не залезть при вычитании (ясно будет далее)
Msg db 'Привет, Мир!!!$'
.code
Entry:
;настраиваем на данные ds:
mov ax, @data
mov ds, ax
;смещение помещаем в dx:
mov dx, offset Msg
;Функция 09h прерывания 21h
;ждет от нас адрес в паре регистров DS и DX.
;У нас в DS сейчас адрес сегмента данных (@data)
;а в DX - смещение строки в данных.
;Т.е. логический адрес @data:offset Msg.
;Адрес наш верен, выводим строку:
mov ah, 09h
int 21h
;Увеличим DS на 1 (десятич.)
mov ax, @data+1
mov ds, ax
;это изменило физический адреc на 16 (десятич.)
;компенсируем это в смещении:
mov dx, offset Msg - 16; (здесь от отриц. смещ. нас страхует org 16 (см. выше))
;теперь наш альтернативный адрес @data+1:offset Msg - 16
;(физический будет тот-же)
;Проверяем:
mov ah, 09h
int 21h
mov ah, 4ch
int 21h
end Entry
Код:
;
mov ax,seg data
dec ax
mov ds,ax
mov dx,offset message
add dx,16
mov ax,seg data
dec ax
mov ds,ax
mov dx,offset message
add dx,16
Сегментация, оверлеи: не, не слышали =^.^=