Запись VM - хорошо сформированный байт-код?

Я пишу виртуальную машину в C только для забавы. Ламе, я знаю, но к счастью я иду Так себе, надо надеяться, никто не сделает забаву :)

Я записал действительно quick'n'dirty VM, который читает строки (мое собственное) ASM и действительно наполняет. Прямо сейчас у меня только есть 3 инструкции: add, jmp, end. Все хорошо, и это - на самом деле довольно прохладная способность к линиям питания (выполнение его что-то как write_line(&prog[1], "jmp", regA, regB, 0); и затем запущение программы:

while (machine.code_pointer <= BOUNDS && DONE != true)
{
    run_line(&prog[machine.cp]);
}

Я использую справочную таблицу кода операции (который не может быть эффективным, но это изящно) в C, и все, кажется, работает хорошо.

Моим вопросом является больше вопроса "о лучших практиках", но я действительно думаю, что существует корректный ответ на него. Я делаю способное VM для чтения двоичных файлов (хранящий байты в unsigned char[]) и выполните байт-код. Мой вопрос: действительно ли это - задание VM, чтобы удостовериться, что байт-код хорошо формируется, или это - просто задание компилятора для проверки двоичного файла, который это выкладывает, хорошо формируется?

Я только спрашиваю это потому что, что произошло бы, если кто-то отредактирует двоичный файл и завинтит материал (удаляют произвольные части его, и т.д.). Очевидно, программа была бы багги и вероятно не функциональная. Это - даже проблема VM? Я уверен, что люди, намного более умные, чем я, выяснили решения этих проблем, мне просто любопытно, каковы они!

8
задан Seki 12 June 2015 в 11:25
поделиться

5 ответов

Это работа виртуальной машины, чтобы убедиться, что байт-код правильно сформирован, или это просто задача компилятора, чтобы убедиться, что двоичный файл, который она выводит, правильно сформирован ?

Вам решать.

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

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

15
ответ дан 5 December 2019 в 08:22
поделиться

Виртуальные машины, интерпретирующие байт-код, обычно имеют какой-то способ проверки своего ввода; например, Java выдаст VerifyError, если файл класса находится в несогласованном состоянии

. Однако похоже, что вы реализуете процессор, а поскольку они имеют тенденцию быть более низкого уровня, у вас меньше способов получить что-то в обнаруживаемом недопустимом состоянии - один из очевидных способов - присвоить ему неопределенный код операции. Реальные процессоры будут сигнализировать о том, что процесс попытался выполнить недопустимую инструкцию, и ОС обработает ее (например, Linux убивает ее с помощью SIGILL)

2
ответ дан 5 December 2019 в 08:22
поделиться

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

В вашем случае, если ваш домашний язык не станет популярным и популярным, аспект безопасности - это то, о чем вам не нужно так сильно беспокоиться; в конце концов, кто будет взламывать ваши программы, кроме вас? Тем не менее, я бы сказал, что было бы неплохо убедиться, что ваша виртуальная машина, по крайней мере, имеет разумную стратегию отказа, когда байт-код недействителен. Как минимум, если он обнаруживает что-то, чего не понимает и не может обработать, он должен это обнаружить и вывести сообщение об ошибке, что упростит отладку с вашей стороны.

2
ответ дан 5 December 2019 в 08:22
поделиться

Имеет смысл, чтобы компилятор выполнял как можно больше проверок работоспособности (поскольку он должен сделать это только один раз), но всегда будут проблемы, которые не могут быть обнаружены статическим анализом, такие как [кашель] стек переполнение, ошибки диапазона массива и т.п.

0
ответ дан 5 December 2019 в 08:22
поделиться

Я бы сказал, что ваша виртуальная машина разрешает эмулируемый процессор загорится, пока сама реализация виртуальной машины не выйдет из строя. Как разработчик виртуальной машины вы можете устанавливать правила. Но если вы хотите, чтобы компании, производящие виртуальное оборудование, виртуально покупали ваш виртуальный чип, вам придется сделать что-то более прощающее ошибки: хорошие варианты могут заключаться в создании исключения (труднее реализовать) или сбросе процессора (намного проще). Или, может быть, вы просто определяете каждый код операции как действительный, за исключением того, что некоторые из них «недокументированы» - они делают что-то неопределенное, кроме сбоя вашей реализации. Обоснование: если (!) Ваша реализация виртуальной машины должна запускать несколько экземпляров гостя одновременно, было бы очень плохо, если бы один гость мог вызвать сбой других.

0
ответ дан 5 December 2019 в 08:22
поделиться
Другие вопросы по тегам:

Похожие вопросы: