Системное программирование.
Работа с памятью.
Для низкоуровневого доступа к памяти можно использовать модуль
era.mem
Code:
function mem.float (ptr, value)
function mem.double (ptr, value)
function mem.i32 (ptr, value)
function mem.i16 (ptr, value)
function mem.i8 (ptr, value)
function mem.u32 (ptr, value)
function mem.u16 (ptr, value)
function mem.u8 (ptr, value)
Указанный набор функций позволяет считывать данные по числовому адресу (если опущен второй аргумент) или записывать (если оба аргумента присутствуют).
i = integer, целочисленный
u = unsigned integer, беззнаковое целое число
Число после символа — размер данных в битах.
float и double позволяют работать с float32 и float64 (числа с плавающей запятой).
Пример
Data\Scripts\test.sys.lua
Code:
local mem = require('era.mem') -- загрузили модуль era.mem и сохранили его в локальной переменной
mem.i32(0x887668, 777) -- записали 777 в v1 как целое 4-байтное число со знаком
local byte = mem.u8(0x401000) -- считали байт по адресу 0x401000
Другие полезные функции:
function mem.addr (ptr)
Преобразовывает адрес в виде ffi.cdata в обычное число. Возвращает обычное число в неизменном виде.
function mem.ptr (ptr)
Преобазовывает адрес или указатель в void*-указатель типа ffi.cdata
function mem.val (ptr)
Принимает адрес или указатель. Возвращает объединение (union) типа ffi.cdata:
Code:
union {
int v;
void* ptr;
float* f32;
double* f64;
int32_t* i32;
uint32_t* u32;
int16_t* i16;
uint16_t* u16;
int8_t* i8;
uint8_t* u8;
char* text;
}
Данное объединение позволяет изменять адрес указателя как обычное число (поле v) и получать типизированные данные по адресу.
Пример.
Code:
local v1 = mem.val(0x887668)
v1.f32[0] = 3.14 -- записали в v1 (адрес ЕРМ-переменной) число 3.14 ординарной точности
Доступен метод :str, аналогичный mem.str, позволяющий трактовать объединение как строку.
Code:
v1:str('Hi!') -- записывать в первые байты переменной v1 значение 'Hi'\0
function mem.ofs (ptr, offset)
По адресу/указателю и смещению возвращает новый адрес типа void*.
Пример: mem.ofs(0x400000, 0x1000)
function mem.str (ptr, str, bufSize)
Читает или записывает строку по адресу
ptr. Последний аргумент — опциональный размер буфера, отведённый под строку.
Пример.
Code:
local text = mem.str(0x500000) -- прочитать нуль-терминированную строку по адресу 0x500000
mem.str(0x500000, 'Привет, мир', 4) -- записать строку 'При'\0 по тому же адресу, ограничить размер буфера 4-мя символами, включая #0
Для удобства и повышения скорости работы модуль предоставляет готовые псевдонимы для популярных типов данных языка C:
Code:
mem.pvoid = ffi.typeof('void*')
mem.pchar = ffi.typeof('char*');
mem.intptr = ffi.typeof('intptr_t')
mem.pfloat = ffi.typeof('float*')
mem.pdouble = ffi.typeof('double*')
mem.pi32 = ffi.typeof('int32_t*')
mem.pi16 = ffi.typeof('int16_t*')
mem.pi8 = ffi.typeof('int8_t*')
mem.pu32 = ffi.typeof('uint32_t*')
mem.pu16 = ffi.typeof('uint16_t*')
mem.pu8 = ffi.typeof('uint8_t*')