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