Skip to content

Instantly share code, notes, and snippets.

@elct9620
Created August 14, 2021 12:43
Show Gist options
  • Save elct9620/6d54a301728010fe11681e27c619b110 to your computer and use it in GitHub Desktop.
Save elct9620/6d54a301728010fe11681e27c619b110 to your computer and use it in GitHub Desktop.
RubyKaigi 2021 Takeout - mruby VM demo
#include <stdint.h>
#include <stdio.h>
#include <string.h>
static inline uint32_t
bin_to_uint32(const uint8_t *bin)
{
return (uint32_t)bin[0] << 24 |
(uint32_t)bin[1] << 16 |
(uint32_t)bin[2] << 8 |
(uint32_t)bin[3];
}
static inline uint16_t
bin_to_uint16(const uint8_t *bin)
{
return (uint16_t)bin[0] << 8 |
(uint16_t)bin[1];
}
static size_t skip_padding(const uint8_t* buf) {
const size_t align = sizeof(uint32_t);
return -(intptr_t)buf & (align - 1);
}
const uint8_t* irep_get_symbol(const uint8_t* p, int n) {
// SKIP IREP HEADER / ISEQ
p += 10;
uint32_t length = bin_to_uint32(p);
p += 4;
p += skip_padding(p);
p += length;
// SKIP POOL
{
uint32_t npool = bin_to_uint32(p);
p += 4;
for(int i = 0; i < npool; i++) {
uint8_t vtype = *p;
p++;
uint16_t len = bin_to_uint16(p);
p += 2;
p += len + 1; // End with null byte
}
}
// Find in SYM
{
uint32_t nsym = n;
p += 4;
for (int i = 0; i < nsym; i++) {
uint16_t len = bin_to_uint16(p);
p += len + 1; // End with null byte
}
return p + 2; // Skip length
}
return p;
}
enum {
OP_NOP,
OP_LOADI__1 = 5,
OP_LOADI_0,
OP_LOADI_1,
OP_LOADI_2,
OP_LOADI_3,
OP_LOADI_4,
OP_LOADI_5,
OP_LOADI_6,
OP_LOADI_7,
OP_LOADSELF = 16,
OP_SEND = 46,
OP_RETURN = 55,
OP_ADD = 59,
OP_ADDI,
};
int main(int argc, char** argv) {
printf("Read: %s\n", argv[1]);
FILE *fp = fopen(argv[1], "r");
fseek(fp, 0, SEEK_END);
size_t size = ftell(fp);
fseek(fp, 0, SEEK_SET);
uint8_t binary[size];
fread(binary, sizeof(uint8_t), size, fp);
const uint8_t* bin = binary;
const uint8_t* data = binary;
// RITE
bin += 34;
data += 34;
// Record Size
bin += 4;
// Local Variables
uint16_t nlocals = bin_to_uint16(bin);
bin += 2;
uint16_t nregs = bin_to_uint16(bin);
bin += 2;
uint16_t nirep = bin_to_uint16(bin);
bin += 2;
uint32_t niseq = bin_to_uint32(bin);
bin += 4;
bin += skip_padding(bin);
printf("nregs=%d nlocals=%d iseq=%d\n", nregs, nlocals, niseq);
// Create Register
intptr_t reg[nregs - 1];
// Temp Variable
int32_t a = 0;
int32_t b = 0;
int32_t c = 0;
for(;;) {
uint8_t opcode = *bin++;
switch(opcode) {
case OP_NOP:
break;
case OP_LOADI_0:
case OP_LOADI_1:
case OP_LOADI_2:
case OP_LOADI_3:
case OP_LOADI_4:
case OP_LOADI_5:
case OP_LOADI_6:
case OP_LOADI_7:
a = *bin++;
reg[a] = opcode - OP_LOADI_0;
break;
case OP_ADDI:
a = *bin++; b = *bin++;
reg[a] += b;
break;
case OP_LOADSELF:
// Create Call Stack
a = *bin++;
break;
case OP_SEND:
a = *bin++;
b = *bin++;
c = *bin++;
const char* fn = (const char*)irep_get_symbol(data, b);
if(strcmp(fn, "c_add") == 0) {
int sum = 0;
// Sum Arguments
for(int i = 1; i <= c; i++) {
sum += reg[a + i];
}
// Save to return value
reg[a] = sum;
} else {
// Undefiend Method
printf("Undefined Method\n");
return 1;
}
break;
case OP_RETURN:
a = *bin++;
printf("Result: %ld\n", reg[a]);
return 0;
default:
printf("Unsuport OPCODE = %d\n", opcode);
return 1;
}
}
fclose(fp);
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment