Программы
ВХОД
Логин:    

Пароль:  

   Запомнить меня
Вам нужно авторизоваться.
Забыли пароль? / Регистрация
Статьи


   Статьи
   Soft
   Программирование
   Работа компилятора в картинках. Часть вторая

Работа компилятора в картинках. Часть вторая

Добавлено: 30.05.2012

Прочитано: 1724

Как работает компилятор?

Но сначала два слова о техническом моменте: мы думаем, что приводить скриншоты будем только в самом крайнем случае, так как они отвлекают от чтения, а особо ценной информации не несут: вместо них будем использовать укороченные листинги программ из программы Hiew. Если вы ее еще не нашли, самое время это сделать.

А теперь ответы по двум вопросам из первой части: как компилятор TURBO Pascal 7.1 организует хранение массивов:

VAR m: ARRAY [1..9] of INTEGER;
BEGIN
M[1]:=2;
M[2]:=6;
M[3]:=5*3;
M[4]:=5*1;
M[5]:=5*2;
M[8]:=2+2;
M[9]:=M[1]+M[8]-M[2];
END.

05F: mov w,[00050],0002
065: mov w,[00052],0006
06B: mov w,[00054],000F
071: mov w,[00056],0005
077: mov w,[00058],000A
07D: mov w,[0005E],0004
083: mov ax,[00050]
086: add ax,[0005E]
08A: sub ax,[00052]
08E: mov [00060],ax

Комментарии здесь почти не требуются. Видно, что массив располагается последовательно, начиная с ячейки 50, под каждую переменную отводятся два байта. По командам с адреса 6B по 7D видно, что компилятор Паскаля способен вычислять выражения с известными заранее константами. Последнее выражение предсказуемо разбивается на серию команд – мы уже говорили, что в Intel-процессорах обмен с памятью возможен только через регистр. В данном случае, через регистр ax. В компьютерах серии DEC (VAX, LSI-11, PDP-11, ДВК) 80-90-х годов, кстати, была более прогрессивная система команд. Собственно, хуже системы команд и архитектуры Intel найти просто невозможно, но это к слову.

Второй вопрос, оставшийся без рассмотрения, касается последних строк программы:

Xor ax, ax
Call [xxxx]:Смещение_к_концу_программы

Как вы помните, команда xor очищает регистр. Зачем это? Если вы когда-нибудь работали с командными файлами bat в MS-DOS, то знаете, что после окончания программа может сообщить о результате своего завершения, выдав код ошибки: 0 – нормальное завершение, иначе нужно анализировать конкретный код и принимать меры. Вот так: компилятор ничего так просто не делает, все имеет смысл.

Интересно, как Паскаль работает с регистрами, которые объявляются в программе и служат для организации резидентных программ, программ обработчиков прерываний.

Uses
Dos;
Var
R: Registers;
Begin
r.bx:=$CC; r.dx:=$DD; intr($21, r); {такой функции нет, программу не запускать!}
End.

05F: mov w,[00052],00CC
065: mov w,[00056],00DD
06B: mov al,21

Как видно, запись в “регистры” сначала осуществляется в ячейки памяти, затем настраивается вызов функции 21 ОС. Далее, и это не показано, все это записывается в стек, чтобы библиотечная функция сохранила реальные регистры, перезагрузила их, вызвала функцию, восстановила регистры и вернула управление основной программе. Довольно неожиданно – компилятор защищает программу от прямых манипуляций с системой.

Передача параметров в процедуру или функцию – тоже интересная вещь. В частности, направление передачи у Паскаля и Си различаются. Кроме того, паскалевская процедура сама после выполнения работы корректирует вершину стека, а “сишная” программа занимается этим перед вызовом функций.

var
a, b, c, d: integer;

procedure Proc (a, b, c: integer);
begin
d:=a+b+c;
end;

begin
Proc(1,2,3);
writeln(d);
end.

; в Паскале параметры передаются слева направо, т.е. последний будет выше всех в стеке
089: mov ax,0001
08C: push ax
08D: mov ax,0002
090: push ax
091: mov ax,0003
094: push ax
; ближний вызов процедуры; а нам говорили, что это будет похоже на GOTO – ничего подобного!
095: call 00000060

; а вот и сама процедура
060: push bp ; сохранить фрейм стека
061: mov bp,sp ; настроить указатель стека
063: xor ax,ax
065: call 0006:02CD ; интересно, зачем вызывается эта подпрограмма? Пока не знаем.
06A: mov ax,[bp][00008] ; a
06D: add ax,[bp][00006] ; b
070: add ax,[bp][00004] ; c
073: mov [00058],ax ; d:=a+b+c;
076: pop bp
077: retn 0006 ; убрать из стека 6 байтов, занятых нашими переменными

Казалось бы, данный пример не представляет особого интереса, но это не так. Как вы понимаете, на этапе генерации кода порядок записи параметров в стек – единственное, что отличает разные языки и компиляторы. Если изменить порядок и зачистку стека, то различия вызовов подпрограмм исчезают. В той же Windows компиляторы уже давно научились использовать различные стили записи в стек при вызове процедур: в стиле Си, Паскаля и т.д. Подробнее можно почитать в ru.wikipedia.org/wiki/Соглашение_вызова.

В следующей части мы продолжим исследования работы компиляторов.



обновить программы бесплатно

<<  Как работает компилятор? Часть первая. Работа компилятора в картинках. Часть третья  >>


Добавить Комментарий

Скачать программу для проверки на ошибки
Скачать программу автоматического обновления программ
Статьи
Новые Программы
Новые статьи
Популярные Программы
Самые читаемые статьи
Copyright © Дай Прогу 2011 Контакты ¤ Статистика