Рефераты
 

Мова програмування Assembler

Мова програмування Assembler

Лекція 1 Вступна лекція

1. Загальний огляд дисципліни

2. Основні аспекти створення системних програм

3. Типи мов програмування: інтерпретатори, транслятори, компілятори та компоновщики

4. Моделі пам'яті та компонування програм

1. Загальний огляд дисципліни

Дисципліна "системне програмування" зазвичай викладається в технічних вузах як курс якоїсь окремої мови програмування, частіше всього - це асемблер або С. Насправді ж ця дисципліна не є черговим курсом з методики створення програм, а є курсом з тонкощів операційної системи, які можна використовувати в будь-якій мові програмування, де є можливість підключення або зовнішніх модулів або асемблерних вставок безпосередньо до програмного коду.

Отже, сформулюємо чітке визначення курсу:

Системне програмування - дисципліна, яка вивчає засоби та функції операційної системи, пов'язані з керуванням нею, периферійними пристроями та обміну даними між ними.

Історично склалось так, що існують дві мови, які використовуються для роботи на рівні операційної системи - асемблер та С. Перша мова бере свій початок від найпершого компілятора - Автокоду (1952), розробленого Аліком Гленні для комп'ютера Манчестер Марко I. Цей компілятор вперше використовував мнемонічне (у вигляді команд та відповідних операндів) позначення основних операцій, які здатна виконувати машина, які потім перетворювались на коди, зрозумілі машині. Цей процес був названий трансляцією. А мови, похідні від Автокоду, були названі асемблерами (від слова assembly - "збирати", адже програми збирались з окремих "цеглинок", мнемонічних команд). Ці мови працювали фактично на найнижчому рівні, на рівні процесора та його функцій, а пізніше - на рівні функцій операційної системи.

Саме тоді було закладено основи дисципліни системного програмування і закладено основні задачі, які і нині розв'язуються за допомогою його методів. Це насамперед керування процесором та керування периферійними пристроями, які під'єднані до загальної шини, і керуються цим процесором. З винайденням операційної системи, на яку покладалися загальні задачі обміну даними між процесором, пам'яттю та периферійними пристроями, основна задача системного програмування змінилась - оскільки керування обміну даними між периферійними пристроями перебрала на себе операційна система, до задач системного програмування увійшло завдання керування ресурсами, які контролює операційна система. Саме такою основна задача системного програмування є і по сьогодні. Отже, сформулюємо основну задачу системного програмування: створення програм для керування безпосередньо процесором та ресурсами операційної системи (пам'яттю та периферійними пристроями).

2. Основні аспекти створення системних програм

Перед тим, як ввести поняття системної програми, розглянемо спрощену архітектуру комп'ютерної системи:

На рівні мікрокоду як правило, працюють прошиті в мікросхемі програми, наприклад, MMX (MultiMedia Extended Set) чи SSE (Sequenced and Structured Extensions/Поширення для роботи з послідовностями та структурами), які фактично є програмами, зашитими в процесор. Ними системне програмування майже не займається, хоч може використовувати їх ресурси, чи викликати такі програми.

На рівні команд процесора працюють такі базові пакети, як BIOS та операційна система. Загалом, системне програмування займається написанням і того, і іншого, але останнім часом у світі існує тенденція щодо виділення їх в окремі наукові дисципліни. На рівні команд процесора також працюють так звані програми нульового рівня, тобто такі програми, які реалізовують основні функції операційної системи - обробники переривання, драйвери тощо.

На рівні операційної системи працює більшість користувацьких програм. Коди програм базуються на використанні переривань, драйверів, функцій операційної системи, написаних рівнем нижче. Слід розрізняти інтерфейс програміста та функції операційної системи. Перше - це набір вже написаних програм на певній мові програмування, і сформованих у так звану бібліотеку, якою може користуватись програміст. Друге - це прошитий у ядро операційної системи програмний код, який виконується в залежності від того, які переривання були збуджені, і які значення регістрів при цьому були. Інтерфейс програміста прийнято називати рівнем користувача, а функції операційної системи - рівнем операційної системи.

Системні програми працюють на рівні команд процесора та функцій операційної системи. Усе, що стосується більш низьких чи високих рівнів до системних програм може відноситись тільки опосередковано.

Системні програми, як правило, майже не мають інтерфейсу користувача, а лише набір текстових повідомлень, які керують нею, або повідомляють про перебіг її роботи. Крім того, системні програми займають порівняно невеликий розмір, що викликано самим характером мови, на якій вони пишуться. Програми на асемблері, які більші за 1000 рядків, вже не сприймаються адекватно навіть тим програмістом, який цю програму пише.

3. Типи мов програмування: інтерпретатори, транслятори, компілятори та компоновщики

Більшість системних програм, як вже говорилося вище, пишеться на мовах асемблер та С. Загалом, системні програми можна писати на будь-якій мові, де є можливість працювати безпосередньо з процесором, пам'яттю та функціями операційної системи. Всі такі мови поділяються на два великі класи: інтерпретовані та трансльовані.

Інтерпретовані - це мови, програми на яких перетворюються на машинний код тільки під час виконання. Загальна схема роботи програм на таких мовах має вигляд:

На цій діаграмі ми бачимо, що між програмою та операційною системою є ще "перетворювач" (інтерпретатор), який послідовно читає програмний код, і послідовно на льоту перетворює його на машинний код. Прикладом такої мови є мова Rexx, розроблена IBM для операційної системи PCDOS. Такі програми, зазвичай, повільніші за трансльовані, але їх простіше редагувати, оскільки виконується не машинний код, а безпосередньо текст програми: рядок за рядком.

Трансльовані - це такі мови, програмний код яких цілком може бути безпосередньо перетворений у машинний код, і поширюватись у вигляді цілісного двійкового (виконуваного) модуля. Такий підхід дозволяє аналізувати код, і оптимізувати його, враховуючи при перетворенні не лише поточний рядок, а й попередні, і наступні. Такий процес називається компіляцією:

Перші два етапи називаються компіляцією, тобто утворення певного кістяку, за якими буде будуватись вихідний програмний код. Третій етап називається трансляцією, а останній - компоновкою.

Таким чином утворюється двійковий файл, який містить машинний код, і може бути зрозумілий операційній системі та безпосередньо процесору. Це значно пришвидшує програму, і тоді виконання програми має вигляд.

Як видно, ніяких проміжних програм при цьому немає, тобто програма безпосередньо працює з системою, а відтак - швидше.

4. Моделі пам'яті та загальна структура програм

Кожна системна програма обов'язково повинна відповідати певному типу пам'яті. Цим визначається, яким чином ця програма завантажуватиметься в пам'ять, які на неї накладатимуться обмеження, та які ресурси їй доступні. Ці моделі пам'яті однакові як в асемблері, так і в С, тому доцільніше їх розглянути тут. Програми складаються з сегментів (частин). Кожна з яких може бути не більша за 64 Кб. Сегмент може містити код або дані, відповідно до термінів Фон Неймана. Програма може мати сегментів трьох типів: коду, даних та стеку. Відповідно, існує 6 типів моделей пам'яті, які задають співвідношення та обмеження на ці сегменти:

Tiny (дуже малий). Дані та код знаходяться в один та тільки одному сегменті як у двійковому, так і програмному коді.

Small (малий) - Дані та код по замовчанню знаходяться в одному і тому ж самому сегменті після компіляції, але в програмному коді small можуть бути розділені на сегмент даних.

Compact (компактний). Код знаходиться в одному сегменті, але кожна змінна - фактично у своєму власному сегменті, оскільки адресується не за локальним посиланням, а шляхом точного вказання комірки. Така структура застосована, коли змінні містять великі обсяги даних.

Medium (середній) - протилежний попередньому. Дані знаходяться в одному сегменті, а кожна процедура - у своєму власному. Ця модель пам'яті дає оптимізацію при великих обсягах програмного коду в процедурах.

Large (великий) - позначає тип пам'яті, де розподіл програмного коду по сегментах відбувається за вибором програміста.

Flat (плоский) - програма взагалі не поділяється на сегменти, але може містити обсяг коду даних, більше за 64 Кбайт. Деякі операційні системи такої моделі пам'яті не підтримують, однак це можна обійти за допомогою драйвера-розширювача (наприклад, dos2gw). Така модель пам'яті використовується для великих програм: Windows, Linux тощо.

Лекція 2 Класифікація мов програмування, основні поняття програмування

1. Класифікація мов програмування за семантикою, за призначенням, за рівнем використання, за способом компіляції

2. Поняття "транслятор", "компілятор", "інтерпретатор", "компоновщик"

3. Загальний алгоритм створення програми

1. Класифікація мов програмування за семантикою, за призначенням, за рівнем використання, за способом компіляції

Мови програмування можна класифікувати за декількома параметрами. Найбільш поширеними є класифікація за семантикою, за призначенням, за рівнем використання та за способом компіляції. Отже, розглянемо їх:

