Доброго времени суток.
Довольно давно имелось желание написать эмулятор какого-нибудь процессора.
А что может быть лучше, чем изобрести велосипед?
Имя велосипеду — V16, от склеивания слова Virtual и, собственно, разрядности.

Типизированный язык программирования
Доброго времени суток.
Довольно давно имелось желание написать эмулятор какого-нибудь процессора.
А что может быть лучше, чем изобрести велосипед?
Имя велосипеду — V16, от склеивания слова Virtual и, собственно, разрядности.
#include <stdio.h>
void main() {
printf("Hello World!\n");
}
Очередной пользователь хочет записать на жесткий диск новый кусок данных, но ему не хватает свободного места для этого. Удалять тоже ничего не хочется, так как "все очень важное и нужное". И что нам с ним делать?
Такая проблема встает ни у него одного. На наших жестких дисках покоятся терабайты информации, и это количество не стремится уменьшаться. Но насколько она уникальна? В конце-концов, ведь все файлы это лишь наборы бит определенной длины и, скорее всего, новая не сильно отличается от той, что уже хранится.
Понятное дело, что искать уже хранящиеся куски информации на жестком диске — задача если не провальная, то как минимум не эффективная. С другой стороны, ведь если разница небольшая, то можно немного и подогнать...
TL;DR — вторая попытка рассказать о странном методе оптимизации данных с помощью JPEG-файлов, теперь в более понятной форме.
Участвовал я недавно в разработке нетипичного для меня девайса из класса потребительской электроники. Вроде ничего сложного, коробка, которая должна иногда выходить из спящего режима, отчитываться серверу и засыпать обратно.
Практика быстро показала, что отладчик не слишком помогает при работе с микроконтроллером, который постоянно уходит в режим глубокого сна или вырубает себе питание. В основном, потому что коробка в тестовом режиме стояла без отладчика и без меня рядом и иногда глючила. Примерно раз в несколько суток.
На соплях был прикручен отладочный UART, в который я стал выводить логи. Стало легче, часть проблем решилась. Но потом случился assert и все завертелось.
В предыдущей части я приблизительно описал, как можно загрузить eBPF функции из ELF-файла. Теперь пришла пора перейти от фэнтези к советским мультикам, и следуя мудрому совету, потратив один раз некоторое количество усилий, сделать универсальный инструмент инструментации (или, сокращённо, УИИ!!!). При этом я воспользуюсь антипаттерном проектирования «Золотой молоток» и сооружу инструмент из относительно знакомого мне QEMU. Бонусом за это мы получим кросс-архитектурную инструментацию, а также инструментацию на уровне целого виртуального компьютера. Инструментация будет вида «небольшой нативный so-шничек + небольшой .o-файл с eBPF». При этом eBPF-функции будут подставляться перед соответствующими инструкциями внутреннего представления QEMU перед оптимизацией и кодогенерацией.
В итоге сама инструментация, добавляемая при кодогенерации (то есть, не считая пары килобайтов обычного сишного рантайма), выглядит вот так, и это не псевдокод:
#include <stdint.h>
extern uint8_t *__afl_area_ptr;
extern uint64_t prev;
void inst_qemu_brcond_i64(uint64_t tag, uint64_t x, uint64_t y, uint64_t z, uint64_t u)
{
__afl_area_ptr[((prev >> 1) ^ tag) & 0xFFFF] += 1;
prev = tag;
}
void inst_qemu_brcond_i32(uint64_t tag, uint64_t x, uint64_t y, uint64_t z, uint64_t u)
{
__afl_area_ptr[((prev >> 1) ^ tag) & 0xFFFF] += 1;
prev = tag;
}
Что же, пора загрузить нашего эльфа в Матрицу. Ну, как загрузить, скорее вмазать распылить.
Внимание: содержит системное программирование. Да, в сущности, ничего другого и не содержит.
Давайте представим, что вам дали задание написать фэнтезийно-фантастическую игру. Ну там про эльфов. И про виртуальную реальность. Вы с детства мечтали написать что-нибудь эдакое и, не раздумывая, соглашаетесь. Вскоре вы понимаете, что о мире эльфов вы знаете по большей части из анекдотов со старого башорга и прочих разрозненных источников. Упс, неувязочка. Ну, где наша не пропадала… Наученный богатым программистским опытом, вы отправляетесь в Гугл, вводите «Elf specification» и идёте по ссылкам. О! Вот эта ведёт на какую-то PDF-ку… так, что тут у нас… какой-то Elf32_Sword
— эльфийские мечи — похоже, то что нужно. 32 — это, по-видимому, уровень персонажа, а две четвёрки в следующих столбцах — это урон, наверное. Точно то, что нужно, да к тому же как систематизировано!..
Когда-то давно я смеха ради решил доказать обратимость процесса и научиться генерировать JavaScript (а точнее, Asm.js) из машинного кода. Для эксперимента был выбран QEMU, некоторое время спустя была написана статья на Хабр. В комментариях мне посоветовали переделать проект на WebAssembly, да и самому бросать почти законченный проект как-то не хотелось… Работа шла, но уж очень медленно, и вот, недавно в той статье появился комментарий на тему «Так и чем всё закончилось?». На мой развёрнутый ответ я услышал «Это тянет на статью». Ну, раз тянет, то будет статья. Может, кому пригодится. Из неё читатель узнает некоторые факты про устройство бекендов кодогенерации QEMU, а также как написать Just-in-Time компилятор для веб-приложения.
extern
с неопределёнными границами, например:extern int external_array[];
int
array_get (long int index)
{
return external_array[index];
}
int external_array[3] = { 1, 2, 3 };
int external_array[4] = { 1, 2, 3, 4 };
int external_array[2] = { 1, 2 };
В MSDN'овской статье Process Security and Access Rights есть интересная ремарка:
… if process A has a handle to process B with PROCESS_DUP_HANDLE access, it can duplicate the pseudo handle for process B. This creates a handle that has maximum access to process B.
Если вольно перевести это на русский, то тут говорится, что имея описатель на процесс с правом доступа PROCESS_DUP_HANDLE мы можем, используя функцию DuplicateHandle(...), получить описатель с максимально разрешенными масками доступа на этот процесс.