[Урок] Трансляция программного кода, Байт-код SourcePawn

Kailo

Участник
Сообщения
168
Реакции
755
Дисклеймер: содержание данного урока не претендует на научную достоверность и выражает моё субъективное виденье.

История развития языков программирования и трансляции кода
Начнём раскладывать все по полочкам.
Для начала я должен рассказать о процессе трансляции, что бы у вас возникло представление откуда и зачем
берется этот байт-код и как и кем он используется. Сейчас я применил термин трансляция - преобразование программы
из одного языка программирования в другой.
Зачем же это нам нужно и что я имею ввиду? Если вы подумали про перевод SourcePawn в C++, то нет, это не об этом.

Мозг ЭВМ - процессор, который знает только один язык программирования - машинный код. Есть много разных процессоров,
различных по устройству, принципам работы и производителям. Так что, машинный код, это не один конкретный язык,
а множество языков процессорного уровня. В этом случае, «Язык», даже "громко" сказано. Это набор инструкций для
выполнения на процессоре, т.е. машинный код это набор инструкций записываемых числами. При этом как было сказано,
у разных процессоров это свой набор. Было бы вам удобно запоминать, что к примеру 73 производит сложение чисел,
а 82 вычитание: уверен, нет. Тут надо сделать оговорку, что не прям у каждого процессора этот набор индивидуален.
У процессоров выделяют архитектурную платформу, определяемую в частности архитектурой набора команд (включает в себя
понятие машинного кода). Уверен вы могли слышать о одной из них - x86-64 и наверное процессор именно этой архитектуры
стоит у вас дома в ПК.

Вот и обуславливается наши проблемы. Писать программы на машинном коде сложно, не удобно и не читабельно, так же
под каждый процессор надо писать используя свой набор команд, а выражения имеют мало общего с человеческими
представлениями о логики и мысли. Для борьбы с этими недостатками изобретались другие более совершенные языки.
Т.к. мы, люди, привыкли разговаривать, и нам ближе слова, чем цифры, то были изобретены языки ассемблера, в них числа были
заменены, используя методы мнемоники, на слова.
("Для обозначения машинных команд обычно применяется мнемоническое обозначение. Это позволяет запоминать команды
не в виде последовательности двоичных нулей и единиц, а в виде осмысленных сокращений слов человеческого языка (обычно английских)." - Википедия).
Опять же важно понимать, что это не один язык, а множество, каждый из которых предназначен для своей архитектуры.
С ассемблером появились первые программы трансляторы, для перевода с ассемблера на машинный код
(тогда это так еще не выделяли наверно, т.к. даже assembler переводится как сборщик, но мы все таки говорим о современных представлениях).
С языками ассемблера стало возможным выражать значения строками, что и привело к появлению переменных и констант, вместо прямого указания адреса.
Но то, о чем я ранее говорил, называется языками низкого уровня.

Стремясь приблизить код к более мысли-подобному виду появились языки высокого уровня. Если раньше мы делали условные
переходы выполнения от одной части кода к другой, то теперь мы представляем себе это как условные операторы в более понятном нам виде и д.р.
Теперь же нам требуется написать программу для трансляции кода с языка высокого уровня в машинный код, понятный процессору.
Трансляторы классифицируют следующим образом:
компиляторы - переводят программу в машинный код без её непосредственного выполнения, сохраняя результат в виде файла;
интерпретаторы - переводящие программу в машинный код, которой сразу же исполняется.​
Языки высокого уровня так же позволили уйти от зависимости от конкретной платформы. Эта зависимость теперь стала определятся
в требовании собственного компилятора языка под каждую платформу, а так же компиляции программы отдельно для каждой архитектуры.

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

Если кто-то подробнее желает вникнуть в тему, вот вам набор ссылок:
Транслятор — Википедия
Байт-код — Википедия
Виртуальная машина — Википедия

SourcePawn использует JIT-компиляцию.
Код сначала компилируется из языка высокого уровня в байт-код, называемый OP-code (или opcode) (в *.smx он содержится в .code секции),
а далее путем интерпретации виртуальной машиной в машинный код исполняется.

Дальнейшая часть урока тесно связана с другим уроком - Виртуальная машина SourcePawn (еще не написан).

Пример исходного кода (randomcycle.sp) и байткода созданного на его основе:
PHP:
public void OnPluginStart()
{
    int arraySize = ByteCountToCells(PLATFORM_MAX_PATH);
    g_MapList = new ArrayList(arraySize);
    g_OldMapList = new ArrayList(arraySize);
    g_Cvar_ExcludeMaps = CreateConVar("sm_randomcycle_exclude", "5", "Specifies how many past maps to exclude from the vote.", _, true, 0.0);
    AutoExecConfig(true, "randomcycle");
}
Код:
// Число в начале, адрес
3008: proc
3012: break
3016: break
3020: stack -4
3028: push2.c 256 1
3040: call 2920
3048: stor.s.pri -4
3056: break
3060: push.c 0
3068: push.s -4
3076: sysreq.n 2 2
3088: stor.pri 2348
3096: break
3100: push.c 0
3108: push.s -4
3116: sysreq.n 2 2
3128: stor.pri 2352
3136: break
3140: push5.c 0 0 0 1 0
3164: push3.c 2388 2384 2360
3180: sysreq.n 3 8
3192: stor.pri 2344
3200: break
3204: push3.c 2456 2444 1
3220: sysreq.n 4 3
3232: stack 4
3240: zero.pri
3244: retn
Описание инструкций байт-кода SourcePawn:
Список "опкодов" можно найти в исходниках компилятора:
sourcepawn/sc6.cpp at master · alliedmodders/sourcepawn · GitHub
а понять что они делают (пока еще я сам это не расписал ниже словами), из кода виртуальной машины SP
sourcepawn/interpreter.cpp at master · alliedmodders/sourcepawn · GitHub
 
Последнее редактирование:
Сверху