• XSS.stack #1 – первый литературный журнал от юзеров форума

Статья Серия эксплуатации V8 - часть 3

вавилонец

CPU register
Пользователь
Регистрация
17.06.2021
Сообщения
1 116
Реакции
1 265

V8 Code Base

Введение​

Когда я начал изучать эксплуатацию V8, я думал, что где-нибудь найдется руководство, объясняющее общую структуру кода, по крайней мере, для разработчиков. Я был очень разочарован, когда ничего не смог найти (если вы знаете о чем-то подобном, расскажите, пожалуйста!). К счастью, многие статьи, которые я прочитал, дали мне достаточно информации, чтобы постепенно выработать понимание того, где искать, когда я начал исследовать самостоятельно.

Также есть много комментариев, оставленных командой V8, поэтому я научился находить общую область того, что искал, а затем читать комментарии, пока не доберусь до нужного места. Я также использовал документацию NodeJS V8 , чтобы понять некоторые структуры. Это будет краткий обзор различных папок в src-каталоге с некоторыми возможностями проверить код самостоятельно, чтобы чувствовать себя более комфортно. При этом я могу ошибаться в некоторых аспектах кода. Я очень много работал, чтобы попытаться проверить все в этом посте, но у меня могут быть неверные предположения. Код также, вероятно, изменится, поэтому я попытаюсь говорить о местах в целом, не обращаясь к именам конкретных функций. Если вы заметите какие-либо ошибки, пожалуйста, свяжитесь со мной .

Еще одна вещь, которая действительно помогла мне, — начать с меньшего. Я прошел путь от ничего не зная о движках JS до попыток найти ошибки в одном из самых сложных движков. Как только я сделал шаг назад и попытался посмотреть на другие движки JS, я узнал больше об общих концепциях, которые также присутствуют в V8. В частности, я многое узнал о макетах движка JS через вызовы CTF, связанные с MuJS , который также является открытым исходным кодом .

Installing the Code

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

Отказ от ответственности: они могут измениться/не работать из-за отсутствия зависимостей в вашей среде. Обратитесь к документации V8 за самой последней версией руководства. Эти команды запускались в Ubuntu 20.04.

Код:
# V8 Source
git clone https://chromium.googlesource.com/chromium/tools/depot_tools.git
export PATH=/path/to/depot_tools:$PATH
gclient
mkdir ~/v8
cd ~/v8
fetch v8
cd v8
git pull
gclient sync
tools/dev/gm.py x64.release
tools/dev/gm.py x64.debug

В приведенных выше инструкциях кратко упоминается загрузка Visual Studio. Я настоятельно рекомендую следовать инструкциям здесь для создания вашей установки. Например, я использую VSCode, который позволяет быстро переходить к ссылкам между функциями. Это чрезвычайно полезно для отладки.

Это было бы прекрасное время, чтобы выпить чашечку кофе, потому что сборка займет некоторое время. А пока рекомендую посмотреть эту презентацию ( слайды ), чтобы получить представление о том, как V8 обрабатывает скрипты.
Теперь давайте проверим некоторые из важных папок в v8/src/.


Разбивка по директориям

d8


Локальная компиляция выводит двоичный файл с именем d8 . Это очень легкая оболочка для V8, и она избавляет вас от необходимости создавать свою собственную. Если вы заинтересованы в этом. Как я упоминал в своем последнем посте, V8 обычно встраивается в другое приложение, поэтому нам нужно запустить Isolate, чтобы запустить наш JavaScript. d8 делает это в d8/d8.cc через вызовы API V8 и множество других настроек для REPL. Посмотрев еще немного на весь код в папке, вы увидите ссылки на Fuzzilli , поскольку d8 включает в себя множество функций для поддержки этого фреймворка, а также другие инструменты тестирования, используемые Google. Важно понимать этот двоичный файл, если вы думаете о добавлении поддержки большего количества тестовых систем или о расширении оболочки каким-либо образом.

Кроме того, вы можете получить хороший опыт, запустив двоичный файл d8 под GDB. Например, вы можете пройти через процесс запуска, разбив на mainили установить точки останова на других интересных функциях и использовать обратную трассировку для проверки цепочки вызовов. Он расположен в out/x64.[release||debug]/d8. Обе версии имеют символы, но двоичный файл отладки также позволяет вам видеть исходный код из GDB.

api

Многое происходит, когда мы запускаем Isolate V8. Он должен инициализировать свою кучу, компоненты (такие как Ignition и Turbofan) и все остальное, что необходимо для подготовки среды выполнения. Папка api предоставляет конечные точки для запуска этого процесса, а также другие функции, полезные после запуска.

Согласно документам V8:

API V8 предоставляет функции для компиляции и выполнения сценариев, доступа к методам и структурам данных C++, обработки ошибок и включения проверок безопасности. Ваше приложение может использовать V8 точно так же, как и любую другую библиотеку C++. Ваш код C++ обращается к V8 через V8 API, включая заголовок include/v8.h.