1. За семантикою мови поділяються на імперативні та декларативні. Імперативні мови програмування є детальним викладенням якогось процесу обчислення або дій, які повинен виконати процесор або периферійний пристрій, або ж програмний засіб. Прикладом імперативних мов може слугувати будь-яка сучасна мова програмування, наприклад, C чи Assembler. На відміну від них, декларативні мови передбачають насамперед формулювання мети, тобто кінцевого результату. До декларативних мов належать спеціалізовані мови, такі як Prolog або Occam, але найбільш поширеними мовами цього типу є так звані "оболонки", себто командні інтерпретатори, які існують у кожній сучасній операційній системі, і в яких користувач дає операційній системі виконати певні дії над ресурсом.

2. За призначенням мови поділяються на алгоритмічні, математичні, логічні, функціональні, об'єктно-орієнтовані та спеціалізовані. До алгоритмічних належать всі мови, головним завданням яких є виконання певних задач, які піддаються формалізації. Такі мови містять ключові слова для утворення основних елементів алгоритмів - розгалужень, точок вибору, циклів, функцій тощо та відповідних структур даних. Це знову ж таки С, C++, Pascal, Ada тощо. До математичних мов належать такі мови, головною задачею в яких визнається формалізація та розв'язок математичних рівнянь. Чисто математичною мовою прийнято вважати мову Fortran. Ця мова містить виключно засоби для створення складних математичних виразів, але не містить жодного елементу алгоритму. Однак на сьогодні, більшу популярність набули так звані мішані мови, які також увібрали в собі елементи алгоритмічних мов, зберігаючи засоби для відображення математичної нотації. До таких мов належить, зокрема, MathLab. Логічні мови сконцентровані на відображенні логічних тверджень та автоматичному доказі висновків з цих тверджень. Прикладом такої мови може слугувати Prolog, створений для автоматичного доведення теорем. Функціональні мови призначені для моделювання процесів, і хоч вони містять елементи алгоритмічних мов, але їх основною задачею все-таки є процеси фактично без звертання до даних. Прикладом такої мови є Haskell - університетська розробка. Об'єктно-орієнтовані є протилежними за архітектурою. Подібно до концентрації функціональних мов на функціях та процесах, ці мови концентруються на маніпуляції даними та відносинами між ними, до яких прив'язуються відповідні дії. Класичними об'єктно-орієнтованими мовами є SmallTalk та C++. Спеціалізовані мови можуть містити будь-які конструкції та засоби, відповідно до специфіки сфери, для яких їх призначено. Так, мови розмітки документів XML та HTML містять способи вказання способу відображення даних у Web-браузері, а мова APL - методи для обробки векторних даних.

3. За рівнем використання мови поділяються на низькорівневі, високорівневі, надвисокорівневі та мішані. Низькорівневі мови працюють на рівні операційної системи та команд процесора. Найчастіше це асемблери різних типів. Високорівневі мови - на рівні так званого інтерфейсу програміста, написаного на низькорівневих мовах для забезпечення виконання певних типових задач, як, наприклад, звертання до файлової системи за допомогою більш універсальних засобів, ніж переривання або функції ОС. До цих мов можна віднести C++, Perl, Ada або Pascal. Надвисокорівневі мови, як правило, розширюють можливості певного комплексного програмного засобу, або ж побудовані на бібліотеках так званих компонентів - готових "цеглинок" для побудови кінцевого продукту. Такі мови (а точніше - діалекти, оскільки чистих мов такого типу на сьогодні не існує) - Object Pascal, Visual C++. Мішаними називають такі мови, які здатні працювати на кількох рівнях у межах однієї програми. Класичною мовою такого типу є C, яка містить засоби роботи як на низькому, так і високому рівнях.

4. За типом компіляції мови поділяються на інтерпретовані, трансльовані та мішані. Інтерпретовані мови, як вже здавалося вище, існують у вигляді відкритого програмного коду, який при виконанні рядок за рядком перетворюється в машинний код проміжною програмою-інтерпретатором. Прикладом такої мови є Rexx, Objective (діалект мови З) та Forth. Трансльовані мови цілком перетворюються в машинний код після аналізу програмного коду. Прикладами таких мов можуть слугувати більшість алгоритмічних мов на сьогодні. Мішаними називаються такі мови, які поєднують у собі кращі риси обох цих типів. Першою такою мовою була створена Sun Microsystems мова Java, яка компілюється в кросплатформений байт-код, а потім інтерпретується віртуальною машиною, яка транслює цей проміжний код у машинний код для поточного процесора. На сьогодні існує ще дві такі мови: C# та Python.

2. Поняття "транслятор", "компілятор", "інтерпретатор", "компоновщик"

Транслятор - програма, яка перетворює програмний код, викладений на певній мові програмування, у машинний код.

Компілятор - програма, яка аналізує програмний код, проводить аналіз помилок, якщо їх не знайдено, оптимізує його, себто вирізає зайві шматки коду, або неефективні фрагменти замінює їх більш ефективними аналогами, і покращенний таким чином код передає транслятору. У сучасних системах розробки ПО компілятор та транслятор часто об'єднані в один модуль.

Інтерпретатор - програма, яка виконує програмний код, рядок за рядком перетворюючи його на льоту в машинний код за певною таблицею відповідності.

Компоновщик - програма, яка виконує зборку виконуваного модуля з одного чи кількох так званих двійкових модулів, які містять чистий машинний код, трансльований з певної мови програмування.

3. Загальний алгоритм створення програми

Загальний алгоритм можна звести до простої діаграми:

При цьому слід зазначити, що всі ці етапи розробки полегшуються за допомогою так званого "середовища інтегрованої розробки", який постачається з майже будь-якою мовою програмування. Єдиним винятком з цього правила є асемблери, які мають інтерфейс тільки командної стрічки.

Для запуску макроасемблера з використанням підказок необхідно ввести командний рядок, що містить тільки ім'я макроасемблера MASM зі специфікацією підзаголовку, якщо вона потрібна. MASM перейде в діалоговий режим і серією підказок запросить у користувача інформацію про наступні файли (відповідь полягає в наборі необхідних символів і натисканні клавіші ENTER):

1. Ім'я вихідного файлу. Якщо при відповіді не зазначене розширення, передбачається ASM.

2. Ім'я об'єктного файлу. Якщо при відповіді не зазначене розширення, передбачається OBJ. Базове ім'я об'єктного файлу за замовчуванням збігається з базовим ім'ям вихідного файлу.

3. Ім'я файлу лістинга. Якщо при відповіді не зазначене розширення, передбачається LST. Базове ім'я файлу лістинга за замовчуванням NUL.

4. Ім'я файлу перехресних посилань. Якщо при відповіді не зазначене розширення, передбачається CRF. Базове ім'я файлу лістинга за замовчуванням NUL.

Наприкінці будь-якої відповіді після символів "/" або - "," можуть бути задані опції макроасемблера.

Якщо в якій-небудь відповіді специфіковано символ ";", MASM вийде з діалогового режиму й встановить імена, що залишилися, за замовчуванням з наступного списку:

<ім'я вихідного файлу>.OBJ

NUL.LST

NUL.CRF

У будь-якій відповіді також можуть бути задані відповіді на кілька наступних підказок. У цьому випадку одна відповідь від іншого відокремлюється комами.

Для запуску MASM за допомогою командного рядка необхідно ввести командний рядок наступного виду:

MASM <ім'я вихідного файлу>[,[<ім'я об'єктного файлу>]

[,[<ім'я файлу лістинга>][,[<ім'я файлу перек. посилань>]]]]

[<опції>][;]

Символ ";" може бути специфікований у будь-якому місці командного рядка до того, як були визначені усі файли. У цьому випадку імена невизначених файлів, що залишилися, приймаються за замовчуванням із приведеного вище списку. З цього ж списку приймаються за замовчуванням імена файлів, специфікація яких у командному рядку опущена (за допомогою зайвої коми).

Якщо в командному рядку виявлена помилка, про це повідомляється через консоль, і MASM переходить у діалоговий режим.

Опції MASM можуть розташовуватися в будь-якому місці командного рядка.

Лекція 3 Порівняльна характеристика С та асемблера

1. Визначення низькорівневої мови

2. Порівняльна характеристика мов Assembler та C

3. Види асемблерів

4. Види компіляторів C

1. Визначення низькорівневої мови

Низькорівневою називається така мова, яка містить методи для звертання безпосередньо до функцій операційної системи, зокрема, збудження переривань та виклик їх функцій, периферійних пристроїв через порти введення-виведення, а також звертання безпосередньо до конкретних комірок системної пам'яті та регістрів мікропроцесора.

2. Порівняльна характеристика мов Assembler та C

