Форум программистов «Весельчак У»
  *
Добро пожаловать, Гость. Пожалуйста, войдите или зарегистрируйтесь.
Вам не пришло письмо с кодом активации?

  • Рекомендуем проверить настройки временной зоны в вашем профиле (страница "Внешний вид форума", пункт "Часовой пояс:").
  • У нас больше нет рассылок. Если вам приходят письма от наших бывших рассылок mail.ru и subscribe.ru, то знайте, что это не мы рассылаем.
   Начало  
Наши сайты
Помощь Поиск Календарь Почта Войти Регистрация  
 
Страниц: [1]   Вниз
  Печать  
Автор Тема: Прыжки)  (Прочитано 10552 раз)
0 Пользователей и 1 Гость смотрят эту тему.
Aether
Специалист

ru
Offline Offline
Пол: Мужской

« : 03-07-2014 15:02 » 

Доброго дня)

В эпоху ДОСа и сегментированной памяти было вроде так:
JMP SHORT - перемещение на малое расстояние, аргумент 1 байт (смещение целое со знаком 8 бит),
JMP NEAR - перемещение малость далее, аргумент 2 байта (смещение целое без знака 16бит),
JMP FAR - перемещение в любую точку памяти, аргумент 4 байта (сегмент:смещение оба 16 бит целое без знака)
В защищённом режиме в сегментный регистр грузится не сегмент, а селектор, но суть дела не меняется - это также 16бит(?) значение, а смещение уже 32бита.

Теперь к сути вопроса:
Во-первых, правильно ли я понимаю:
JMP SHORT - остаётся также с 8бит аргументом или уже 16?
Появляется ли SHORT2 )) с аргументом 16бит.
JMP NEAR - так полагаю переход с аргументом в 32бита
JMP FAR - аргумент селектор (16бит):смещение(32бит)

Во-вторых, когда загружается файл в формате PE, загрузчик "осматривает" его EXPORTS список и загружает необходимые  DLL в память, как он это делает, то есть: загружает их как обычные программы, и сбрасывает в основную программу ссылки на них в формате селектор:смещение начала нужной функции?

В третьих, часто вижу в описании функции в MSDN такой тип данных, как POINTER, вроде, он представляет из себя 32бит число, значит полноценным FAR быть не может, и не может ссылаться на данные в другом селекторе по крайней мере напрямую?

Эх, вопросы, возможно базовые, но уж лучше спросить, и знать, чем молча остаться "умным"))
Записан
darkelf
Молодой специалист

no
Offline Offline

« Ответ #1 : 04-07-2014 06:18 » new

Aether, практически во всех современных операционных системах не используется сегментированная организация памяти, точнее используется, но в очень и очень урезанном формате. Если не рассматривать организацию локальных данных потока, используются 4-ре фиксированных дескриптора - дескриптор кода ядра, дескриптор данных ядра, дескриптор кода прикладной задачи и дескриптор данных прикладной задачи. Все они имеют базовый адрес 0, а предел - 4G т.е. адресуют всё виртуальное адресное пространство памяти. Организация защиты строится на базе страничной адресации процессора.  Такой подход называется "плоской моделью памяти".

Теперь по сути вопроса:
в 16-тибитном реальном режиме есть:
JMP rel8 - с восьмибитным смещением (SHORT)
JMP rel16 - с 16-ти битным смещением (NEAR)
JMP ptr16:16 - межсегментный переход (FAR)

в 32-х битном защищённом режиме есть:
JMP rel8 - с восьмибитным смещением (SHORT)
JMP rel32 - с 32-ти битным смещением (NEAR)
JMP ptr16:32 - межсегментный переход (FAR)

в принципе JMP rel32 в реальном режиме можно закодировать при помощи префиксов 66h/67h, но надо проверять, как их обработает процессор, в принципе при помощи этих-же префиксов можно закодировать JMP rel16 в 32-хбитном защищённом режиме.

Во вторых:
Загрузчик, а точнее часть ОС отвечающая за загрузку и запуск прикладных программ создаёт отображения памяти, в которые загружает необходимые секции из разделяемой библиотеки. При наличии уже загруженных экземпляров библиотек за счёт использования страничной адресации оно может создать разделяемые страницы - т.е. копия, например, кода разделяемых библиотек может не создаваться, а будут использоваться страницы кода раннее уже загруженные.

В третьих - при использовании плоской модели памяти прикладные программы оперируют только смещениями в своём адресном пространстве, при этом сегментные регистры у них считаются фиксированными. Если кто и оперирует сегментными регистрами - так это ОС.

Эти вопросы, имхо, больше относятся к теории построения операционных систем, а не напрямую к ассемблеру.
Записан
Aether
Специалист

ru
Offline Offline
Пол: Мужской

« Ответ #2 : 04-07-2014 10:16 » 

Все они имеют базовый адрес 0, а предел - 4G т.е. адресуют всё виртуальное адресное пространство памяти. ся фиксированными. Если кто и оперирует сегментными регистрами - так это ОС.
Хорошо, у нас есть, например, 512Мб физической памяти, значит адресоваться оно может от 0...536870911 линейно, первая грузится ОС из реального режима, создаёт GDT, и описывает свои дескрипторы кода и данных. Предположим, что первый будет иметь базу 0, лимит 4G, фактически займёт 40Мб пространства, тогда у второго база уже 0 быть не может (база, вроде, считается от физического "0"), тогда база второго будет соответствовать концу первого.
Правильно ли я понимаю: мы считаем участок flat от 0 до лимита, но физически это фрагмент от 0+база, до 0+база+лимит? Любая программа, включая загрузчик, запрашивает себе дескрипторы у ОС. Когда грузится DLL, то она тоже получает свои сегменты, в которых и выполняется...
С чего, собственно, вопрос возник: такое чувство, что, когда пишешь, например:
; NASM
call [ShowMessageA]
то мы совершаем:
call NEAR [32бит смещение на некую функцию внутри кода нашей программы]
а там:
call FAR [16:32 поле полного адреса, которое формируется с нулями, а заполняется на стадии загрузки DLL]
Сущность никак не просеку, может посоветуете почитать толковый труд.

Сорри, другого раздела не нашёл, однако, пользователи ассемблера, обычно, ближе у сути реальных процессов) Спасибо.
Записан
RXL
Технический
Администратор

ru
Offline Offline
Пол: Мужской

WWW
« Ответ #3 : 04-07-2014 11:26 » 

Принципиально различается только JMP FAR. В PM сегментный регистр - это индекс в GDT/LDT и указание запрашиваемого уровня доступа. Стоит почитать доку Интела.
Записан

... мы преодолеваем эту трудность без синтеза распределенных прототипов. (с) Жуков М.С.
darkelf
Молодой специалист

no
Offline Offline

« Ответ #4 : 04-07-2014 11:42 » 

Все они имеют базовый адрес 0, а предел - 4G т.е. адресуют всё виртуальное адресное пространство памяти. ся фиксированными. Если кто и оперирует сегментными регистрами - так это ОС.
Хорошо, у нас есть, например, 512Мб физической памяти, значит адресоваться оно может от 0...536870911 линейно, первая грузится ОС из реального режима, создаёт GDT, и описывает свои дескрипторы кода и данных.
Нет, адресоваться в виртуальной памяти будет от 0 до 4Гбайт, а эта виртуальная память уже будет отображаться на физическую. В принципе в этом и есть суть виртуальной памяти - реально памяти может быть много меньше, но создаётся иллюзия, что ей столько, сколько надо. Например это делается при помощи свопинга (при недостаче страниц памяти занятые страницы записываются на диск и объявляются свободными и при необходимости данных, которые раньше были в них необходимо записать их текущее содержимое на диск и опять прочитать, что там было до того).

Предположим, что первый будет иметь базу 0, лимит 4G, фактически займёт 40Мб пространства, тогда у второго база уже 0 быть не может (база, вроде, считается от физического "0"), тогда база второго будет соответствовать концу первого.
Нет у всех база 0, лимит 4Гбайт. мало того, дескрипторы сегментов для всех прикладных задач общие. Т.е. не будет для каждой задачи своих дескрипторов, все они будут общие, а разделение, что этот участок памяти относится к одной задаче, этот - к другой, а этот  - вообще к ОС уже делается на основании страничной адресации.

Правильно ли я понимаю: мы считаем участок flat от 0 до лимита, но физически это фрагмент от 0+база, до 0+база+лимит? Любая программа, включая загрузчик, запрашивает себе дескрипторы у ОС. Когда грузится DLL, то она тоже получает свои сегменты, в которых и выполняется...
Думаю, что не запрашивает, как я сказал - дескрипторы сегментов используются очень ограниченно.

С чего, собственно, вопрос возник: такое чувство, что, когда пишешь, например:
; NASM
call [ShowMessageA]
то мы совершаем:
call NEAR [32бит смещение на некую функцию внутри кода нашей программы]
а там:
call FAR [16:32 поле полного адреса, которое формируется с нулями, а заполняется на стадии загрузки DLL]
Возможно даже в "а там:" не call FAR [16:32], а int 2fh (если не путаю), а то и SYSCALL - поход в ОС.
да и там, где call NEAR [32], зависит от типа компоновки, при статической - там будет обычный адрес библиотечной функции, а при динамической - действительно что-то типа 0, и запись в спец-таблице, что этот 0 надо заменить на адрес такой-то функции, которое потом загрузчиком динамических библиотек будет заменено на адрес реальной функции, когда он подгрузит библиотеку и выяснит, по какому адресу в этой библиотеке находится необходимая функция.

Сущность никак не просеку, может посоветуете почитать толковый труд.
Сорри, другого раздела не нашёл, однако, пользователи ассемблера, обычно, ближе у сути реальных процессов) Спасибо.
в принципе - любую книгу по теории построения операционных систем - просто, чтобы представлять как вообще это всё обычно строится, а потом уже переходить к частностям. Можно почитать Танненбаума про общую теорию, Роберта Лава про Linux, Вахалию про построение ОС Unix и Соломона и Руссиновича про Windows.
« Последнее редактирование: 04-07-2014 11:44 от darkelf » Записан
Aether
Специалист

ru
Offline Offline
Пол: Мужской

« Ответ #5 : 05-07-2014 06:10 » 

Почитал Таненбаума "Современные операционные системы" 2-ое издание 2002г. Получается мы оба правы) Сегментную адрессацию можно организовать на сегментных дескрипторах, но Windows строит её на управляющих регистрах процессора, каталогах страниц... Отсюда вывод для меня: если я строю приложение, как Win32, то всё, что вижу - это свою 32бит линейную адресную зону, отсюда и все указатели 32бит. Переходы между процессами, библиотеками... осуществляет ОС, либо включая их в моё адресное пространство, либо через "себя" (SYSCALL) - но это на уровне прикладных программ не так важно.
Записан
Страниц: [1]   Вверх
  Печать  
 

Powered by SMF 1.1.21 | SMF © 2015, Simple Machines