From 494ed1738d2360685d6c03661f51edbf75c0f7ff Mon Sep 17 00:00:00 2001 From: Peter Johnson <peter@tortall.net> Date: Sun, 6 Oct 2002 19:43:51 +0000 Subject: [PATCH] Make output endian-tolerant by making intnum and floatnum output functions for arch. This will also simplify other objfmt expr output functions. Change file functions to use bits instead of byte/short/long, and create both little and big endian versions. This name change caused changes in several other files. svn path=/trunk/yasm/; revision=747 --- libyasm/arch.h | 11 ++++ libyasm/bytecode.c | 2 +- libyasm/file.c | 28 +++++++++- libyasm/file.h | 89 ++++++++++++++++++++++++++------ libyasm/floatnum.c | 2 +- libyasm/intnum.c | 2 +- modules/arch/x86/x86arch.c | 5 ++ modules/arch/x86/x86arch.h | 6 +++ modules/arch/x86/x86bc.c | 55 +++++++++++++++----- modules/arch/x86/x86expr.c | 24 +++++++++ modules/objfmts/bin/bin-objfmt.c | 54 +++---------------- src/arch.h | 11 ++++ src/arch/x86/x86arch.c | 5 ++ src/arch/x86/x86arch.h | 6 +++ src/arch/x86/x86bc.c | 55 +++++++++++++++----- src/arch/x86/x86expr.c | 24 +++++++++ src/bytecode.c | 2 +- src/file.c | 28 +++++++++- src/file.h | 89 ++++++++++++++++++++++++++------ src/floatnum.c | 2 +- src/intnum.c | 2 +- src/objfmts/bin/bin-objfmt.c | 54 +++---------------- 22 files changed, 396 insertions(+), 160 deletions(-) diff --git a/libyasm/arch.h b/libyasm/arch.h index e5a8b167..6d5132c9 100644 --- a/libyasm/arch.h +++ b/libyasm/arch.h @@ -141,6 +141,17 @@ struct arch { output_expr_func output_expr); } bc; + /* Functions to output floats and integers, architecture-specific because + * of endianness. Returns nonzero on error, otherwise updates bufp by + * valsize (bytes saved to bufp). For intnums, rel indicates a relative + * displacement, and bc is the containing bytecode to compute it from. + */ + int (*floatnum_tobytes) (const floatnum *flt, unsigned char **bufp, + unsigned long valsize, const expr *e); + int (*intnum_tobytes) (const intnum *intn, unsigned char **bufp, + unsigned long valsize, const expr *e, + const bytecode *bc, int rel); + /* Gets the equivalent register size in bytes. Returns 0 if there is no * suitable equivalent size. */ diff --git a/libyasm/bytecode.c b/libyasm/bytecode.c index 46188805..04d8649a 100644 --- a/libyasm/bytecode.c +++ b/libyasm/bytecode.c @@ -668,7 +668,7 @@ bc_tobytes_data(bytecode_data *bc_data, unsigned char **bufp, if (slen > 0) { slen = bc_data->size-slen; for (i=0; i<slen; i++) - WRITE_BYTE(*bufp, 0); + WRITE_8(*bufp, 0); } break; } diff --git a/libyasm/file.c b/libyasm/file.c index a6649dc1..77f1aa9e 100644 --- a/libyasm/file.c +++ b/libyasm/file.c @@ -75,7 +75,7 @@ replace_extension(const char *orig, /*@null@*/ const char *ext, } size_t -fwrite_short(unsigned short val, FILE *f) +fwrite_16_l(unsigned short val, FILE *f) { if (fputc(val & 0xFF, f) == EOF) return 0; @@ -85,7 +85,7 @@ fwrite_short(unsigned short val, FILE *f) } size_t -fwrite_long(unsigned long val, FILE *f) +fwrite_32_l(unsigned long val, FILE *f) { if (fputc((int)(val & 0xFF), f) == EOF) return 0; @@ -97,3 +97,27 @@ fwrite_long(unsigned long val, FILE *f) return 0; return 1; } + +size_t +fwrite_16_b(unsigned short val, FILE *f) +{ + if (fputc((val >> 8) & 0xFF, f) == EOF) + return 0; + if (fputc(val & 0xFF, f) == EOF) + return 0; + return 1; +} + +size_t +fwrite_32_b(unsigned long val, FILE *f) +{ + if (fputc((int)((val >> 24) & 0xFF), f) == EOF) + return 0; + if (fputc((int)((val >> 16) & 0xFF), f) == EOF) + return 0; + if (fputc((int)((val >> 8) & 0xFF), f) == EOF) + return 0; + if (fputc((int)(val & 0xFF), f) == EOF) + return 0; + return 1; +} diff --git a/libyasm/file.h b/libyasm/file.h index 2c597620..39407478 100644 --- a/libyasm/file.h +++ b/libyasm/file.h @@ -1,5 +1,5 @@ /* $IdPath$ - * Little-endian file functions header file. + * Big and little endian file functions header file. * * Copyright (C) 2001 Peter Johnson * @@ -33,16 +33,16 @@ /* These functions only work properly if p is an (unsigned char *) */ -#define WRITE_BYTE(ptr, val) \ +#define WRITE_8(ptr, val) \ *((ptr)++) = (unsigned char)((val) & 0xFF) -#define WRITE_SHORT(ptr, val) \ +#define WRITE_16_L(ptr, val) \ do { \ *((ptr)++) = (unsigned char)((val) & 0xFF); \ *((ptr)++) = (unsigned char)(((val) >> 8) & 0xFF); \ } while (0) -#define WRITE_LONG(ptr, val) \ +#define WRITE_32_L(ptr, val) \ do { \ *((ptr)++) = (unsigned char)((val) & 0xFF); \ *((ptr)++) = (unsigned char)(((val) >> 8) & 0xFF); \ @@ -50,18 +50,33 @@ *((ptr)++) = (unsigned char)(((val) >> 24) & 0xFF); \ } while (0) +#define WRITE_16_B(ptr, val) \ + do { \ + *((ptr)++) = (unsigned char)(((val) >> 8) & 0xFF); \ + *((ptr)++) = (unsigned char)((val) & 0xFF); \ + } while (0) + +#define WRITE_32_B(ptr, val) \ + do { \ + *((ptr)++) = (unsigned char)(((val) >> 24) & 0xFF); \ + *((ptr)++) = (unsigned char)(((val) >> 16) & 0xFF); \ + *((ptr)++) = (unsigned char)(((val) >> 8) & 0xFF); \ + *((ptr)++) = (unsigned char)((val) & 0xFF); \ + } while (0) + + /* Non-incrementing versions of the above. */ -#define SAVE_BYTE(ptr, val) \ +#define SAVE_8(ptr, val) \ *(ptr) = (unsigned char)((val) & 0xFF) -#define SAVE_SHORT(ptr, val) \ +#define SAVE_16_L(ptr, val) \ do { \ *(ptr) = (unsigned char)((val) & 0xFF); \ *((ptr)+1) = (unsigned char)(((val) >> 8) & 0xFF); \ } while (0) -#define SAVE_LONG(ptr, val) \ +#define SAVE_32_L(ptr, val) \ do { \ *(ptr) = (unsigned char)((val) & 0xFF); \ *((ptr)+1) = (unsigned char)(((val) >> 8) & 0xFF); \ @@ -69,27 +84,43 @@ *((ptr)+3) = (unsigned char)(((val) >> 24) & 0xFF); \ } while (0) +#define SAVE_16_B(ptr, val) \ + do { \ + *(ptr) = (unsigned char)(((val) >> 8) & 0xFF); \ + *((ptr)+1) = (unsigned char)((val) & 0xFF); \ + } while (0) + +#define SAVE_32_B(ptr, val) \ + do { \ + *(ptr) = (unsigned char)(((val) >> 24) & 0xFF); \ + *((ptr)+1) = (unsigned char)(((val) >> 16) & 0xFF); \ + *((ptr)+2) = (unsigned char)(((val) >> 8) & 0xFF); \ + *((ptr)+3) = (unsigned char)((val) & 0xFF); \ + } while (0) + /* Direct-to-file versions of the above. Using the above macros and a single * fwrite() will probably be faster than calling these functions many times. * These functions return 1 if the write was successful, 0 if not (so their * return values can be used like the return value from fwrite()). */ -size_t fwrite_short(unsigned short val, FILE *f); -size_t fwrite_long(unsigned long val, FILE *f); +size_t fwrite_16_l(unsigned short val, FILE *f); +size_t fwrite_32_l(unsigned long val, FILE *f); +size_t fwrite_16_b(unsigned short val, FILE *f); +size_t fwrite_32_b(unsigned long val, FILE *f); /* Read/Load versions. val is the variable to receive the data. */ -#define READ_BYTE(val, ptr) \ +#define READ_8(val, ptr) \ (val) = *((ptr)++) & 0xFF -#define READ_SHORT(val, ptr) \ +#define READ_16_L(val, ptr) \ do { \ (val) = *((ptr)++) & 0xFF; \ (val) |= (*((ptr)++) & 0xFF) << 8; \ } while (0) -#define READ_LONG(val, ptr) \ +#define READ_32_L(val, ptr) \ do { \ (val) = *((ptr)++) & 0xFF; \ (val) |= (*((ptr)++) & 0xFF) << 8; \ @@ -97,18 +128,32 @@ size_t fwrite_long(unsigned long val, FILE *f); (val) |= (*((ptr)++) & 0xFF) << 24; \ } while (0) +#define READ_16_B(val, ptr) \ + do { \ + (val) = (*((ptr)++) & 0xFF) << 8; \ + (val) |= *((ptr)++) & 0xFF; \ + } while (0) + +#define READ_32_B(val, ptr) \ + do { \ + (val) = (*((ptr)++) & 0xFF) << 24; \ + (val) |= (*((ptr)++) & 0xFF) << 16; \ + (val) |= (*((ptr)++) & 0xFF) << 8; \ + (val) |= *((ptr)++) & 0xFF; \ + } while (0) + /* Non-incrementing versions of the above. */ -#define LOAD_BYTE(val, ptr) \ +#define LOAD_8(val, ptr) \ (val) = *(ptr) & 0xFF -#define LOAD_SHORT(val, ptr) \ +#define LOAD_16_L(val, ptr) \ do { \ (val) = *(ptr) & 0xFF; \ (val) |= (*((ptr)+1) & 0xFF) << 8; \ } while (0) -#define LOAD_LONG(val, ptr) \ +#define LOAD_32_L(val, ptr) \ do { \ (val) = (unsigned long)(*(ptr) & 0xFF); \ (val) |= (unsigned long)((*((ptr)+1) & 0xFF) << 8); \ @@ -116,4 +161,18 @@ size_t fwrite_long(unsigned long val, FILE *f); (val) |= (unsigned long)((*((ptr)+3) & 0xFF) << 24); \ } while (0) +#define LOAD_16_B(val, ptr) \ + do { \ + (val) = (*(ptr) & 0xFF) << 8; \ + (val) |= *((ptr)+1) & 0xFF; \ + } while (0) + +#define LOAD_32_B(val, ptr) \ + do { \ + (val) = (unsigned long)((*(ptr) & 0xFF) << 24); \ + (val) |= (unsigned long)((*((ptr)+1) & 0xFF) << 16); \ + (val) |= (unsigned long)((*((ptr)+2) & 0xFF) << 8); \ + (val) |= (unsigned long)(*((ptr)+3) & 0xFF); \ + } while (0) + #endif diff --git a/libyasm/floatnum.c b/libyasm/floatnum.c index 9f4e936b..6f98dc26 100644 --- a/libyasm/floatnum.c +++ b/libyasm/floatnum.c @@ -529,7 +529,7 @@ floatnum_get_int(const floatnum *flt, unsigned long *ret_val) return 1; } - LOAD_LONG(*ret_val, &t[0]); + LOAD_32_L(*ret_val, &t[0]); return 0; } diff --git a/libyasm/intnum.c b/libyasm/intnum.c index 99d47862..38c57221 100644 --- a/libyasm/intnum.c +++ b/libyasm/intnum.c @@ -551,7 +551,7 @@ intnum_get_sized(const intnum *intn, unsigned char *ptr, size_t size) case INTNUM_UL: ul = intn->val.ul; while (size-- > 0) { - WRITE_BYTE(ptr, ul); + WRITE_8(ptr, ul); if (ul != 0) ul >>= 8; } diff --git a/modules/arch/x86/x86arch.c b/modules/arch/x86/x86arch.c index de8ef8e2..e4b91255 100644 --- a/modules/arch/x86/x86arch.c +++ b/modules/arch/x86/x86arch.c @@ -22,9 +22,12 @@ #include "util.h" /*@unused@*/ RCSID("$IdPath$"); +#include "file.h" + #include "globals.h" #include "errwarn.h" #include "intnum.h" +#include "floatnum.h" #include "expr.h" #include "bytecode.h" @@ -177,6 +180,8 @@ arch x86_arch = { x86_bc_resolve, x86_bc_tobytes }, + x86_floatnum_tobytes, + x86_intnum_tobytes, x86_get_reg_size, x86_reg_print, x86_segreg_print, diff --git a/modules/arch/x86/x86arch.h b/modules/arch/x86/x86arch.h index 9f10c9d0..5223e42c 100644 --- a/modules/arch/x86/x86arch.h +++ b/modules/arch/x86/x86arch.h @@ -220,6 +220,12 @@ void x86_handle_seg_prefix(bytecode *bc, unsigned long segreg); void x86_handle_seg_override(effaddr *ea, unsigned long segreg); +int x86_floatnum_tobytes(const floatnum *flt, unsigned char **bufp, + unsigned long valsize, const expr *e); +int x86_intnum_tobytes(const intnum *intn, unsigned char **bufp, + unsigned long valsize, const expr *e, + const bytecode *bc, int rel); + unsigned int x86_get_reg_size(unsigned long reg); void x86_reg_print(FILE *f, unsigned long reg); diff --git a/modules/arch/x86/x86bc.c b/modules/arch/x86/x86bc.c index f5dc6a4b..b7f8851f 100644 --- a/modules/arch/x86/x86bc.c +++ b/modules/arch/x86/x86bc.c @@ -726,17 +726,17 @@ x86_bc_tobytes_insn(x86_insn *insn, unsigned char **bufp, const section *sect, /* Prefixes */ if (insn->lockrep_pre != 0) - WRITE_BYTE(*bufp, insn->lockrep_pre); + WRITE_8(*bufp, insn->lockrep_pre); if (ea && ead->segment != 0) - WRITE_BYTE(*bufp, ead->segment); + WRITE_8(*bufp, ead->segment); if (insn->opersize != 0 && insn->opersize != insn->mode_bits) - WRITE_BYTE(*bufp, 0x66); + WRITE_8(*bufp, 0x66); if (insn->addrsize != 0 && insn->addrsize != insn->mode_bits) - WRITE_BYTE(*bufp, 0x67); + WRITE_8(*bufp, 0x67); /* Opcode */ for (i=0; i<insn->opcode_len; i++) - WRITE_BYTE(*bufp, insn->opcode[i]); + WRITE_8(*bufp, insn->opcode[i]); /* Effective address: ModR/M (if required), SIB (if required), and * displacement (if required). @@ -745,13 +745,13 @@ x86_bc_tobytes_insn(x86_insn *insn, unsigned char **bufp, const section *sect, if (ead->need_modrm) { if (!ead->valid_modrm) InternalError(_("invalid Mod/RM in x86 tobytes_insn")); - WRITE_BYTE(*bufp, ead->modrm); + WRITE_8(*bufp, ead->modrm); } if (ead->need_sib) { if (!ead->valid_sib) InternalError(_("invalid SIB in x86 tobytes_insn")); - WRITE_BYTE(*bufp, ead->sib); + WRITE_8(*bufp, ead->sib); } if (ea->disp) { @@ -780,7 +780,7 @@ x86_bc_tobytes_insn(x86_insn *insn, unsigned char **bufp, const section *sect, * write out 0 value. */ for (i=0; i<ea->len; i++) - WRITE_BYTE(*bufp, 0); + WRITE_8(*bufp, 0); } } } @@ -805,12 +805,12 @@ x86_bc_tobytes_jmprel(x86_jmprel *jmprel, unsigned char **bufp, /* Prefixes */ if (jmprel->lockrep_pre != 0) - WRITE_BYTE(*bufp, jmprel->lockrep_pre); + WRITE_8(*bufp, jmprel->lockrep_pre); /* FIXME: branch hints! */ if (jmprel->opersize != 0 && jmprel->opersize != jmprel->mode_bits) - WRITE_BYTE(*bufp, 0x66); + WRITE_8(*bufp, 0x66); if (jmprel->addrsize != 0 && jmprel->addrsize != jmprel->mode_bits) - WRITE_BYTE(*bufp, 0x67); + WRITE_8(*bufp, 0x67); /* As opersize may be 0, figure out its "real" value. */ opersize = (jmprel->opersize == 0) ? jmprel->mode_bits : @@ -826,7 +826,7 @@ x86_bc_tobytes_jmprel(x86_jmprel *jmprel, unsigned char **bufp, /* Opcode */ for (i=0; i<jmprel->shortop.opcode_len; i++) - WRITE_BYTE(*bufp, jmprel->shortop.opcode[i]); + WRITE_8(*bufp, jmprel->shortop.opcode[i]); /* Relative displacement */ if (output_expr(&jmprel->target, bufp, 1, sect, bc, 1, d)) @@ -842,7 +842,7 @@ x86_bc_tobytes_jmprel(x86_jmprel *jmprel, unsigned char **bufp, /* Opcode */ for (i=0; i<jmprel->nearop.opcode_len; i++) - WRITE_BYTE(*bufp, jmprel->nearop.opcode[i]); + WRITE_8(*bufp, jmprel->nearop.opcode[i]); /* Relative displacement */ if (output_expr(&jmprel->target, bufp, @@ -876,3 +876,32 @@ x86_bc_tobytes(bytecode *bc, unsigned char **bufp, const section *sect, return 0; } +int +x86_intnum_tobytes(const intnum *intn, unsigned char **bufp, + unsigned long valsize, const expr *e, const bytecode *bc, + int rel) +{ + if (rel) { + long val; + if (valsize != 1 && valsize != 2 && valsize != 4) + InternalError(_("tried to do PC-relative offset from invalid sized value")); + val = intnum_get_uint(intn); + val -= bc->len; + switch (valsize) { + case 1: + WRITE_8(*bufp, val); + break; + case 2: + WRITE_16_L(*bufp, val); + break; + case 4: + WRITE_32_L(*bufp, val); + break; + } + } else { + /* Write value out. */ + intnum_get_sized(intn, *bufp, (size_t)valsize); + *bufp += valsize; + } + return 0; +} diff --git a/modules/arch/x86/x86expr.c b/modules/arch/x86/x86expr.c index 9855a087..fdcc6c38 100644 --- a/modules/arch/x86/x86expr.c +++ b/modules/arch/x86/x86expr.c @@ -771,3 +771,27 @@ x86_expr_checkea(expr **ep, unsigned char *addrsize, unsigned char bits, } return 1; } + +int +x86_floatnum_tobytes(const floatnum *flt, unsigned char **bufp, + unsigned long valsize, const expr *e) +{ + int fltret; + + if (!floatnum_check_size(flt, (size_t)valsize)) { + ErrorAt(e->line, _("invalid floating point constant size")); + return 1; + } + + fltret = floatnum_get_sized(flt, *bufp, (size_t)valsize); + if (fltret < 0) { + ErrorAt(e->line, _("underflow in floating point expression")); + return 1; + } + if (fltret > 0) { + ErrorAt(e->line, _("overflow in floating point expression")); + return 1; + } + *bufp += valsize; + return 0; +} diff --git a/modules/objfmts/bin/bin-objfmt.c b/modules/objfmts/bin/bin-objfmt.c index f408adb8..bf4823d1 100644 --- a/modules/objfmts/bin/bin-objfmt.c +++ b/modules/objfmts/bin/bin-objfmt.c @@ -37,6 +37,7 @@ #include "expr-int.h" #include "bc-int.h" +#include "arch.h" #include "objfmt.h" @@ -106,7 +107,7 @@ bin_objfmt_output_expr(expr **ep, unsigned char **bufp, unsigned long valsize, /*@observer@*/ const bytecode *bc, int rel, /*@unused@*/ /*@null@*/ void *d) { - /*@dependent@*/ /*@null@*/ const intnum *num; + /*@dependent@*/ /*@null@*/ const intnum *intn; /*@dependent@*/ /*@null@*/ const floatnum *flt; assert(info != NULL); @@ -120,54 +121,13 @@ bin_objfmt_output_expr(expr **ep, unsigned char **bufp, unsigned long valsize, /* Handle floating point expressions */ flt = expr_get_floatnum(ep); - if (flt) { - int fltret; - - if (!floatnum_check_size(flt, (size_t)valsize)) { - ErrorAt((*ep)->line, _("invalid floating point constant size")); - return 1; - } - - fltret = floatnum_get_sized(flt, *bufp, (size_t)valsize); - if (fltret < 0) { - ErrorAt((*ep)->line, _("underflow in floating point expression")); - return 1; - } - if (fltret > 0) { - ErrorAt((*ep)->line, _("overflow in floating point expression")); - return 1; - } - *bufp += valsize; - return 0; - } + if (flt) + return cur_arch->floatnum_tobytes(flt, bufp, valsize, *ep); /* Handle integer expressions */ - num = expr_get_intnum(ep, NULL); - if (num) { - if (rel) { - long val; - if (valsize != 1 && valsize != 2 && valsize != 4) - InternalError(_("tried to do PC-relative offset from invalid sized value")); - val = intnum_get_uint(num); - val -= bc->len; - switch (valsize) { - case 1: - WRITE_BYTE(*bufp, val); - break; - case 2: - WRITE_SHORT(*bufp, val); - break; - case 4: - WRITE_LONG(*bufp, val); - break; - } - } else { - /* Write value out. */ - intnum_get_sized(num, *bufp, (size_t)valsize); - *bufp += valsize; - } - return 0; - } + intn = expr_get_intnum(ep, NULL); + if (intn) + return cur_arch->intnum_tobytes(intn, bufp, valsize, *ep, bc, rel); /* Check for complex float expressions */ if (expr_contains(*ep, EXPR_FLOAT)) { diff --git a/src/arch.h b/src/arch.h index e5a8b167..6d5132c9 100644 --- a/src/arch.h +++ b/src/arch.h @@ -141,6 +141,17 @@ struct arch { output_expr_func output_expr); } bc; + /* Functions to output floats and integers, architecture-specific because + * of endianness. Returns nonzero on error, otherwise updates bufp by + * valsize (bytes saved to bufp). For intnums, rel indicates a relative + * displacement, and bc is the containing bytecode to compute it from. + */ + int (*floatnum_tobytes) (const floatnum *flt, unsigned char **bufp, + unsigned long valsize, const expr *e); + int (*intnum_tobytes) (const intnum *intn, unsigned char **bufp, + unsigned long valsize, const expr *e, + const bytecode *bc, int rel); + /* Gets the equivalent register size in bytes. Returns 0 if there is no * suitable equivalent size. */ diff --git a/src/arch/x86/x86arch.c b/src/arch/x86/x86arch.c index de8ef8e2..e4b91255 100644 --- a/src/arch/x86/x86arch.c +++ b/src/arch/x86/x86arch.c @@ -22,9 +22,12 @@ #include "util.h" /*@unused@*/ RCSID("$IdPath$"); +#include "file.h" + #include "globals.h" #include "errwarn.h" #include "intnum.h" +#include "floatnum.h" #include "expr.h" #include "bytecode.h" @@ -177,6 +180,8 @@ arch x86_arch = { x86_bc_resolve, x86_bc_tobytes }, + x86_floatnum_tobytes, + x86_intnum_tobytes, x86_get_reg_size, x86_reg_print, x86_segreg_print, diff --git a/src/arch/x86/x86arch.h b/src/arch/x86/x86arch.h index 9f10c9d0..5223e42c 100644 --- a/src/arch/x86/x86arch.h +++ b/src/arch/x86/x86arch.h @@ -220,6 +220,12 @@ void x86_handle_seg_prefix(bytecode *bc, unsigned long segreg); void x86_handle_seg_override(effaddr *ea, unsigned long segreg); +int x86_floatnum_tobytes(const floatnum *flt, unsigned char **bufp, + unsigned long valsize, const expr *e); +int x86_intnum_tobytes(const intnum *intn, unsigned char **bufp, + unsigned long valsize, const expr *e, + const bytecode *bc, int rel); + unsigned int x86_get_reg_size(unsigned long reg); void x86_reg_print(FILE *f, unsigned long reg); diff --git a/src/arch/x86/x86bc.c b/src/arch/x86/x86bc.c index f5dc6a4b..b7f8851f 100644 --- a/src/arch/x86/x86bc.c +++ b/src/arch/x86/x86bc.c @@ -726,17 +726,17 @@ x86_bc_tobytes_insn(x86_insn *insn, unsigned char **bufp, const section *sect, /* Prefixes */ if (insn->lockrep_pre != 0) - WRITE_BYTE(*bufp, insn->lockrep_pre); + WRITE_8(*bufp, insn->lockrep_pre); if (ea && ead->segment != 0) - WRITE_BYTE(*bufp, ead->segment); + WRITE_8(*bufp, ead->segment); if (insn->opersize != 0 && insn->opersize != insn->mode_bits) - WRITE_BYTE(*bufp, 0x66); + WRITE_8(*bufp, 0x66); if (insn->addrsize != 0 && insn->addrsize != insn->mode_bits) - WRITE_BYTE(*bufp, 0x67); + WRITE_8(*bufp, 0x67); /* Opcode */ for (i=0; i<insn->opcode_len; i++) - WRITE_BYTE(*bufp, insn->opcode[i]); + WRITE_8(*bufp, insn->opcode[i]); /* Effective address: ModR/M (if required), SIB (if required), and * displacement (if required). @@ -745,13 +745,13 @@ x86_bc_tobytes_insn(x86_insn *insn, unsigned char **bufp, const section *sect, if (ead->need_modrm) { if (!ead->valid_modrm) InternalError(_("invalid Mod/RM in x86 tobytes_insn")); - WRITE_BYTE(*bufp, ead->modrm); + WRITE_8(*bufp, ead->modrm); } if (ead->need_sib) { if (!ead->valid_sib) InternalError(_("invalid SIB in x86 tobytes_insn")); - WRITE_BYTE(*bufp, ead->sib); + WRITE_8(*bufp, ead->sib); } if (ea->disp) { @@ -780,7 +780,7 @@ x86_bc_tobytes_insn(x86_insn *insn, unsigned char **bufp, const section *sect, * write out 0 value. */ for (i=0; i<ea->len; i++) - WRITE_BYTE(*bufp, 0); + WRITE_8(*bufp, 0); } } } @@ -805,12 +805,12 @@ x86_bc_tobytes_jmprel(x86_jmprel *jmprel, unsigned char **bufp, /* Prefixes */ if (jmprel->lockrep_pre != 0) - WRITE_BYTE(*bufp, jmprel->lockrep_pre); + WRITE_8(*bufp, jmprel->lockrep_pre); /* FIXME: branch hints! */ if (jmprel->opersize != 0 && jmprel->opersize != jmprel->mode_bits) - WRITE_BYTE(*bufp, 0x66); + WRITE_8(*bufp, 0x66); if (jmprel->addrsize != 0 && jmprel->addrsize != jmprel->mode_bits) - WRITE_BYTE(*bufp, 0x67); + WRITE_8(*bufp, 0x67); /* As opersize may be 0, figure out its "real" value. */ opersize = (jmprel->opersize == 0) ? jmprel->mode_bits : @@ -826,7 +826,7 @@ x86_bc_tobytes_jmprel(x86_jmprel *jmprel, unsigned char **bufp, /* Opcode */ for (i=0; i<jmprel->shortop.opcode_len; i++) - WRITE_BYTE(*bufp, jmprel->shortop.opcode[i]); + WRITE_8(*bufp, jmprel->shortop.opcode[i]); /* Relative displacement */ if (output_expr(&jmprel->target, bufp, 1, sect, bc, 1, d)) @@ -842,7 +842,7 @@ x86_bc_tobytes_jmprel(x86_jmprel *jmprel, unsigned char **bufp, /* Opcode */ for (i=0; i<jmprel->nearop.opcode_len; i++) - WRITE_BYTE(*bufp, jmprel->nearop.opcode[i]); + WRITE_8(*bufp, jmprel->nearop.opcode[i]); /* Relative displacement */ if (output_expr(&jmprel->target, bufp, @@ -876,3 +876,32 @@ x86_bc_tobytes(bytecode *bc, unsigned char **bufp, const section *sect, return 0; } +int +x86_intnum_tobytes(const intnum *intn, unsigned char **bufp, + unsigned long valsize, const expr *e, const bytecode *bc, + int rel) +{ + if (rel) { + long val; + if (valsize != 1 && valsize != 2 && valsize != 4) + InternalError(_("tried to do PC-relative offset from invalid sized value")); + val = intnum_get_uint(intn); + val -= bc->len; + switch (valsize) { + case 1: + WRITE_8(*bufp, val); + break; + case 2: + WRITE_16_L(*bufp, val); + break; + case 4: + WRITE_32_L(*bufp, val); + break; + } + } else { + /* Write value out. */ + intnum_get_sized(intn, *bufp, (size_t)valsize); + *bufp += valsize; + } + return 0; +} diff --git a/src/arch/x86/x86expr.c b/src/arch/x86/x86expr.c index 9855a087..fdcc6c38 100644 --- a/src/arch/x86/x86expr.c +++ b/src/arch/x86/x86expr.c @@ -771,3 +771,27 @@ x86_expr_checkea(expr **ep, unsigned char *addrsize, unsigned char bits, } return 1; } + +int +x86_floatnum_tobytes(const floatnum *flt, unsigned char **bufp, + unsigned long valsize, const expr *e) +{ + int fltret; + + if (!floatnum_check_size(flt, (size_t)valsize)) { + ErrorAt(e->line, _("invalid floating point constant size")); + return 1; + } + + fltret = floatnum_get_sized(flt, *bufp, (size_t)valsize); + if (fltret < 0) { + ErrorAt(e->line, _("underflow in floating point expression")); + return 1; + } + if (fltret > 0) { + ErrorAt(e->line, _("overflow in floating point expression")); + return 1; + } + *bufp += valsize; + return 0; +} diff --git a/src/bytecode.c b/src/bytecode.c index 46188805..04d8649a 100644 --- a/src/bytecode.c +++ b/src/bytecode.c @@ -668,7 +668,7 @@ bc_tobytes_data(bytecode_data *bc_data, unsigned char **bufp, if (slen > 0) { slen = bc_data->size-slen; for (i=0; i<slen; i++) - WRITE_BYTE(*bufp, 0); + WRITE_8(*bufp, 0); } break; } diff --git a/src/file.c b/src/file.c index a6649dc1..77f1aa9e 100644 --- a/src/file.c +++ b/src/file.c @@ -75,7 +75,7 @@ replace_extension(const char *orig, /*@null@*/ const char *ext, } size_t -fwrite_short(unsigned short val, FILE *f) +fwrite_16_l(unsigned short val, FILE *f) { if (fputc(val & 0xFF, f) == EOF) return 0; @@ -85,7 +85,7 @@ fwrite_short(unsigned short val, FILE *f) } size_t -fwrite_long(unsigned long val, FILE *f) +fwrite_32_l(unsigned long val, FILE *f) { if (fputc((int)(val & 0xFF), f) == EOF) return 0; @@ -97,3 +97,27 @@ fwrite_long(unsigned long val, FILE *f) return 0; return 1; } + +size_t +fwrite_16_b(unsigned short val, FILE *f) +{ + if (fputc((val >> 8) & 0xFF, f) == EOF) + return 0; + if (fputc(val & 0xFF, f) == EOF) + return 0; + return 1; +} + +size_t +fwrite_32_b(unsigned long val, FILE *f) +{ + if (fputc((int)((val >> 24) & 0xFF), f) == EOF) + return 0; + if (fputc((int)((val >> 16) & 0xFF), f) == EOF) + return 0; + if (fputc((int)((val >> 8) & 0xFF), f) == EOF) + return 0; + if (fputc((int)(val & 0xFF), f) == EOF) + return 0; + return 1; +} diff --git a/src/file.h b/src/file.h index 2c597620..39407478 100644 --- a/src/file.h +++ b/src/file.h @@ -1,5 +1,5 @@ /* $IdPath$ - * Little-endian file functions header file. + * Big and little endian file functions header file. * * Copyright (C) 2001 Peter Johnson * @@ -33,16 +33,16 @@ /* These functions only work properly if p is an (unsigned char *) */ -#define WRITE_BYTE(ptr, val) \ +#define WRITE_8(ptr, val) \ *((ptr)++) = (unsigned char)((val) & 0xFF) -#define WRITE_SHORT(ptr, val) \ +#define WRITE_16_L(ptr, val) \ do { \ *((ptr)++) = (unsigned char)((val) & 0xFF); \ *((ptr)++) = (unsigned char)(((val) >> 8) & 0xFF); \ } while (0) -#define WRITE_LONG(ptr, val) \ +#define WRITE_32_L(ptr, val) \ do { \ *((ptr)++) = (unsigned char)((val) & 0xFF); \ *((ptr)++) = (unsigned char)(((val) >> 8) & 0xFF); \ @@ -50,18 +50,33 @@ *((ptr)++) = (unsigned char)(((val) >> 24) & 0xFF); \ } while (0) +#define WRITE_16_B(ptr, val) \ + do { \ + *((ptr)++) = (unsigned char)(((val) >> 8) & 0xFF); \ + *((ptr)++) = (unsigned char)((val) & 0xFF); \ + } while (0) + +#define WRITE_32_B(ptr, val) \ + do { \ + *((ptr)++) = (unsigned char)(((val) >> 24) & 0xFF); \ + *((ptr)++) = (unsigned char)(((val) >> 16) & 0xFF); \ + *((ptr)++) = (unsigned char)(((val) >> 8) & 0xFF); \ + *((ptr)++) = (unsigned char)((val) & 0xFF); \ + } while (0) + + /* Non-incrementing versions of the above. */ -#define SAVE_BYTE(ptr, val) \ +#define SAVE_8(ptr, val) \ *(ptr) = (unsigned char)((val) & 0xFF) -#define SAVE_SHORT(ptr, val) \ +#define SAVE_16_L(ptr, val) \ do { \ *(ptr) = (unsigned char)((val) & 0xFF); \ *((ptr)+1) = (unsigned char)(((val) >> 8) & 0xFF); \ } while (0) -#define SAVE_LONG(ptr, val) \ +#define SAVE_32_L(ptr, val) \ do { \ *(ptr) = (unsigned char)((val) & 0xFF); \ *((ptr)+1) = (unsigned char)(((val) >> 8) & 0xFF); \ @@ -69,27 +84,43 @@ *((ptr)+3) = (unsigned char)(((val) >> 24) & 0xFF); \ } while (0) +#define SAVE_16_B(ptr, val) \ + do { \ + *(ptr) = (unsigned char)(((val) >> 8) & 0xFF); \ + *((ptr)+1) = (unsigned char)((val) & 0xFF); \ + } while (0) + +#define SAVE_32_B(ptr, val) \ + do { \ + *(ptr) = (unsigned char)(((val) >> 24) & 0xFF); \ + *((ptr)+1) = (unsigned char)(((val) >> 16) & 0xFF); \ + *((ptr)+2) = (unsigned char)(((val) >> 8) & 0xFF); \ + *((ptr)+3) = (unsigned char)((val) & 0xFF); \ + } while (0) + /* Direct-to-file versions of the above. Using the above macros and a single * fwrite() will probably be faster than calling these functions many times. * These functions return 1 if the write was successful, 0 if not (so their * return values can be used like the return value from fwrite()). */ -size_t fwrite_short(unsigned short val, FILE *f); -size_t fwrite_long(unsigned long val, FILE *f); +size_t fwrite_16_l(unsigned short val, FILE *f); +size_t fwrite_32_l(unsigned long val, FILE *f); +size_t fwrite_16_b(unsigned short val, FILE *f); +size_t fwrite_32_b(unsigned long val, FILE *f); /* Read/Load versions. val is the variable to receive the data. */ -#define READ_BYTE(val, ptr) \ +#define READ_8(val, ptr) \ (val) = *((ptr)++) & 0xFF -#define READ_SHORT(val, ptr) \ +#define READ_16_L(val, ptr) \ do { \ (val) = *((ptr)++) & 0xFF; \ (val) |= (*((ptr)++) & 0xFF) << 8; \ } while (0) -#define READ_LONG(val, ptr) \ +#define READ_32_L(val, ptr) \ do { \ (val) = *((ptr)++) & 0xFF; \ (val) |= (*((ptr)++) & 0xFF) << 8; \ @@ -97,18 +128,32 @@ size_t fwrite_long(unsigned long val, FILE *f); (val) |= (*((ptr)++) & 0xFF) << 24; \ } while (0) +#define READ_16_B(val, ptr) \ + do { \ + (val) = (*((ptr)++) & 0xFF) << 8; \ + (val) |= *((ptr)++) & 0xFF; \ + } while (0) + +#define READ_32_B(val, ptr) \ + do { \ + (val) = (*((ptr)++) & 0xFF) << 24; \ + (val) |= (*((ptr)++) & 0xFF) << 16; \ + (val) |= (*((ptr)++) & 0xFF) << 8; \ + (val) |= *((ptr)++) & 0xFF; \ + } while (0) + /* Non-incrementing versions of the above. */ -#define LOAD_BYTE(val, ptr) \ +#define LOAD_8(val, ptr) \ (val) = *(ptr) & 0xFF -#define LOAD_SHORT(val, ptr) \ +#define LOAD_16_L(val, ptr) \ do { \ (val) = *(ptr) & 0xFF; \ (val) |= (*((ptr)+1) & 0xFF) << 8; \ } while (0) -#define LOAD_LONG(val, ptr) \ +#define LOAD_32_L(val, ptr) \ do { \ (val) = (unsigned long)(*(ptr) & 0xFF); \ (val) |= (unsigned long)((*((ptr)+1) & 0xFF) << 8); \ @@ -116,4 +161,18 @@ size_t fwrite_long(unsigned long val, FILE *f); (val) |= (unsigned long)((*((ptr)+3) & 0xFF) << 24); \ } while (0) +#define LOAD_16_B(val, ptr) \ + do { \ + (val) = (*(ptr) & 0xFF) << 8; \ + (val) |= *((ptr)+1) & 0xFF; \ + } while (0) + +#define LOAD_32_B(val, ptr) \ + do { \ + (val) = (unsigned long)((*(ptr) & 0xFF) << 24); \ + (val) |= (unsigned long)((*((ptr)+1) & 0xFF) << 16); \ + (val) |= (unsigned long)((*((ptr)+2) & 0xFF) << 8); \ + (val) |= (unsigned long)(*((ptr)+3) & 0xFF); \ + } while (0) + #endif diff --git a/src/floatnum.c b/src/floatnum.c index 9f4e936b..6f98dc26 100644 --- a/src/floatnum.c +++ b/src/floatnum.c @@ -529,7 +529,7 @@ floatnum_get_int(const floatnum *flt, unsigned long *ret_val) return 1; } - LOAD_LONG(*ret_val, &t[0]); + LOAD_32_L(*ret_val, &t[0]); return 0; } diff --git a/src/intnum.c b/src/intnum.c index 99d47862..38c57221 100644 --- a/src/intnum.c +++ b/src/intnum.c @@ -551,7 +551,7 @@ intnum_get_sized(const intnum *intn, unsigned char *ptr, size_t size) case INTNUM_UL: ul = intn->val.ul; while (size-- > 0) { - WRITE_BYTE(ptr, ul); + WRITE_8(ptr, ul); if (ul != 0) ul >>= 8; } diff --git a/src/objfmts/bin/bin-objfmt.c b/src/objfmts/bin/bin-objfmt.c index f408adb8..bf4823d1 100644 --- a/src/objfmts/bin/bin-objfmt.c +++ b/src/objfmts/bin/bin-objfmt.c @@ -37,6 +37,7 @@ #include "expr-int.h" #include "bc-int.h" +#include "arch.h" #include "objfmt.h" @@ -106,7 +107,7 @@ bin_objfmt_output_expr(expr **ep, unsigned char **bufp, unsigned long valsize, /*@observer@*/ const bytecode *bc, int rel, /*@unused@*/ /*@null@*/ void *d) { - /*@dependent@*/ /*@null@*/ const intnum *num; + /*@dependent@*/ /*@null@*/ const intnum *intn; /*@dependent@*/ /*@null@*/ const floatnum *flt; assert(info != NULL); @@ -120,54 +121,13 @@ bin_objfmt_output_expr(expr **ep, unsigned char **bufp, unsigned long valsize, /* Handle floating point expressions */ flt = expr_get_floatnum(ep); - if (flt) { - int fltret; - - if (!floatnum_check_size(flt, (size_t)valsize)) { - ErrorAt((*ep)->line, _("invalid floating point constant size")); - return 1; - } - - fltret = floatnum_get_sized(flt, *bufp, (size_t)valsize); - if (fltret < 0) { - ErrorAt((*ep)->line, _("underflow in floating point expression")); - return 1; - } - if (fltret > 0) { - ErrorAt((*ep)->line, _("overflow in floating point expression")); - return 1; - } - *bufp += valsize; - return 0; - } + if (flt) + return cur_arch->floatnum_tobytes(flt, bufp, valsize, *ep); /* Handle integer expressions */ - num = expr_get_intnum(ep, NULL); - if (num) { - if (rel) { - long val; - if (valsize != 1 && valsize != 2 && valsize != 4) - InternalError(_("tried to do PC-relative offset from invalid sized value")); - val = intnum_get_uint(num); - val -= bc->len; - switch (valsize) { - case 1: - WRITE_BYTE(*bufp, val); - break; - case 2: - WRITE_SHORT(*bufp, val); - break; - case 4: - WRITE_LONG(*bufp, val); - break; - } - } else { - /* Write value out. */ - intnum_get_sized(num, *bufp, (size_t)valsize); - *bufp += valsize; - } - return 0; - } + intn = expr_get_intnum(ep, NULL); + if (intn) + return cur_arch->intnum_tobytes(intn, bufp, valsize, *ep, bc, rel); /* Check for complex float expressions */ if (expr_contains(*ep, EXPR_FLOAT)) { -- 2.40.0