Сі є мовою функцій, типів даних, операторів присвоювання і керування послідовністю обчислень. Програмуючи на Сі, ви здійснюєте звертання до функцій, і більшість функцій повертають деякі значення. Значення, що повертається функцією, будь то значення змінної чи константа, може використовуватися в операторі присвоювання, що змінює значення іншої змінної. Доповнений операторами керування послідовністю обчислень (while, for, do, switch), Сі перетворюється в мову високого рівня, що сприяє гарному стилю програмування.

Сі має невеликий набір типів даних: цілі числа, числа з комою, що плаває, бітові поля і перерахований тип. У мові Сі ви можете описати змінну типу покажчик, що зв'язується з об'єктом, який належить до будь-якого типу даних. Адресна арифметика мови Сі є чутливою до типу даних того об'єкта, з яким зв'язаний використовуваний покажчик. Дозволені також покажчики до функцій. Ви можете розширити список типів даних шляхом створення структур з ієрархічною залежністю типів даних, що входять у нього. Кожен тип даних може належати або до основного типу, або до раніше описаного структурного типу. Об'єднання нагадують структури, але визначають різні види ієрархічних залежностей, у яких дані різних типів розташовуються в пам'яті.

Допустимим є опис масивів даних різних типів, включаючи структури й об'єднання. Масиви можуть бути багатомірними.

Функції Сі є рекурсивними за замовчуванням. Ви можете, щоправда, створити функцію, що не буде рекурсивною, але сама мова по своїй природі прагне підтримувати рекурсивність і вимагає мінімальних зусиль при програмуванні рекурсій.

Програма функції мовою Сі розбивається на блоки, у кожному з яких можуть бути визначені свої власні локальні змінні. Блоки можуть вибиратися для виконання в результаті виконання оператора керування послідовністю обчислень. Блоки можуть бути вкладеними один у інший.

Змінні і функції можуть бути глобальними для програми, глобальними для вихідного модуля чи локальними для блоку, у якому вони описані. Локальні змінні можуть бути описані таким чином, що вони будуть зберігати свої значення при всіх звертаннях усередині даного блоку (статичні змінні) або ж будуть сприйматися як нові об'єкти при кожному звертанні (автоматичні змінні).

Сі дозволяє створювати програму у виді декількох вихідних модулів, що будуть транслюватися окремо. Переміщувані об'єктні модулі, що відповідають вихідним модулям, компонуються в єдиний завантажувальний модуль. Ця особливість дозволяє компілятору підтримувати об'єктні бібліотеки функцій, що багаторазово використовуються і створювати великі програми з безлічі невеликих вихідних модулів.

У мові Сі немає операторів введення/виведення, усе введення/виведення виконується за допомогою функцій. Унаслідок цієї особливості мови Сі розроблена стандартна бібліотека функцій. Існування цього стандарту і складає головну привабливість мови Сі, тому що робить програми на Сі мобільними для переносу з однієї системи на іншу.

3. Види асемблерів

Макроасемблер MASM фірми MICROSOFT асемблює програми мовою асемблера для мікропроцесорів 8086, 8088, 80186 і 80286 і створює об'єктні файли, що можуть редагуватися і виконуватися в операційній системі MS-DOS. Макроасемблер забезпечує виконання наступних функцій:

1. Аналіз вихідного тексту мовою асемблера на предмет наявності у ньому макрокоманд та макровизначень, і обробка цих конструкцій з відповідною корекцією вихідного тексту.

2. Синтаксичний аналіз отриманого тексту і виведення необхідної діагностичної інформації.

3. Формування об'єктного модуля. Сприймаючи як вхід один файл із вихідним текстом, макроасемблер може формувати до трьох вихідних файлів, як показано на рис. 2.1.

Рис. 2.1. Робота макроасемблера

Розширення імен файлів, показані на малюнку, приймаються за замовчуванням. Файл лістинга містить роздруківку вихідного тексту у відповідності зі специфікованими директивами асемблера режимами і діагностичними повідомленнями про результати синтаксичного аналізу. Ці ж повідомлення дублюються на консолі.

Файл перехресних посилань містить усі використовувані у вхідному тексті ідентифікатори. Надалі він може бути використаний утилітою CREF.

У файлі об'єктного коду формується об'єктний модуль. Цей файл не формується, якщо в тексті виявлені помилки.

4. Види компіляторів C

Borland International

Вихід компілятора Turbo C являє собою розумний, але не дуже оптимізований код. Крім згортки констант, видалення зайвих завантажень регістрів і алгебраїчних спрощень, компілятор виконує тільки зниження потужності, видалення недосяжного коду і розміщення змінних у регістрах. Він не підтримує інші загальні методи оптимізації, такі як видалення зайвих збережень, загальних підвиразів і змінні індукції циклу, а також винесення інваріантного коду. Turbo C розумно керує прологом і епілогом функцій і використанням регістрів, засилаючи в стек і витягаючи тільки ті регістри, що явно використовуються усередині тіла функції.