Вот пример из репозитория по использованию V8 для запуска JavaScript из встроенного устройства. Я буду ссылаться на некоторые из этих вызовов API позже.

C++:
// Create a string containing the JavaScript source code.
      v8::Local<v8::String> source =
          v8::String::NewFromUtf8Literal(isolate, "'Hello' + ', World!'");
      // Compile the source code.
      v8::Local<v8::Script> script =
          v8::Script::Compile(context, source).ToLocalChecked();
      // Run the script to get the result.
      v8::Local<v8::Value> result = script->Run(context).ToLocalChecked();
      // Convert the result to an UTF8 string and print it.
      v8::String::Utf8Value utf8(isolate, result);
      printf("%s\n", *utf8);

init/ base


Так как же V8 на самом деле выполняет эти задачи запуска? Большая часть этой функциональности находится в initа также base-папки. init/v8.cc это хорошее место для отслеживания начального пути, по которому V8 запускается. Тем не менее base-папка содержит гораздо больше кода и выполняет большую часть фактической работы по инициализации.

codegen


Когда встраиватель хочет запустить какой-либо JavaScript, он вызывает Compile-функцию API. Папка codegen содержит функционал для использования Ignition или Turbofan для компиляции и возврата указателя на сгенерированный код. Он также отвечает за сбор статистики компиляции и представление этой информации.

execution


Лично я считаю execution.cc было бы хорошим названием для сборщика мусора (глупая шутка, извините). Однако на самом деле это код, отвечающий за запуск скриптов. Встраиватель делает отдельный вызов для запуска кода, созданного в результате компиляции JavaScript. Это означает создание областей памяти для сопоставления исполняемого файла и кода и его выполнения. Если вы хотите отслеживать выполнение на этом шаге, изучите compiler.cc.

interpreter


Как следует из названия, эта папка содержит функции для Ignition; однако обратите внимание, что часть того, что входит в генерацию байт-кода, находится в других местах (например, в синтаксическом анализаторе). interpreter.cc имеет общую логику, но вы можете углубиться в специфику и найти логику для инструкций, выбора регистров, планирования и т. д.
Если вы хотите изучить, как интерпретируется конкретный сценарий, вы, вероятно, захотите использовать некоторые функции отладки, встроенные в d8 (о которых я расскажу в следующем посте). Однако вы можете использовать GDB для просмотра цепочки вызовов, если вы заинтересованы в перехвате определенных частей генерации байт-кода. Здесь я просто сделал обратную трассировку, показывающую, как достигается интерпретатор во время Compile вызов.


1653922467700.png


compiler


Опять же, очень полезна, мы знаем, что это каталог для Turbofan. В моем следующем посте этот код будет более подробно описан.

common

В этой папке есть интересный файл, globals.h, в котором хранятся постоянные значения, связанные с размером различных типов. Многие из них всплывут снова, когда мы будем говорить о Turbofan.

torque/ builtins/ objects


Многие из файлов .tq (torque) расположены в builtinsа также objects-каталоги. Это реализации часто используемых функций, указанных в ECMAScript.

Папка torque отвечает за выполнение действий, перечисленных в документации Torque . Это отдельный двоичный файл, который используется для генерации кода из файлов .tq. Main-функция находится в torque.cc если вам нужно проследить путь выполнения.

flags/ runtime


Папка flags указывает необязательные флаги, которые могут быть переданы в V8, которые вы можете установить с помощью d8. Один флаг, который мы будем часто использовать, это --allow-natives-syntax, что позволит нам вызывать определенные функции из нашего кода JavaScript. V8 имеет много функций runtime, которые удобны для отладки. Они определены в runtime/runtime.cc и реализован в той же папке.

wasm


Честно говоря, у меня нет большого опыта работы с WebAssembly, поскольку это относится к V8. Тем не менее, я почти уверен, что эта папка является компонентом «Liftoff», судя по названию. Мы поговорим об этом подробнее в следующем посте, так как у меня будет возможность изучить его подробнее.

Заключение​

Цель этого поста — познакомить вас с кодовой базой V8, которая может быть ошеломляющей из-за своего размера. Есть еще много, много всего, что можно было бы сказать о коде, но общее представление о том, где находятся компоненты, некоторые важные имена и опыт пошагового выполнения различных функций сделают дальнейшее использование гораздо более удобным для изучения. Как я упоминал ранее, было бы невозможно и ненужно полностью пройтись по коду за раз. Лучший способ действий, когда у вас есть вопрос, — проверить код, обратиться к комментариям или любой документации, установить точку останова на важной функции, посмотреть на обратную трассировку и продолжить. Далее мы начнем использовать некоторые инструменты Google для отладки, чтобы посмотреть на интерпретатор и компилятор



Перевод этой статьи.
 


Напишите ответ...
  • Вставить:
Прикрепить файлы
Верх