Skip to content

Commit

Permalink
allow endian specification of mrb files by mrbc -e/-E
Browse files Browse the repository at this point in the history
`mruby -b` now accepts both big/little endian mrb (compiled binary) files.

`mrbc` generates mrb files in big endian for .mrb files and in native endian
for C files (with -B option specified) by default.  If you are cross compiling,
you need to specify target endian by -e/-E options if it is different from
host endian.
  • Loading branch information
matz committed Feb 2, 2015
1 parent 089f1f6 commit bc9c47d
Show file tree
Hide file tree
Showing 4 changed files with 180 additions and 68 deletions.
57 changes: 47 additions & 10 deletions include/mruby/dump.h
Expand Up @@ -14,10 +14,16 @@ extern "C" {
#include "mruby.h" #include "mruby.h"
#include "mruby/irep.h" #include "mruby/irep.h"


int mrb_dump_irep(mrb_state *mrb, mrb_irep *irep, int debug_info, uint8_t **bin, size_t *bin_size); #define DUMP_DEBUG_INFO 1
#define DUMP_ENDIAN_BIG 2
#define DUMP_ENDIAN_LIL 4
#define DUMP_ENDIAN_NAT 6
#define DUMP_ENDIAN_MASK 6

int mrb_dump_irep(mrb_state *mrb, mrb_irep *irep, uint8_t flags, uint8_t **bin, size_t *bin_size);
#ifdef ENABLE_STDIO #ifdef ENABLE_STDIO
int mrb_dump_irep_binary(mrb_state*, mrb_irep*, int, FILE*); int mrb_dump_irep_binary(mrb_state*, mrb_irep*, uint8_t, FILE*);
int mrb_dump_irep_cfunc(mrb_state *mrb, mrb_irep*, int, FILE *f, const char *initname); int mrb_dump_irep_cfunc(mrb_state *mrb, mrb_irep*, uint8_t flags, FILE *f, const char *initname);
mrb_irep *mrb_read_irep_file(mrb_state*, FILE*); mrb_irep *mrb_read_irep_file(mrb_state*, FILE*);
MRB_API mrb_value mrb_load_irep_file(mrb_state*,FILE*); MRB_API mrb_value mrb_load_irep_file(mrb_state*,FILE*);
MRB_API mrb_value mrb_load_irep_file_cxt(mrb_state*, FILE*, mrbc_context*); MRB_API mrb_value mrb_load_irep_file_cxt(mrb_state*, FILE*, mrbc_context*);
Expand All @@ -42,25 +48,26 @@ MRB_API mrb_irep *mrb_read_irep(mrb_state*, const uint8_t*);
#define MRB_DUMP_NULL_SYM_LEN 0xFFFF #define MRB_DUMP_NULL_SYM_LEN 0xFFFF


/* Rite Binary File header */ /* Rite Binary File header */
#define RITE_BINARY_IDENTIFIER "RITE" #define RITE_BINARY_IDENT "RITE"
#define RITE_BINARY_IDENT_LIL "ETIR"
#define RITE_BINARY_FORMAT_VER "0003" #define RITE_BINARY_FORMAT_VER "0003"
#define RITE_COMPILER_NAME "MATZ" #define RITE_COMPILER_NAME "MATZ"
#define RITE_COMPILER_VERSION "0000" #define RITE_COMPILER_VERSION "0000"


#define RITE_VM_VER "0000" #define RITE_VM_VER "0000"


#define RITE_BINARY_EOF "END\0" #define RITE_BINARY_EOF "END\0"
#define RITE_SECTION_IREP_IDENTIFIER "IREP" #define RITE_SECTION_IREP_IDENT "IREP"
#define RITE_SECTION_LINENO_IDENTIFIER "LINE" #define RITE_SECTION_LINENO_IDENT "LINE"
#define RITE_SECTION_DEBUG_IDENTIFIER "DBG\0" #define RITE_SECTION_DEBUG_IDENT "DBG\0"
#define RITE_SECTION_LV_IDENTIFIER "LVAR" #define RITE_SECTION_LV_IDENT "LVAR"


#define MRB_DUMP_DEFAULT_STR_LEN 128 #define MRB_DUMP_DEFAULT_STR_LEN 128
#define MRB_DUMP_ALIGNMENT sizeof(uint32_t) #define MRB_DUMP_ALIGNMENT sizeof(uint32_t)


/* binary header */ /* binary header */
struct rite_binary_header { struct rite_binary_header {
uint8_t binary_identify[4]; /* Binary Identifier */ uint8_t binary_ident[4]; /* Binary Identifier */
uint8_t binary_version[4]; /* Binary Format Version */ uint8_t binary_version[4]; /* Binary Format Version */
uint8_t binary_crc[2]; /* Binary CRC */ uint8_t binary_crc[2]; /* Binary CRC */
uint8_t binary_size[4]; /* Binary Size */ uint8_t binary_size[4]; /* Binary Size */
Expand All @@ -70,7 +77,7 @@ struct rite_binary_header {


/* section header */ /* section header */
#define RITE_SECTION_HEADER \ #define RITE_SECTION_HEADER \
uint8_t section_identify[4]; \ uint8_t section_ident[4]; \
uint8_t section_size[4] uint8_t section_size[4]


struct rite_section_header { struct rite_section_header {
Expand Down Expand Up @@ -101,6 +108,17 @@ struct rite_binary_footer {
RITE_SECTION_HEADER; RITE_SECTION_HEADER;
}; };


static inline int
bigendian_p()
{
int i;
char *p;

i = 1;
p = (char*)&i;
return p[0]?0:1;
}

static inline size_t static inline size_t
uint8_to_bin(uint8_t s, uint8_t *bin) uint8_to_bin(uint8_t s, uint8_t *bin)
{ {
Expand All @@ -126,6 +144,16 @@ uint32_to_bin(uint32_t l, uint8_t *bin)
return sizeof(uint32_t); return sizeof(uint32_t);
} }


static inline size_t
uint32l_to_bin(uint32_t l, uint8_t *bin)
{
bin[3] = (l >> 24) & 0xff;
bin[2] = (l >> 16) & 0xff;
bin[1] = (l >> 8) & 0xff;
bin[0] = l & 0xff;
return sizeof(uint32_t);
}

static inline uint32_t static inline uint32_t
bin_to_uint32(const uint8_t *bin) bin_to_uint32(const uint8_t *bin)
{ {
Expand All @@ -135,6 +163,15 @@ bin_to_uint32(const uint8_t *bin)
(uint32_t)bin[3]; (uint32_t)bin[3];
} }


static inline uint32_t
bin_to_uint32l(const uint8_t *bin)
{
return (uint32_t)bin[3] << 24 |
(uint32_t)bin[2] << 16 |
(uint32_t)bin[1] << 8 |
(uint32_t)bin[0];
}

static inline uint16_t static inline uint16_t
bin_to_uint16(const uint8_t *bin) bin_to_uint16(const uint8_t *bin)
{ {
Expand Down
122 changes: 90 additions & 32 deletions src/dump.c
Expand Up @@ -80,14 +80,25 @@ write_iseq_block(mrb_state *mrb, mrb_irep *irep, uint8_t *buf, uint8_t flags)


cur += uint32_to_bin(irep->ilen, cur); /* number of opcode */ cur += uint32_to_bin(irep->ilen, cur); /* number of opcode */
cur += write_padding(cur); cur += write_padding(cur);
if (flags & FLAG_BYTEORDER_NATIVE) { switch (flags & DUMP_ENDIAN_NAT) {
memcpy(cur, irep->iseq, irep->ilen * sizeof(mrb_code)); case DUMP_ENDIAN_BIG:
cur += irep->ilen * sizeof(mrb_code); if (bigendian_p()) goto native;
}
else {
for (iseq_no = 0; iseq_no < irep->ilen; iseq_no++) { for (iseq_no = 0; iseq_no < irep->ilen; iseq_no++) {
cur += uint32_to_bin(irep->iseq[iseq_no], cur); /* opcode */ cur += uint32_to_bin(irep->iseq[iseq_no], cur); /* opcode */
} }
break;
case DUMP_ENDIAN_LIL:
if (!bigendian_p()) goto native;
for (iseq_no = 0; iseq_no < irep->ilen; iseq_no++) {
cur += uint32l_to_bin(irep->iseq[iseq_no], cur); /* opcode */
}
break;

native:
case DUMP_ENDIAN_NAT:
memcpy(cur, irep->iseq, irep->ilen * sizeof(mrb_code));
cur += irep->ilen * sizeof(mrb_code);
break;
} }


return cur - buf; return cur - buf;
Expand Down Expand Up @@ -323,7 +334,7 @@ write_footer(mrb_state *mrb, uint8_t *bin)
{ {
struct rite_binary_footer footer; struct rite_binary_footer footer;


memcpy(footer.section_identify, RITE_BINARY_EOF, sizeof(footer.section_identify)); memcpy(footer.section_ident, RITE_BINARY_EOF, sizeof(footer.section_ident));
uint32_to_bin(sizeof(struct rite_binary_footer), footer.section_size); uint32_to_bin(sizeof(struct rite_binary_footer), footer.section_size);
memcpy(bin, &footer, sizeof(struct rite_binary_footer)); memcpy(bin, &footer, sizeof(struct rite_binary_footer));


Expand All @@ -336,7 +347,7 @@ write_section_irep_header(mrb_state *mrb, size_t section_size, uint8_t *bin)
{ {
struct rite_section_irep_header *header = (struct rite_section_irep_header*)bin; struct rite_section_irep_header *header = (struct rite_section_irep_header*)bin;


memcpy(header->section_identify, RITE_SECTION_IREP_IDENTIFIER, sizeof(header->section_identify)); memcpy(header->section_ident, RITE_SECTION_IREP_IDENT, sizeof(header->section_ident));


mrb_assert_int_fit(size_t, section_size, uint32_t, UINT32_MAX); mrb_assert_int_fit(size_t, section_size, uint32_t, UINT32_MAX);
uint32_to_bin((uint32_t)section_size, header->section_size); uint32_to_bin((uint32_t)section_size, header->section_size);
Expand Down Expand Up @@ -373,7 +384,7 @@ write_section_lineno_header(mrb_state *mrb, size_t section_size, uint8_t *bin)
{ {
struct rite_section_lineno_header *header = (struct rite_section_lineno_header*)bin; struct rite_section_lineno_header *header = (struct rite_section_lineno_header*)bin;


memcpy(header->section_identify, RITE_SECTION_LINENO_IDENTIFIER, sizeof(header->section_identify)); memcpy(header->section_ident, RITE_SECTION_LINENO_IDENT, sizeof(header->section_ident));
uint32_to_bin((uint32_t)section_size, header->section_size); uint32_to_bin((uint32_t)section_size, header->section_size);


return MRB_DUMP_OK; return MRB_DUMP_OK;
Expand Down Expand Up @@ -664,7 +675,7 @@ write_section_debug(mrb_state *mrb, mrb_irep *irep, uint8_t *cur, mrb_sym const
dlen = write_debug_record(mrb, irep, cur, filenames, filenames_len); dlen = write_debug_record(mrb, irep, cur, filenames, filenames_len);
section_size += dlen; section_size += dlen;


memcpy(header->section_identify, RITE_SECTION_DEBUG_IDENTIFIER, sizeof(header->section_identify)); memcpy(header->section_ident, RITE_SECTION_DEBUG_IDENT, sizeof(header->section_ident));
mrb_assert(section_size <= INT32_MAX); mrb_assert(section_size <= INT32_MAX);
uint32_to_bin(section_size, header->section_size); uint32_to_bin(section_size, header->section_size);


Expand Down Expand Up @@ -803,7 +814,7 @@ write_section_lv(mrb_state *mrb, mrb_irep *irep, uint8_t *start, mrb_sym const *
goto lv_section_exit; goto lv_section_exit;
} }


memcpy(header->section_identify, RITE_SECTION_LV_IDENTIFIER, sizeof(header->section_identify)); memcpy(header->section_ident, RITE_SECTION_LV_IDENT, sizeof(header->section_ident));


diff = cur - start; diff = cur - start;
mrb_assert_int_fit(ptrdiff_t, diff, size_t, SIZE_MAX); mrb_assert_int_fit(ptrdiff_t, diff, size_t, SIZE_MAX);
Expand All @@ -820,19 +831,23 @@ write_rite_binary_header(mrb_state *mrb, size_t binary_size, uint8_t *bin, uint8
uint16_t crc; uint16_t crc;
uint32_t offset; uint32_t offset;


if (flags & FLAG_BYTEORDER_NATIVE) { switch (flags & DUMP_ENDIAN_NAT) {
uint32_t ident = 0; default:
size_t i; endian_big:

case DUMP_ENDIAN_BIG:
for(i=0; i<sizeof(ident); i++) { memcpy(header->binary_ident, RITE_BINARY_IDENT, sizeof(header->binary_ident));
ident<<=8; break;
ident|=RITE_BINARY_IDENTIFIER[i]; endian_little:
} case DUMP_ENDIAN_LIL:
memcpy(header->binary_identify, (char*)&ident, sizeof(uint32_t)); memcpy(header->binary_ident, RITE_BINARY_IDENT_LIL, sizeof(header->binary_ident));
} break;
else {
memcpy(header->binary_identify, RITE_BINARY_IDENTIFIER, sizeof(header->binary_identify)); case DUMP_ENDIAN_NAT:
if (bigendian_p()) goto endian_big;
goto endian_little;
break;
} }

memcpy(header->binary_version, RITE_BINARY_FORMAT_VER, sizeof(header->binary_version)); memcpy(header->binary_version, RITE_BINARY_FORMAT_VER, sizeof(header->binary_version));
memcpy(header->compiler_name, RITE_COMPILER_NAME, sizeof(header->compiler_name)); memcpy(header->compiler_name, RITE_COMPILER_NAME, sizeof(header->compiler_name));
memcpy(header->compiler_version, RITE_COMPILER_VERSION, sizeof(header->compiler_version)); memcpy(header->compiler_version, RITE_COMPILER_VERSION, sizeof(header->compiler_version));
Expand Down Expand Up @@ -872,8 +887,23 @@ is_lv_defined(mrb_irep *irep)
return FALSE; return FALSE;
} }


static uint8_t
dump_flags(uint8_t flags, uint8_t native)
{
if (native == FLAG_BYTEORDER_NATIVE) {
if ((flags & DUMP_ENDIAN_NAT) == 0) {
return (flags & DUMP_DEBUG_INFO) | DUMP_ENDIAN_NAT;
}
return flags;
}
if ((flags & DUMP_ENDIAN_NAT) == 0) {
return (flags & DUMP_DEBUG_INFO) | DUMP_ENDIAN_BIG;
}
return flags;
}

static int static int
dump_irep(mrb_state *mrb, mrb_irep *irep, int debug_info, uint8_t **bin, size_t *bin_size, uint8_t flags) dump_irep(mrb_state *mrb, mrb_irep *irep, uint8_t flags, uint8_t **bin, size_t *bin_size)
{ {
int result = MRB_DUMP_GENERAL_FAILURE; int result = MRB_DUMP_GENERAL_FAILURE;
size_t malloc_size; size_t malloc_size;
Expand All @@ -893,7 +923,7 @@ dump_irep(mrb_state *mrb, mrb_irep *irep, int debug_info, uint8_t **bin, size_t
section_irep_size += get_irep_record_size(mrb, irep); section_irep_size += get_irep_record_size(mrb, irep);


/* DEBUG section size */ /* DEBUG section size */
if (debug_info) { if (flags & DUMP_DEBUG_INFO) {
if (debug_info_defined) { if (debug_info_defined) {
section_lineno_size += sizeof(struct rite_section_debug_header); section_lineno_size += sizeof(struct rite_section_debug_header);
/* filename table */ /* filename table */
Expand Down Expand Up @@ -933,7 +963,7 @@ dump_irep(mrb_state *mrb, mrb_irep *irep, int debug_info, uint8_t **bin, size_t
sizeof(struct rite_binary_footer); sizeof(struct rite_binary_footer);


/* write DEBUG section */ /* write DEBUG section */
if (debug_info) { if (flags & DUMP_DEBUG_INFO) {
if (debug_info_defined) { if (debug_info_defined) {
result = write_section_debug(mrb, irep, cur, filenames, filenames_len); result = write_section_debug(mrb, irep, cur, filenames, filenames_len);
} }
Expand Down Expand Up @@ -972,13 +1002,13 @@ dump_irep(mrb_state *mrb, mrb_irep *irep, int debug_info, uint8_t **bin, size_t
} }


int int
mrb_dump_irep(mrb_state *mrb, mrb_irep *irep, int debug_info, uint8_t **bin, size_t *bin_size) mrb_dump_irep(mrb_state *mrb, mrb_irep *irep, uint8_t flags, uint8_t **bin, size_t *bin_size)
{ {
return dump_irep(mrb, irep, debug_info, bin, bin_size, FLAG_BYTEORDER_NONATIVE); return dump_irep(mrb, irep, dump_flags(flags, FLAG_BYTEORDER_NONATIVE), bin, bin_size);
} }


int int
mrb_dump_irep_binary(mrb_state *mrb, mrb_irep *irep, int debug_info, FILE* fp) mrb_dump_irep_binary(mrb_state *mrb, mrb_irep *irep, uint8_t flags, FILE* fp)
{ {
uint8_t *bin = NULL; uint8_t *bin = NULL;
size_t bin_size = 0; size_t bin_size = 0;
Expand All @@ -988,7 +1018,7 @@ mrb_dump_irep_binary(mrb_state *mrb, mrb_irep *irep, int debug_info, FILE* fp)
return MRB_DUMP_INVALID_ARGUMENT; return MRB_DUMP_INVALID_ARGUMENT;
} }


result = dump_irep(mrb, irep, debug_info, &bin, &bin_size, FLAG_BYTEORDER_NONATIVE); result = dump_irep(mrb, irep, dump_flags(flags, FLAG_BYTEORDER_NONATIVE), &bin, &bin_size);
if (result == MRB_DUMP_OK) { if (result == MRB_DUMP_OK) {
if (fwrite(bin, sizeof(bin[0]), bin_size, fp) != bin_size) { if (fwrite(bin, sizeof(bin[0]), bin_size, fp) != bin_size) {
result = MRB_DUMP_WRITE_FAULT; result = MRB_DUMP_WRITE_FAULT;
Expand All @@ -1015,8 +1045,22 @@ is_valid_c_symbol_name(const char *name)
return TRUE; return TRUE;
} }


static int
dump_bigendian_p(uint8_t flags)
{
switch (flags & DUMP_ENDIAN_NAT) {
case DUMP_ENDIAN_BIG:
return TRUE;
case DUMP_ENDIAN_LIL:
return FALSE;
default:
case DUMP_ENDIAN_NAT:
return bigendian_p();
}
}

int int
mrb_dump_irep_cfunc(mrb_state *mrb, mrb_irep *irep, int debug_info, FILE *fp, const char *initname) mrb_dump_irep_cfunc(mrb_state *mrb, mrb_irep *irep, uint8_t flags, FILE *fp, const char *initname)
{ {
uint8_t *bin = NULL; uint8_t *bin = NULL;
size_t bin_size = 0, bin_idx = 0; size_t bin_size = 0, bin_idx = 0;
Expand All @@ -1025,9 +1069,23 @@ mrb_dump_irep_cfunc(mrb_state *mrb, mrb_irep *irep, int debug_info, FILE *fp, co
if (fp == NULL || initname == NULL || !is_valid_c_symbol_name(initname)) { if (fp == NULL || initname == NULL || !is_valid_c_symbol_name(initname)) {
return MRB_DUMP_INVALID_ARGUMENT; return MRB_DUMP_INVALID_ARGUMENT;
} }

flags = dump_flags(flags, FLAG_BYTEORDER_NATIVE);
result = dump_irep(mrb, irep, debug_info, &bin, &bin_size, FLAG_BYTEORDER_NATIVE); result = dump_irep(mrb, irep, flags, &bin, &bin_size);
if (result == MRB_DUMP_OK) { if (result == MRB_DUMP_OK) {
if (!dump_bigendian_p(flags)) {
if (fprintf(fp, "/* dumped in little endian order.\n"
" use `mrbc -E` option for big endian CPU. */\n") < 0) {
mrb_free(mrb, bin);
return MRB_DUMP_WRITE_FAULT;
}
}
else {
if (fprintf(fp, "/* dumped in big endian order.\n"
" use `mrbc -e` option for better performance on little endian CPU. */\n") < 0) {
mrb_free(mrb, bin);
return MRB_DUMP_WRITE_FAULT;
}
}
if (fprintf(fp, "#include <stdint.h>\n") < 0) { /* for uint8_t under at least Darwin */ if (fprintf(fp, "#include <stdint.h>\n") < 0) { /* for uint8_t under at least Darwin */
mrb_free(mrb, bin); mrb_free(mrb, bin);
return MRB_DUMP_WRITE_FAULT; return MRB_DUMP_WRITE_FAULT;
Expand Down

0 comments on commit bc9c47d

Please sign in to comment.