* C for Dummies * Aleph * 2000-09-03 * 010 *
-----[00]----------[Quote of Day]-----------------------------------------
An expert is one who knows more and more about less and less.
Nicholas Murray Butler
-----[01]----------[Hot News]---------------------------------------------
Очень старая но все еще полезная книга Брэдли об ассемблере IBM PC/XT.
http://win32asm.newmail.ru/bradley.arj (367,943)
или
http://members.xoom.com/c4dummies/files/bradley.zip (287,210)
Также очень старая, но все еще полезная книга Журдена
"Справочник программиста на персональном компьютере фирмы IBM"
http://members.xoom.com/c4dummies/files/jourdan.zip (353,678)
Описание IDE (Интегрированной Среды Разработки) TC 2.0
http://members.xoom.com/c4dummies/files/tc20dox.zip (347,446)
Справочное руководство по библиотечным функциям TC 2.0
http://members.xoom.com/c4dummies/files/tc20libref.zip ( 91,171)
Описание Turbo Debugger 2.0 (поставляется отдельно). Мы будем пользоваться
более новой версией, но это описание все же стоит прочесть.
http://members.xoom.com/c4dummies/files/td20dox.zip (235,000)
-----[02]----------[Blah-Blah-Blah]---------------------------------------
Не мог пройти мимо такой заметки:
> Служба Рассылок Городского Кота / CityCat's E-mail Service
> -*--------------------------------------------------------
> Subject: Веселости из FidoNet
> Date: Sat, 22 Jul 2000 00:13:15 +0300 (MSK)
> From: CityCat <namma@citycat.ru>
> To: "funny.fido" <null@citycat.ru>
> ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
> * Area : RU.CRYPT
> * From : Andrew Mezhutkov, 2:5080/38.10
> * To : All
> * Subj : это есть маленький шутка
> ---------------------------------------
>
> Мое почтение, All.
>
> к вопросу об использовании "живых шифраторов"
>
> "СHАRGОGGАGОGGМАNСHАUGGАGОGGСHАUВUNАGUNGАМАUGG"
>
> Это название массачусетского озера переводится с одного из индейских
> языков так: "Ты ловишь рыбу на своей стороне, а я - на своей, и никто
> не рыбачит посредине". Алькальд местечка Вебстер уверяет, что, несмотря
> на то, что название не умещается на карте и немного сложно в
> произнесении, никому не приходит в голову его менять. "Это наша марка,
> - говорит он. - Это то, что отличает нашу местность от других. Это имя
> возникло в 17 веке, но впервые появилось в официальных документах в
> 1795 году, как результат разделения территорий между поселенцами и
> индейцами." Очевидно, что все те, кто обитает в городке Вебстер, - 16
> 000 жителей - гордятся навыками безошибочного произнесения этого
> названия из 45 букв. "Весь секрет в том, чтобы начать заучивать его с
> детства, еще в школе", - объяснил мэр корреспонденту AFP.
>
> Andrew.
> -*---------------------------------------------------------------------
> Eugene Dolgodvorov.
> Home Page: http://www.citycat.ru/~deb/
> E-mail: deb@citycat.ru
> Сообщение на пейджер http://www.citycat.ru/~deb/pager.html
-----[03]----------[Topic]------------------------------------------------
Memory Models. Pointers.
-----[04]----------[Body]-------------------------------------------------
Memory Models
-------------
Как мы уже говорили, процессор 8086 использует для адресации четыре
сегментных регистра:
> +---------------------------+
> | CS |
> +---------------------------+
> | DS |
> +---------------------------+ Сегментные регистры
> | ES |
> +---------------------------+
> | SS |
> +---------------------------+
Их мнемонические названия напрямую связаны с их использованием:
CS - адресует сегмент кода
DS - адресует сегмент данных
SS - адресует сегмент стека
ES - адресует дополнительный сегмент (данных)
Первый вопрос, который должен у Вас возникнуть, а чем, собственно,
отличаются двоичные данные размещенные по разным адресам памяти, что
следует давать им разные названия и придумывать разные сегменты ?
Физически - ничем !
А вот логически - да, различаются.
Современная парадигма программирования всячески избегает
самомодифицирующегося кода ( Agrrr..rh ! Bad Style ! ), столь
излюбленного авторами первых программ (и компьютеров) и нынешними
Vx-мейкерами (авторами вирусов). Автоинкрементные регистры, кажется,
навсегда ушли в прошлое. Код не должен изменяться. Все, что помещается в
сегмент кода помечается атрибутом "Только для чтения". Это становится
особенно важным в многозадачных системах с разделяемым кодом, когда тот же
самый код может быть вызван из различных процессов или различных нитей того
же самого процесса.
Хорошо Вам знакомый пример многозадачной системы - Windows. Системный код,
помещенный в динамические библиотеки (DLL), такие как GDI, Kernel, User
итд, может одновременно использоваться несколькими программами и утилиты,
изменяющие этот код (например, отладчики) прибегают к специальным
ухищрениям, (копирование при записи) чтобы сделать эти изменения
невидимыми для всех остальных процессов.
С данными ситуация прямо противоположная - предполагается, что при работе
они могут изменяться (причем не обязательно процессом-собственником).
Стек - отдельный разговор. С одной стороны это тоже данные, которые могут
изменяться, с другой, стек имеет свою собственную специфику.
Во первых, стек отображается моделью LIFO (Last In First Out) - Последний
Пришел - Первый Ушел, часто также называемой магазинной структурой.
Если Вы знакомы с устройством автоматного рожка, то это название Вам все
объяснит :-)
Можете также вообразить себе Скупого Рыцаря, складывающего золотые в очень
длинный и узкий чулок (капрон еще не был изобретен). Чулок настолько узок,
что за один раз в него пролезает ровно одна монета. Если теперь попытаться
достать монету из чулка, то вытащить можно только одну монету, положенную
последней. Если же Скупой Рыцарь вдруг захочет полюбоваться испанским
дублоном, сунутым в чулок в прошлом месяце, то ему сначала придется
достать все монеты, положенные после этого.
Так вот, сегмент стека не только обеспечивает место для такого "чулка", но
еще и "растет" сверху вниз.
Можете представить себе мир с отрицательной гравитацией, где упавший
золотой "падает" на потолок. Сегмент стека и будет имитацией этого мира.
+--------------------+
| 1st value |
+--------------------+
| 2nd value |
+--------------------+
| 3rd value |
+--------------------+
| 4th value |
+--------------------+
| |
| Grow | <-- Top of Stack
| |
Как Вы уже поняли, "верхушка" стека находится внизу и каждый новый
"золотой" увеличивает стек по направлению вниз.
Такая особенность использования сегмента стека позволяет легко совместить
его с сегментом данных.
В самом деле, если назначить сегменту данных и сегменту стека один и тот
же адрес, то данные и стек будут заполнять этот сегмент с разных сторон
(сверху и снизу), подобно сталактитам и сталагмитам, растущим в одной
пещере.
Обратимся к документации по Turbo C
> Сегментация памяти
> ------------------
>
> Микропроцессор 8086 имеет сегментированную архитектуру памяти. Он
> обеспечивает общее адресное пространство величиной 1 Мб, однако может
> прямо адресовать только 64К. Логическую единицу памяти размером 64К
> называют сегментом, отсюда и название "сегментированная архитектура
> памяти".
>
> Теперь возникают вопросы: сколько различных сегментов существует, где
> они располагаются и как 8086 понимает, где они расположены?
>
> - 8086 работает с 4 различными сегментами: кода, данных, стека и
> дополнительных данных. Кодовый сегмент содержит машинную программу;
> сегмент данных - данные; стековый сегмент - стек; дополнительный
> сегмент обычно используют для дополнительных данных;
>
> - 8086 имеет 4 16-битных сегментных регистра, называемых CS, DS, SS и
> ES; они указывают на сегменты кода, данных, стека и дополнительных
> данных соответственно;
>
> - сегмент может быть расположен в любом месте памяти. По причине,
> которая будет рассмотрена далее, сегмент всегда начинается с адреса,
> кратного 16 (в десятичной системе).
>
>
> Вычисление адреса
> -----------------
>
> Итак, каким же образом 8086 использует эти сегментные регистры для
> вычисления адреса ? Полный адрес 8086 получает из 2-х 16-битных
> величин: адреса сегмента и смещения. Предположим, что адрес сегмента
> данных - величина в DS регистре - 2F84 (HEX-код), и вы хотите вычислить
> реальный адрес некоторых данных, которые имеют смещение 0532 (HEX-код)
> от начала сегмента данных. Как это делается ?
>
> Вычисление адреса происходит следующим образом: величина сегментного
> регистра сдвигается на 4 бита (1 разряд HEX-кода) влево и затем
> складывается со смещением. Полученная в результате 20-битная величина
> есть реальный адрес данных, что иллюстрирует следующая запись:
>
> DS регистр (сдвинутый) 0010 1111 1000 0100 0000 = 2F840
> смещение 0000 0101 0011 0010 = 00532
> адрес 0010 1111 1101 0111 0010 = 2FD72
>
> Начальный адрес сегмента - всегда 20-битное число, однако сегментный
> регистр содержит только 16 бит. Т.о., младшие 4 бита всегда
> предполагаются равными нулю. Это означает, как мы уже отмечали, что
> сегменты могут начинаться только с адреса, кратного 16-и, т.е. с
> адреса, в котором младшие 4 бита (младшая HEX-цифра) нулевые.
>
> T.о., если DS-регистр содержит величину 2F84, то сегмент данных реально
> начинается с адреса 2F840. Как отмечалось, отрезок памяти из 16 байт
> называется параграфом, т.е. этот сегмент всегда начинается на границе
> параграфа. Стандартно адрес представляется в форме "сегмент:смещение".
> Например, рассмотренный выше адрес будет записан как 2F84:0532.
> Заметим, что т.к. смещение может меняться, приведенная пара
> "сегмент:смещение" не единственна. Все следующие адреса указывают на
> одну и ту же ячейку памяти:
>
> 0000:0123
> 0002:0103
> 0008:00А3
> 0010:0023
> 0012:0003
>
> И еще: сегменты могут перекрываться. Например, все четыре сегмента
> могут начинаться с одного и того же адреса, что означает, что ваша
> программа не будет иметь больше чем 64К адресного пространства, в
> котором находятся ваша программа, данные и стек.
Документация по Turbo C, из которой я позаимствовал иллюстрации,
содержит исчерпывающая информацию о моделях памяти.
> Tiny
> ----
>
> Как вы можете предположить, это самая маленькая из моделей памяти. Все
> четыре сегментных регистра (DS,CS,SS,ES) указывают на один и тот же
> адрес, поэтому вы имеете всего 64К для всех программ, данных и
> массивов. В этом случае используются только near-указатели.
> Используйте эту модель, когда у вас маленькая оперативная память.
> Программы с крохотной моделью памяти могут быть переведены в .COM
> формат.
>
>
> Сегментные Размер
> регистры: Нач.адрес. сегмента:
> CS,DS,SS -->+------------------------------+
> + |_TEXT class 'CODE'Программа | +
> | +------------------------------+ |
> DGROUP -+ |_DATA class 'DATA'иниц.данные | |
> | +------------------------------+ |
> + |_BSS class 'BSS'не иниц,данные| |
> +------------------------------+ +- до 64К
> | ХИП | |
> +------------------------------+ |
> | Свободная область | |
> SР (ТOS) -->+------------------------------+ |
> Стартовый SP-->| СТЕК | +
> +------------------------------+
> Конеч.адрес.
Обратите внимание, что адреса всех сегментов совпадают. Ирония заключается
в том, что формат COM (от Command), наспех перенесенный из CP/M, от
поддержки которого Microsoft давно обещает отказаться, фактически
возрожден в PE-формате под Win32, который также представляет из себя образ
памяти и реализует простейшую односегментную модель. (И Вы даже можете
переименовать все свои Win32 .EXE-файлы в .COM и они будут нормально
работать - загрузчик различает их не по расширениям, а по сигнатурам).
Вы можете видеть, что данные размещены непосредственно за кодом (Borland
традиционно использует для сегмента кода метку TEXT), а стек, как и
следовало ожидать, растет вниз от конца сегмента. Сокращение TOS (Top of
Stack) обозначает верхушку стека.
Здесь Вас может настичь неприятность, называемая переполнением стека (Stack
Overflow), когда заносимые в стек данные затирают то, что хранится в
сегменте данных. Результатом, разумеется, будет крах программы.
> Small
> ------
>
> Программный сегмент и сегмент данных различны и не перекрываются,
> поэтому у вас есть 64К для программ и 64К для статических данных.
> Сегменты стека и дополнительные сегменты данных начинаются с того же
> адреса, что и сегмент данных. В этом случае используются только
> near-указатели. Это наилучшая модель для большинства реализаций.
>
>
> Сегментные Размер
> регистры: сегмента:
> Нач.адрес.
> CS -->+------------------------------+
> |_TEXT class 'CODE' программа | до 64К
> DS,SS -->+------------------------------+
> + |_DATA class 'DATA'иниц.данные | +
> DGROUР -+ +------------------------------+ |
> + |_BSS class 'BSS'не иниц.данные| |
> +------------------------------+ |
> | ХИП | +- до 64К
> +------------------------------+ |
> | Свободная область | |
> SP (TOS) -->+------------------------------+ |
> | СТЕК | +
> Стартовый SP-->+------------------------------+ до конца
> | FAR ХИП | памяти
> +------------------------------+
> | Свободная область |
> +------------------------------+
> Конеч.адрес.
Хотя на рисунке сегмент данных непосредственно примыкает к сегменту кода,
это, вообще говоря, необязательно и загрузчик может расположить их по
собственному усмотрению (перенастроив соответствующие ссылки).
Обратите также внимание на появившийся Far Heap - область, где память
может быть выделена динамически (в пределах 1-го мегабайта).
> Medium
> ------
> Far-указатели используются для программ, но не для данных. В результате
> статические данные ограничены 64К, но программа может иметь величину до
> 1М. Эта модель является наилучшей для больших программ, которые не
> хранят в памяти больших объемов данных.
>
>
> Вложенные
> sfiles
> +----------+(CS-указатель одновременно
> |sfileA |только на 1 sfile)
> CS -->|sfileB |
> +-+... |
> Сегментные | |sfileZ | Размер
> регистры: | +----------+ Нач.адрес. сегмента:
> CS -->+-----|--------------------------+
> |+----++ |каждый sfile
> ||sfile|_TEXTclass'CODE'программа|до 64К
> |+-----+ |
> DS,SS -->+--------------------------------+
> + |_DATA class 'DATA' иниц.данные | +
> | +--------------------------------+ |
> | |_BSS class 'BSS' не иниц.данные | |
> | +--------------------------------+ |
> DGROUР -+ | ХИП | +- до 64К
> | +--------------------------------+ |
> | | Свободная область | |
> SP (TOS)-->+--------------------------------+ |
> + | СТЕК | +
> Стартовый SP-->+--------------------------------+ до конца
> | FAR ХИП | памяти
> +--------------------------------+
> | Свободная область |
> +--------------------------------+
> Конеч.адрес.
> Compact
> -------
>
> Прямо противоположна средней, т.е. far-указатели используются для
> данных, а не для программ. Программы ограничиваются величиной в 64К, а
> данные (но не статические) могут быть до 1 Мб. Эта модель наиболее
> удобна, если ваша программа маленькая, но вам необходимо адресовать
> большие объемы данных.
>
>
> Сегментные Размер
> регистры: сегмента:
> Нач.адрес.
> CS,DS -->+------------------------------+
> |_TEXT class 'CODE'Программа | до 64К
> +------------------------------+
> + |_DATA class 'DATA'иниц.данные | +
> DGROUP -+ +------------------------------+ +- до 64К
> + |_BSS CLASS 'BSS' 'иниц.данные | +
> SS -->+------------------------------+
> | Свободная область |
> SP (TOS)-->+------------------------------+
> | СТЕК | до 64К
> Стартовый SP-->+------------------------------+ до конца
> | ХИП | памяти
> +------------------------------+
> | Свободная область |
> +------------------------------+
> Конеч.адрес.
> Large
> -----
>
> Far-указатели используются как для программы, так и для данных. И
> программа, и данные занимают область до 1М; эта модель необходима
> только для очень больших программных продуктов.
>
>
> Вложенные
> sfiles
> +----------+(CS-указатель одновременно
> |sfileA | только на 1 sfile)
> CS -->|sfileB |
> +-+... |
> Сегментные | |sfileZ | Размер
> регистры: | +----------+ Нач.адрес. сегмента:
> CS -->+-----|--------------------------+
> |+----++ | Каждый sfile
> ||sfile|_TEXTclass'CODE'программа| до 64К
> |+-----+ |
> DS -->+--------------------------------+
> + |_DATA class 'DATA'иниц.данные | +
> DGROUP -+ +--------------------------------+ + до 64К
> + |_BSS class 'BSS'не иниц.данные | +
> SS -->+--------------------------------+
> | Свободная область |
> SP (TOS)-->+--------------------------------+
> | СТЕК | до 64К
> Стартовый SP-->+--------------------------------+
> | ХИП | до конца
> +--------------------------------+ памяти
> | Свободная область |
> +--------------------------------+
> Конеч.адрес.
> Huge
> ----
>
> Far-указатели используются для программы и для данных. Турбо Cи обычно
> ограничивает величину статических данных до 64К; огромная модель памяти
> снимает это ограничение, позволяя статическим данным занимать
> пространство более 64К.
>
>
> Вложенные
> sfiles
> +----------+(CS-указатель одновременно
> |sfileA | только на 1 sfile)
> CS-->|sfileB |
> |... |
> Сегментные +-+sfileZ | Размер
> регистры: | +----------+ сегмента:
> | Нач.адрес.
> CS -->+-----|--------------------------+
> |+----++ | каждый sfile
> ||sfile|_TEXTclass'CODE'программа| до 64К
> |+-----+ |
> DS -->+--------------------------------+
> |+-----+ | каждый sfile
> ||sfile|_DATAclass'DATA'иниц.дан.| до 64К
> |++----+ |
> SS -->+-|------------------------------+
> | | Свободная область |
> SP(TOS)-->+-|------------------------------+
> | | СТЕК | до 64К
> Стартовый SP-->+-|------------------------------+ до конца
> | | ХИП | памяти
> +-|------------------------------+
> | | Свободная область |
> +-|------------------------------+
> | +----------+ Конеч.адрес.
> +-+sfileA |
> DS -->|sfileB |(DS-указатель одновременно
> |... | только на 1 sfile)
> |sfileZ |
> +----------+
> Вложенные
> sfiles
> Сводная таблица обобщает информацию о различных моделях и показывает их
> в сравнении. Модели группируют в зависимости от того, какова у них
> величина программы и данных, т.е. маленькая (64 Кb) или большая (1 Мb).
>
> Так, например, крохотную, малую и компактную модели называют "моделями
> с малыми программами" потому, что, по умолчанию, указатели в таких
> программах только near. Аналогично компактную, большую и огромную
> модели называют "моделями с большими данными" потому, что, по
> умолчанию, указатели к данным в них только far.
>
> Заметим, что это также верно для огромной модели: по умолчанию,
> указатели к данным только far, а не нормализованные (huge). Если вы
> хотите использовать huge-указатели к данным, то вы должны
> предварительно объявить их как huge.
>
>
> +-------------+-----------------------------------------------------+
> | | Program Size |
> | Data Size |------------------------------+----------------------+
> | | 64 Кb | 1 Мb |
> +-------------+------------------------------+----------------------+
> | 64К | Tiny | |
> | | (Данные и программа перекры- | |
> | | ваются. Общий размер 64 Кb) | |
> | +------------------------------+----------------------+
> | | Small | Medium |
> | | (Не перекрываются. Общий | (Малые данные, |
> | | размер 128 Кb) | большая программа) |
> +-------------+------------------------------+----------------------+
> | 1М | Compact | Large |
> | | (Большие данные, малая | (Большие данные и |
> | | программа) | программы) |
> | +------------------------------+----------------------+
> | | | Huge |
> | | | (Аналогично Large) |
> | | | только статические |
> | | | данные больше 64 Кb) |
> +-------------+------------------------------+----------------------+
>
>
> Важное замечание.
>
> Когда вы компилируете модуль (указывая исходный файл, содержащий
> несколько функций), результирующая программа не может быть более 64К,
> т.к. все функции должны включаться в один программный сегмент. Это
> верно, даже если вы используете модели с большими программами (среднюю,
> большую и огромную). Если ваш модуль больше величины одного
> программного сегмента (64 Кb), то вы должны разделить его на разные
> исходные программные файлы, откомпилировать каждый файл в отдельности и
> затем объединить их вместе. Проще говоря, хотя огромная модель и
> позволяет статическим данным занимать объем больше, чем 64К, в каждом
> модуле все равно должно быть меньше, чем 64К.
И в заключение, забегая вперед, я решил процитировать раздел документации,
посвященный вплотную примыкающей сюда теме указателей. Позднее мы снова к
ней вернемся.
Pointers
--------
> Указатели типа NEAR, FAR И HUGE
> -------------------------------
>
> Какие указатели применяют в моделях памяти в Турбо Си ? Очень многие.
> Тип указателей, используемых для программы и данных, по умолчанию
> определяется типом модели памяти, выбранной вами. Однако вы можете
> принудительно объявить указатель (или функцию), имеющий специфический
> тип, невзирая на модель, которая используется. Указатели бывают 3-х
> типов: ближние или near (16 бит), дальние или far (32 бита) и огромные
> или huge (также 32 бита).
>
>
> Указатели типа NEAR
> -------------------
>
> 16-битный (near) указатель используется совместно с одним из сегментных
> регистров для вычисления реального адреса. Например, реальный адрес
> функции получается путем сложения 16-битной величины указателя и
> функции с содержимым программного сегмента (CS), сдвинутым влево.
> Аналогично, near-указатель к данным содержит смещение относительно
> адреса в регистре сегмента данных (DS). Ближние указатели просты в
> использовании, т.к. все арифметические операции (такие, как сложение)
> можно выполнять, не заботясь о сегменте.
-----[05]----------[Info]-------------------------------------------------
Вопросы и замечания принимаются по адресу: aleph@canada.com
Предыдущие выпуски доступны со страницы архива:
http://www.subscribe.ru/archive/comp.prog.c4dummies/
или (в упакованном виде):
http://members.xoom.com/c4dummies/archive/000.zip
. . .
http://members.xoom.com/c4dummies/archive/009.zip
Рассылка дублируется (только текстовый вариант) с сервера www.egroups.com
Подписка: c4d-subscribe@egroups.com
-----[--]----------[The End]----------------------------------------------
© Gazlan 2009 * gazlan@yandex.ru
|