Computer Innovation Inc

Компілятор C86Plus виробляє чудовий код із середнім рівнем оптимізації. Він виконує базові прийоми оптимізації, такі як згортка констант і розмноження копій. Однак він не виконує розмноження констант для видалення зайвих збережень. Хоча компілятор успішно виконує алгебраїчні спрощення, він породжує зайві інструкції через те, що розміщає результати в регістрах, замість того, щоб поміщати їх у змінні. Цей ефект виявляється в том, що при розміщенні змінних у регістрах починаються спроби перерозміщення, тому що при виконанні декількох операторів результати в дійсності повинні бути привласнені відповідним змінним. Хоча C86Plus успішно справляється зі згорткою явних присвоювань, що дублюються, в одне присвоювання, видалення зайвих збережень він виконує хитливо. Він не виконує істотну оптимізацію циклів.

Datalight Inc

З появою Optimum-C Datalight стала одним з перших постачальників, що запропонували оптимізований компілятор. Хоча набір тестів не підтвердив наочно претензії Datalight на глобальну оптимізацію, Optimum-C спрацював так добре в деяких фрагментах тесту, що продемонстрував слабкі фрагменти набору, які вимагають змін для удосконалення бажаної перевірки. Наприклад, у першій версії функції jump-compression не поверталося значення, що робило всі обчислення і присвоювання у функції зайвими. Optimum-C виявив це і видалив велику частину коду функції, включаючи ланцюжок переходів. У тесті розмноження констант і копій Optimum-C визначив, що присвоювання i5 в обох умовних операторах є зайвим стосовно наступних присвоювань. Компілятор видалив не тільки ці присвоювання, але й умовні оператори. Незадовільним виявилося видалення зайвих збережень значень регістрів. Optimum-C - єдиний компілятор, що намагався виконати глибоке видалення загальних виражень. Перевірка згенерованого коду показала, що загальне вираження i5+i2 було переміщено вище першого базового блоку умовного оператора, але не було вилучено з другого. Поза обмеженнями на стандартне використання регістрів, що накладаються сімейством мікропроцесорів 80x86, Optimum-C розумно використовує регістри. У функції jump-compression кожен переданий параметр був поміщений у регістр. Усередині тіла функції не було посилань у пам'ять, крім початкового засилання в регістри. Однією важливою областю, у якій компілятор Optimum-C вимагає поліпшень, є оптимізація циклів. Компілятор не намагається виконувати винесення інваріантного коду і видалення змінних індукції циклу. Тест виконання показав, що компілятор Datalight дуже ефективно керує введенням/висновком getc/putc, а інші тести виконуються в прийнятний час.

Lattice Inc

Компілятор, що має велику історію, Lattice MS-DOS C послідовно удосконалювався з кожною новою версією. Він відомий як генератор стабільного, передбачуваного коду і виконує помірну оптимізацію. Lattice С виконує зниження потужності, стиск ланцюжка переходів і видалення загальних підвиразів. Він не видаляє присвоювання, що дублюються після тесту вбудованих функцій і зайві присвоювання у функції dead-code. Lattice C не виконує оптимізацію циклів.

Manx Software Systems Inc

Компілятор Aztec C86 згенерував чудовий код з досить гарним рівнем оптимізації. Крім згортки констант і алгебраїчних спрощень, Aztec C86 виконав зниження потужності і видалення загальних підвиразів. Однак, він не виконав видалення зайвих присвоювань і не видаляв недосяжний код. Aztec C86 згенерував код для недосяжного оператора printf разом з безумовним переходом через нього. Оскільки будь-яка програма на Сі має значну кількість викликів функцій, заголовок кожного виклику необхідно мінімізувати. Aztec C86 використовує незвичайний, але ефективний підхід до рішення цієї проблеми. На виході компілятора виходить текст у мові асемблера, що обробляється окремим асемблером. Компілятор вставляє в текст директиви умовного асемблювання навколо коду, що встановлює стековий фрейм і зберігає регістри. Після генерації коду функції, компілятор визначає символи для керування установкою стекового фрейму і збереження тільки тих регістрів, що використовуються у функції. Aztec C86 не зміг вирішити задачу перетворення ланцюжка переходів в один перехід до кінцевої мети. Він також не виконував оптимізацію циклів.

Metaware Inc

