* 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

Hit Counter