From bc9c47d5180ab28e1a3db4dca80da7512aa6839a Mon Sep 17 00:00:00 2001 From: "Yukihiro \"Matz\" Matsumoto" Date: Mon, 2 Feb 2015 09:34:24 +0900 Subject: [PATCH] allow endian specification of mrb files by `mrbc -e/-E` `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. --- include/mruby/dump.h | 57 ++++++++++++++++---- src/dump.c | 122 +++++++++++++++++++++++++++++++------------ src/load.c | 49 +++++++++-------- tools/mrbc/mrbc.c | 20 +++++-- 4 files changed, 180 insertions(+), 68 deletions(-) diff --git a/include/mruby/dump.h b/include/mruby/dump.h index 194110019e..45774d8722 100644 --- a/include/mruby/dump.h +++ b/include/mruby/dump.h @@ -14,10 +14,16 @@ extern "C" { #include "mruby.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 -int mrb_dump_irep_binary(mrb_state*, mrb_irep*, int, FILE*); -int mrb_dump_irep_cfunc(mrb_state *mrb, mrb_irep*, int, FILE *f, const char *initname); +int mrb_dump_irep_binary(mrb_state*, mrb_irep*, uint8_t, FILE*); +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_API mrb_value mrb_load_irep_file(mrb_state*,FILE*); MRB_API mrb_value mrb_load_irep_file_cxt(mrb_state*, FILE*, mrbc_context*); @@ -42,7 +48,8 @@ MRB_API mrb_irep *mrb_read_irep(mrb_state*, const uint8_t*); #define MRB_DUMP_NULL_SYM_LEN 0xFFFF /* 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_COMPILER_NAME "MATZ" #define RITE_COMPILER_VERSION "0000" @@ -50,17 +57,17 @@ MRB_API mrb_irep *mrb_read_irep(mrb_state*, const uint8_t*); #define RITE_VM_VER "0000" #define RITE_BINARY_EOF "END\0" -#define RITE_SECTION_IREP_IDENTIFIER "IREP" -#define RITE_SECTION_LINENO_IDENTIFIER "LINE" -#define RITE_SECTION_DEBUG_IDENTIFIER "DBG\0" -#define RITE_SECTION_LV_IDENTIFIER "LVAR" +#define RITE_SECTION_IREP_IDENT "IREP" +#define RITE_SECTION_LINENO_IDENT "LINE" +#define RITE_SECTION_DEBUG_IDENT "DBG\0" +#define RITE_SECTION_LV_IDENT "LVAR" #define MRB_DUMP_DEFAULT_STR_LEN 128 #define MRB_DUMP_ALIGNMENT sizeof(uint32_t) /* 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_crc[2]; /* Binary CRC */ uint8_t binary_size[4]; /* Binary Size */ @@ -70,7 +77,7 @@ struct rite_binary_header { /* section header */ #define RITE_SECTION_HEADER \ - uint8_t section_identify[4]; \ + uint8_t section_ident[4]; \ uint8_t section_size[4] struct rite_section_header { @@ -101,6 +108,17 @@ struct rite_binary_footer { 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 uint8_to_bin(uint8_t s, uint8_t *bin) { @@ -126,6 +144,16 @@ uint32_to_bin(uint32_t l, uint8_t *bin) 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 bin_to_uint32(const uint8_t *bin) { @@ -135,6 +163,15 @@ bin_to_uint32(const uint8_t *bin) (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 bin_to_uint16(const uint8_t *bin) { diff --git a/src/dump.c b/src/dump.c index af12ed6051..09857e8c56 100644 --- a/src/dump.c +++ b/src/dump.c @@ -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 += write_padding(cur); - if (flags & FLAG_BYTEORDER_NATIVE) { - memcpy(cur, irep->iseq, irep->ilen * sizeof(mrb_code)); - cur += irep->ilen * sizeof(mrb_code); - } - else { + switch (flags & DUMP_ENDIAN_NAT) { + case DUMP_ENDIAN_BIG: + if (bigendian_p()) goto native; for (iseq_no = 0; iseq_no < irep->ilen; iseq_no++) { 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; @@ -323,7 +334,7 @@ write_footer(mrb_state *mrb, uint8_t *bin) { 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); memcpy(bin, &footer, sizeof(struct rite_binary_footer)); @@ -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; - 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); uint32_to_bin((uint32_t)section_size, header->section_size); @@ -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; - 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); return MRB_DUMP_OK; @@ -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); 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); uint32_to_bin(section_size, header->section_size); @@ -803,7 +814,7 @@ write_section_lv(mrb_state *mrb, mrb_irep *irep, uint8_t *start, mrb_sym const * 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; mrb_assert_int_fit(ptrdiff_t, diff, size_t, SIZE_MAX); @@ -820,19 +831,23 @@ write_rite_binary_header(mrb_state *mrb, size_t binary_size, uint8_t *bin, uint8 uint16_t crc; uint32_t offset; - if (flags & FLAG_BYTEORDER_NATIVE) { - uint32_t ident = 0; - size_t i; - - for(i=0; ibinary_identify, (char*)&ident, sizeof(uint32_t)); - } - else { - memcpy(header->binary_identify, RITE_BINARY_IDENTIFIER, sizeof(header->binary_identify)); + switch (flags & DUMP_ENDIAN_NAT) { + default: + endian_big: + case DUMP_ENDIAN_BIG: + memcpy(header->binary_ident, RITE_BINARY_IDENT, sizeof(header->binary_ident)); + break; + endian_little: + case DUMP_ENDIAN_LIL: + memcpy(header->binary_ident, RITE_BINARY_IDENT_LIL, sizeof(header->binary_ident)); + break; + + 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->compiler_name, RITE_COMPILER_NAME, sizeof(header->compiler_name)); memcpy(header->compiler_version, RITE_COMPILER_VERSION, sizeof(header->compiler_version)); @@ -872,8 +887,23 @@ is_lv_defined(mrb_irep *irep) 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 -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; size_t malloc_size; @@ -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); /* DEBUG section size */ - if (debug_info) { + if (flags & DUMP_DEBUG_INFO) { if (debug_info_defined) { section_lineno_size += sizeof(struct rite_section_debug_header); /* filename table */ @@ -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); /* write DEBUG section */ - if (debug_info) { + if (flags & DUMP_DEBUG_INFO) { if (debug_info_defined) { result = write_section_debug(mrb, irep, cur, filenames, filenames_len); } @@ -972,13 +1002,13 @@ dump_irep(mrb_state *mrb, mrb_irep *irep, int debug_info, uint8_t **bin, size_t } 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 -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; size_t bin_size = 0; @@ -988,7 +1018,7 @@ mrb_dump_irep_binary(mrb_state *mrb, mrb_irep *irep, int debug_info, FILE* fp) 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 (fwrite(bin, sizeof(bin[0]), bin_size, fp) != bin_size) { result = MRB_DUMP_WRITE_FAULT; @@ -1015,8 +1045,22 @@ is_valid_c_symbol_name(const char *name) 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 -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; size_t bin_size = 0, bin_idx = 0; @@ -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)) { return MRB_DUMP_INVALID_ARGUMENT; } - - result = dump_irep(mrb, irep, debug_info, &bin, &bin_size, FLAG_BYTEORDER_NATIVE); + flags = dump_flags(flags, FLAG_BYTEORDER_NATIVE); + result = dump_irep(mrb, irep, flags, &bin, &bin_size); 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 \n") < 0) { /* for uint8_t under at least Darwin */ mrb_free(mrb, bin); return MRB_DUMP_WRITE_FAULT; diff --git a/src/load.c b/src/load.c index 7640d8fda8..889420ae99 100644 --- a/src/load.c +++ b/src/load.c @@ -14,8 +14,9 @@ #include "mruby/debug.h" #include "mruby/error.h" -#define FLAG_BYTEORDER_NATIVE 2 -#define FLAG_BYTEORDER_NONATIVE 0 +#define FLAG_BYTEORDER_BIG 2 +#define FLAG_BYTEORDER_LIL 4 +#define FLAG_BYTEORDER_NATIVE 8 #define FLAG_SRC_MALLOC 1 #define FLAG_SRC_STATIC 0 @@ -93,12 +94,18 @@ read_irep_record_1(mrb_state *mrb, const uint8_t *bin, size_t *len, uint8_t flag memcpy(irep->iseq, src, sizeof(uint32_t) * irep->ilen); src += sizeof(uint32_t) * irep->ilen; } - else { + else if (flags & FLAG_BYTEORDER_BIG) { for (i = 0; i < irep->ilen; i++) { irep->iseq[i] = (mrb_code)bin_to_uint32(src); /* iseq */ src += sizeof(uint32_t); } } + else { + for (i = 0; i < irep->ilen; i++) { + irep->iseq[i] = (mrb_code)bin_to_uint32l(src); /* iseq */ + src += sizeof(uint32_t); + } + } } } @@ -521,22 +528,20 @@ static int read_binary_header(const uint8_t *bin, size_t *bin_size, uint16_t *crc, uint8_t *flags) { const struct rite_binary_header *header = (const struct rite_binary_header *)bin; - uint32_t ident = 0; - size_t i; - /* create native byteorder version of RITE_BINARY_IDENTIFIER */ - for(i=0; ibinary_ident, RITE_BINARY_IDENT, sizeof(header->binary_ident)) == 0) { + if (bigendian_p()) + *flags |= FLAG_BYTEORDER_NATIVE; + else + *flags |= FLAG_BYTEORDER_BIG; } - if (memcmp(header->binary_identify, &ident, sizeof(header->binary_identify)) == 0) { - *flags |= FLAG_BYTEORDER_NATIVE; + else if (memcmp(header->binary_ident, RITE_BINARY_IDENT_LIL, sizeof(header->binary_ident)) == 0) { + if (bigendian_p()) + *flags |= FLAG_BYTEORDER_LIL; + else + *flags |= FLAG_BYTEORDER_NATIVE; } - else if (memcmp(header->binary_identify, RITE_BINARY_IDENTIFIER, sizeof(header->binary_identify)) != 0) { - return MRB_DUMP_INVALID_FILE_HEADER; - } - - if (memcmp(header->binary_version, RITE_BINARY_FORMAT_VER, sizeof(header->binary_version)) != 0) { + else { return MRB_DUMP_INVALID_FILE_HEADER; } @@ -575,25 +580,25 @@ read_irep(mrb_state *mrb, const uint8_t *bin, uint8_t flags) bin += sizeof(struct rite_binary_header); do { section_header = (const struct rite_section_header *)bin; - if (memcmp(section_header->section_identify, RITE_SECTION_IREP_IDENTIFIER, sizeof(section_header->section_identify)) == 0) { + if (memcmp(section_header->section_ident, RITE_SECTION_IREP_IDENT, sizeof(section_header->section_ident)) == 0) { irep = read_section_irep(mrb, bin, flags); if (!irep) return NULL; } - else if (memcmp(section_header->section_identify, RITE_SECTION_LINENO_IDENTIFIER, sizeof(section_header->section_identify)) == 0) { + else if (memcmp(section_header->section_ident, RITE_SECTION_LINENO_IDENT, sizeof(section_header->section_ident)) == 0) { if (!irep) return NULL; /* corrupted data */ result = read_section_lineno(mrb, bin, irep); if (result < MRB_DUMP_OK) { return NULL; } } - else if (memcmp(section_header->section_identify, RITE_SECTION_DEBUG_IDENTIFIER, sizeof(section_header->section_identify)) == 0) { + else if (memcmp(section_header->section_ident, RITE_SECTION_DEBUG_IDENT, sizeof(section_header->section_ident)) == 0) { if (!irep) return NULL; /* corrupted data */ result = read_section_debug(mrb, bin, irep, flags); if (result < MRB_DUMP_OK) { return NULL; } } - else if (memcmp(section_header->section_identify, RITE_SECTION_LV_IDENTIFIER, sizeof(section_header->section_identify)) == 0) { + else if (memcmp(section_header->section_ident, RITE_SECTION_LV_IDENT, sizeof(section_header->section_ident)) == 0) { if (!irep) return NULL; result = read_section_lv(mrb, bin, irep, flags); if (result < MRB_DUMP_OK) { @@ -601,7 +606,7 @@ read_irep(mrb_state *mrb, const uint8_t *bin, uint8_t flags) } } bin += bin_to_uint32(section_header->section_size); - } while (memcmp(section_header->section_identify, RITE_BINARY_EOF, sizeof(section_header->section_identify)) != 0); + } while (memcmp(section_header->section_ident, RITE_BINARY_EOF, sizeof(section_header->section_ident)) != 0); return irep; } @@ -655,7 +660,7 @@ mrb_read_irep_file(mrb_state *mrb, FILE* fp) uint8_t *buf; const size_t header_size = sizeof(struct rite_binary_header); size_t buf_size = 0; - uint8_t flags; + uint8_t flags = 0; int result; if ((mrb == NULL) || (fp == NULL)) { diff --git a/tools/mrbc/mrbc.c b/tools/mrbc/mrbc.c index b51cc4da7f..f27f87a5d6 100644 --- a/tools/mrbc/mrbc.c +++ b/tools/mrbc/mrbc.c @@ -18,7 +18,7 @@ struct mrbc_args { const char *initname; mrb_bool check_syntax : 1; mrb_bool verbose : 1; - mrb_bool debug_info : 1; + unsigned int flags : 4; }; static void @@ -31,6 +31,8 @@ usage(const char *name) "-v print version number, then turn on verbose mode", "-g produce debugging information", "-B binary output in C language format", + "-e generate little endian iseq data", + "-E generate big endian iseq data", "--verbose run at verbose mode", "--version print the version", "--copyright print the copyright", @@ -114,7 +116,13 @@ parse_args(mrb_state *mrb, int argc, char **argv, struct mrbc_args *args) args->verbose = TRUE; break; case 'g': - args->debug_info = TRUE; + args->flags |= DUMP_DEBUG_INFO; + break; + case 'E': + args->flags = DUMP_ENDIAN_BIG | (args->flags & DUMP_DEBUG_INFO); + break; + case 'e': + args->flags = DUMP_ENDIAN_LIL | (args->flags & DUMP_DEBUG_INFO); break; case 'h': return -1; @@ -143,6 +151,10 @@ parse_args(mrb_state *mrb, int argc, char **argv, struct mrbc_args *args) break; } } + if (args->verbose && args->initname && (args->flags & DUMP_ENDIAN_MASK) == 0) { + fprintf(stderr, "%s: generating %s endian C file. specify -e/-E for cross compiling.\n", + args->prog, bigendian_p() ? "big" : "little"); + } return i; } @@ -222,13 +234,13 @@ dump_file(mrb_state *mrb, FILE *wfp, const char *outfile, struct RProc *proc, st mrb_irep *irep = proc->body.irep; if (args->initname) { - n = mrb_dump_irep_cfunc(mrb, irep, args->debug_info, wfp, args->initname); + n = mrb_dump_irep_cfunc(mrb, irep, args->flags, wfp, args->initname); if (n == MRB_DUMP_INVALID_ARGUMENT) { fprintf(stderr, "%s: invalid C language symbol name\n", args->initname); } } else { - n = mrb_dump_irep_binary(mrb, irep, args->debug_info, wfp); + n = mrb_dump_irep_binary(mrb, irep, args->flags, wfp); } if (n != MRB_DUMP_OK) { fprintf(stderr, "%s: error in mrb dump (%s) %d\n", args->prog, outfile, n);