High C виробляє чудовий код із середнім рівнем оптимізації. Компілятор виконує всі базові види оптимізації, включаючи згортку констант і алгебраїчні спрощення, видалення зайвих операцій завантаження регістрів, зниження потужності і видалення загальних підвиразів. Компілятор Metaware видаляє недосяжний код, але не видаляє зайві присвоювання. High C розумно використовує машинно-залежні інструкції. Компілятор удосконалить завантаження констант із крапкою, що плаває, використовуючи команду копіювання рядків MOVS процесорів 80x86 для запису значень із крапкою, що плаває, обчислених під час компіляції. Він також генерує інструкцію LEAVE процесорів 80x86 для епілогу функцій, але встановлює адресацію стекового фрейму в пролозі функції за допомогою окремих інструкцій, а не використовуючи більш тривалу інструкцію ENTER. Компілятор High C не виконує винесення інваріантного коду, важливий метод оптимізації циклів. Він також не зміг застосувати успішне видалення змінних індукції циклів. Вбудовані функції підтримуються для декількох цілочисленних і строкових операцій, таких як strlen.

Microsoft C

У версії 5.0 свого компілятора Сі корпорація Microsoft вивела на ринок PC високий рівень оптимізації коду. Microsoft приділяє багато уваги аналізу циклів. C 5.0 - єдиний з розглянутих компіляторів, що виконує винесення інваріантного коду і сьогоденне видалення змінних індукції циклів. Компілятор Microsoft C 5.0 чудово використовує регістри, намагаючись мінімізувати звертання до пам'яті в тілі циклу . Простий приклад циклу в коді тесту демонструє ступінь оптимізації циклів, який виконує Microsoft C 5.0. Компілятор застосовує зниження потужності і цілком видаляє константне множення, виявляє кінцевий стан змінних, і поміщає в регістри всі змінні всередині циклу. C 5.0 видаляє цикл for і генерує код тільки з метою установки кінцевого стану змінної - індексу циклу й оператора, включеного в цикл. Компілятор також добре використовує регістри. Увага фірми Microsoft до оптимізації винагороджується при роботі тесту виконання. Він виконується за час, що є кращим чи близько до кращого по кожній категорії.

WATCOM

Новітній суперник, що завойовує позиції на ринку компіляторів C - WATCOM C 6.0 (див. Product Watch, Philip N. Hisley, за цей місяць). C 6.0 виробляє компактний код, що чудово використовує трохи обмежений комплект регістрів сімейства 80x86. Крім виконання базових прийомів оптимізації, він підтримує зниження потужності і видалення недосяжного коду і загальних підвиразів. У той час, як Microsoft досягає поліпшення коду завдяки оптимізації циклів, WATCOM збільшує швидкість шляхом зменшення керуючих заголовків викликів функцій до їхнього абсолютно мінімального розміру. Він досягає цього, шляхом переважної передачі параметрів через регістри, а не через стек. WATCOM дуже добре видаляє недосяжний код. C 6.0 не тільки видалив непотрібні присвоювання і недосяжний код усередині функції, але він також видалив пролог і епілог функції і згорнув усю функцію до простого повернення, приписавши ім'я функції до інструкції повернення основної функції. На завершення всього, компілятор видалив локальний виклик функції. Наскільки C 6.0 витончений у знищенні марної функції, настільки ж він безпомічний при видаленні марного присвоювання, що дублюється. Найбільш важлива область, за яку WATCOM C 6.0, як і Optimum-C, не зміг узятися, була оптимізація циклів. Він не підтримує винесення інваріантного коду і видалення змінної індукції циклів. Хоча C 6.0 не виконує розгортання циклів в окремі команди, він (також як Datalight Optimum-C і Computer Innovations C86Plus) використовує команду REP/STOSW процесорів 80x86 для ініціалізації тестового масиву, завдяки чому видаляє цикл. Прекрасна генерація коду в WATCOM, зокрема, розумне використання регістрів, дає йому дуже важлива перевага. Він переміг у більшості тестів, що інтенсивно використовують процесор, і при цьому виконувався для великої моделі в кращий час, ніж більшість інших компіляторів для малої моделі. До слабких сторін WATCOM можна віднести введення/виведення файлів, використання getc і putc. Тут він близький до найгірших компіляторів.

Лекція 4

1. Поняття "об'єктного файлу" та "виконуваного модуля"

2. Архітектура виконуваного модуля

3. Поняття "компонування"

4. Види заголовків виконуваних файлів та огляд видів форматів виконуваних модулів та об'єктних файлів

1. Поняття "об'єктного файлу" та "виконуваного модуля"

Об'єктним файлом називається файл, який містить виключно машинний код без будь-якої прив'язки до особливостей операційної системи.

Виконуваним модулем називається такий об'єктний файл, якому передує так званий заголовок, який вказує, яким чином операційна система повинна виконувати цей код.

2. Архітектура виконуючого модуля

OBJ-модуль - більш наближений до виконавчих форм, але ще не готовий до виконання. Крок компонування включає перетворення OBJ-модуля в EXE (здійсненний) модуль, що містить машинний код. Програма LINK, що знаходиться на диску DOS, виконує наступне:

1. Завершує формування в OBJ-модулі адрес, що залишився невизначеним після асемблювання. В багатьох наступних програмах такі адреси асемблер відмічаєяк -і-іR.

2. Компонує окремо, якщо необхідно, більше одного асемблюваного модуля в одну завантажувальну (здійсненну) програму; можливо дві чи більше асемблерних програм, або асемблерну програму з програмами, написаними на мовах високого рівня, таких як Паскаль чи Бейсік.

3. Ініціалізує EXE-модуль командами завантаження для виконання.

Після компоновки OBJ-модуля (одного чи більше) у EXE-модуль, можна виконати EXE-модуль будь-яку кількість раз. Але, якщо необхідно внести деякі зміни в EXE-модуль, варто скорегувати вихідну програму, асемблювати її в інший OBJ-модуль і виконати компоновку OBJ-модуля в новий EXE-модуль. Навіть, якщо ці кроки поки залишаються незрозумілими, ви зрозумієте, що, одержавши небагато навичок, весь процес підготовки EXE-модуля буде доведений до автоматизму. Помітьте: визначені типи EXE-програм можна перетворити в дуже ефективні COM-програми. Якщо в результаті асемблюваня не виявлено помилок, то cлідуючий крок - компоновка об'єктного модуля. Файл EXASM1.OBJ містить тільки машинний код у шістнадцятковій формі. Оскільки програма може завантажуватися майже в будь-яке місце пам'яті для виконання, тому асемблер може не визначити всі машинні адреси. Крім того, можуть використовуватися інші (під) програми для об'єднання з основними. Призначенням програми LINK є завершення визначення адресних посилань і об'єднання (якщо потрібно) декількох програм. Для виконання можна також створювати COM-файли. Прикладом часто використовуваного COM-файлу є COMMAND.COM. Програма EXE2BIN.COM в оперативній системі DOS перетворить EXE-файли в COM-файли. Фактично ця програма створює BIN (двійковий) файл, тому вона і називається "перетворювач EXE у Вin (EXE-to-BIN)". Вихідний Вin-файл можна переназвати у COM-файл.

РОЗХОДЖЕННЯ МІЖ ПРОГРАМАМИ В EXE і COM-файлах

Незважаючи на те, що EXE2BIN перетворить EXE-файл у COM-файл, існують визначені розходження між програмою, виконуваної як EXE-файл, і програмою, виконуваної як COM-файл.

Розмір програми.

EXE-програма може мати будь-який розмір, у той час як COM-файл обмежений розміром одного сегмента і не перевищує 64ДО. COM-файл завжди менший, ніж відповідаючий EXE-файл; одна з причин цього - відсутність у COM-файлі 512-байтового початкового блоку EXE-файлу.

Сегмент стека.

У EXE-програмі визначається сегмент стека, у той час як COM-програма генерує стек автоматично. У такий спосіб при створенні асемблерної програми, яка буде перетворена в COM-файл, стек повинен бути опущений.

Сегмент даних.

У EXE програмі звичайно визначається сегмент даних, а регістр DS ініціалізується адресою цього сегмента. У COM-програмі всі дані повинні бути визначені у сегменті коду. Нижче буде показаний простий спосіб рішення цього питання.

Ініціалізація.

EXE-програма записує нульове слово в стек та ініціалізує регістр DS, тому що COM-програма не має ні стека, ні сегмента даних, де ці кроки відсутні. Коли COM-програма починає працювати, усі сегментні регістри містять адресу префікса програмного сегмента (PSP), - 256-байтового (тичина. 100) блоку, що резервується операційною системою DOS безпосередньо перед COM чи EXE програмою в пам'яті. Оскільки адресація починається з точки зсуву 100 від початку PSP, то в програмі після оператора SEGMENT кодується директива ORG 100H.

Страницы: 1, 2, 3, 4, 5, 6


© 2010 BANKS OF РЕФЕРАТ