yasm/libyasm/bytecode.c
Peter Johnson d151392af8 Big output_expr(), intnum_tobytes(), and floatnum_tobytes() changes:
- Switch to bit-based output, including shift capability
 - This means the standard intnum output functions can be used for non-byte
   oriented archs like LC-3b (implemented)
 - Default out of range (overflow) warnings for intnum (bugzilla bug 14)
 - Change floating point overflow/underflow errors to warnings
To do (hooks but not implemented):
 - Shifting floatnums into destination
 - Floatnum destinations larger than floatnum value
 - Big endian support for intnum and floatnum
Related simultaneous changes:
 - Use bc instead of ep in objfmt output_expr() functions; while bc->line
   should == (*ep)->line, in case they differ, we want to use the bc->line
   so as not to confuse users.
 - lc3b-mp22NC test was not properly offsetting the accessed variables, but
   since the variable "sections" started at an aligned offset, the output
   was actually correct.  The new intnum warnings uncovered this issue, so
   fix code to be correct (and not generate warnings).

svn path=/trunk/yasm/; revision=1017
2003-07-25 03:27:21 +00:00

1015 lines
26 KiB
C

/*
* Bytecode utility functions
*
* Copyright (C) 2001 Peter Johnson
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
*
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND OTHER CONTRIBUTORS ``AS IS''
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR OTHER CONTRIBUTORS BE
* LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
* POSSIBILITY OF SUCH DAMAGE.
*/
#define YASM_LIB_INTERNAL
#include "util.h"
/*@unused@*/ RCSID("$IdPath$");
#include "coretype.h"
#include "file.h"
#include "errwarn.h"
#include "intnum.h"
#include "expr.h"
#include "bytecode.h"
#include "objfmt.h"
#include "arch.h"
#include "bc-int.h"
#include "expr-int.h"
struct yasm_dataval {
/*@reldef@*/ STAILQ_ENTRY(yasm_dataval) link;
enum { DV_EMPTY, DV_EXPR, DV_STRING } type;
union {
/*@only@*/ yasm_expr *expn;
/*@only@*/ char *str_val;
} data;
};
typedef struct bytecode_data {
yasm_bytecode bc; /* base structure */
/* non-converted data (linked list) */
yasm_datavalhead datahead;
/* final (converted) size of each element (in bytes) */
unsigned char size;
} bytecode_data;
typedef struct bytecode_reserve {
yasm_bytecode bc; /* base structure */
/*@only@*/ yasm_expr *numitems; /* number of items to reserve */
unsigned char itemsize; /* size of each item (in bytes) */
} bytecode_reserve;
typedef struct bytecode_incbin {
yasm_bytecode bc; /* base structure */
/*@only@*/ char *filename; /* file to include data from */
/* starting offset to read from (NULL=0) */
/*@only@*/ /*@null@*/ yasm_expr *start;
/* maximum number of bytes to read (NULL=no limit) */
/*@only@*/ /*@null@*/ yasm_expr *maxlen;
} bytecode_incbin;
typedef struct bytecode_align {
yasm_bytecode bc; /* base structure */
unsigned long boundary; /* alignment boundary */
} bytecode_align;
typedef struct bytecode_objfmt_data {
yasm_bytecode bc; /* base structure */
unsigned int type; /* objfmt-specific type */
/*@dependent@*/ yasm_objfmt *of; /* objfmt that created the data */
/*@only@*/ void *data; /* objfmt-specific data */
} bytecode_objfmt_data;
/* Static structures for when NULL is passed to conversion functions. */
/* for Convert*ToBytes() */
unsigned char bytes_static[16];
/*@dependent@*/ static yasm_arch *cur_arch;
void
yasm_bc_initialize(yasm_arch *a)
{
cur_arch = a;
}
yasm_immval *
yasm_imm_new_int(unsigned long int_val, unsigned long lindex)
{
return yasm_imm_new_expr(
yasm_expr_new_ident(yasm_expr_int(yasm_intnum_new_uint(int_val)),
lindex));
}
yasm_immval *
yasm_imm_new_expr(yasm_expr *expr_ptr)
{
yasm_immval *im = yasm_xmalloc(sizeof(yasm_immval));
im->val = expr_ptr;
im->len = 0;
im->sign = 0;
return im;
}
const yasm_expr *
yasm_ea_get_disp(const yasm_effaddr *ptr)
{
return ptr->disp;
}
void
yasm_ea_set_len(yasm_effaddr *ptr, unsigned int len)
{
if (!ptr)
return;
/* Currently don't warn if length truncated, as this is called only from
* an explicit override, where we expect the user knows what they're doing.
*/
ptr->len = (unsigned char)len;
}
void
yasm_ea_set_nosplit(yasm_effaddr *ptr, unsigned int nosplit)
{
if (!ptr)
return;
ptr->nosplit = (unsigned char)nosplit;
}
/*@-nullstate@*/
void
yasm_ea_delete(yasm_effaddr *ea)
{
if (cur_arch->ea_data_delete)
cur_arch->ea_data_delete(ea);
yasm_expr_delete(ea->disp);
yasm_xfree(ea);
}
/*@=nullstate@*/
/*@-nullstate@*/
void
yasm_ea_print(FILE *f, int indent_level, const yasm_effaddr *ea)
{
fprintf(f, "%*sDisp=", indent_level, "");
yasm_expr_print(f, ea->disp);
fprintf(f, "\n%*sLen=%u\n", indent_level, "", (unsigned int)ea->len);
fprintf(f, "%*sNoSplit=%u\n", indent_level, "", (unsigned int)ea->nosplit);
if (cur_arch->ea_data_print)
cur_arch->ea_data_print(f, indent_level, ea);
}
/*@=nullstate@*/
void
yasm_bc_set_multiple(yasm_bytecode *bc, yasm_expr *e)
{
if (bc->multiple)
bc->multiple = yasm_expr_new_tree(bc->multiple, YASM_EXPR_MUL, e,
e->line);
else
bc->multiple = e;
}
yasm_bytecode *
yasm_bc_new_common(yasm_bytecode_type type, size_t size, unsigned long lindex)
{
yasm_bytecode *bc = yasm_xmalloc(size);
bc->type = type;
bc->multiple = (yasm_expr *)NULL;
bc->len = 0;
bc->line = lindex;
bc->offset = 0;
bc->opt_flags = 0;
return bc;
}
yasm_bytecode *
yasm_bc_new_data(yasm_datavalhead *datahead, unsigned int size,
unsigned long lindex)
{
bytecode_data *data;
data = (bytecode_data *)
yasm_bc_new_common(YASM_BC__DATA, sizeof(bytecode_data), lindex);
data->datahead = *datahead;
data->size = (unsigned char)size;
return (yasm_bytecode *)data;
}
yasm_bytecode *
yasm_bc_new_reserve(yasm_expr *numitems, unsigned int itemsize,
unsigned long lindex)
{
bytecode_reserve *reserve;
reserve = (bytecode_reserve *)
yasm_bc_new_common(YASM_BC__RESERVE, sizeof(bytecode_reserve), lindex);
/*@-mustfree@*/
reserve->numitems = numitems;
/*@=mustfree@*/
reserve->itemsize = (unsigned char)itemsize;
return (yasm_bytecode *)reserve;
}
yasm_bytecode *
yasm_bc_new_incbin(char *filename, yasm_expr *start, yasm_expr *maxlen,
unsigned long lindex)
{
bytecode_incbin *incbin;
incbin = (bytecode_incbin *)
yasm_bc_new_common(YASM_BC__INCBIN, sizeof(bytecode_incbin), lindex);
/*@-mustfree@*/
incbin->filename = filename;
incbin->start = start;
incbin->maxlen = maxlen;
/*@=mustfree@*/
return (yasm_bytecode *)incbin;
}
yasm_bytecode *
yasm_bc_new_align(unsigned long boundary, unsigned long lindex)
{
bytecode_align *align;
align = (bytecode_align *)
yasm_bc_new_common(YASM_BC__ALIGN, sizeof(bytecode_align), lindex);
align->boundary = boundary;
return (yasm_bytecode *)align;
}
yasm_bytecode *
yasm_bc_new_objfmt_data(unsigned int type, unsigned long len, yasm_objfmt *of,
void *data, unsigned long lindex)
{
bytecode_objfmt_data *objfmt_data;
objfmt_data = (bytecode_objfmt_data *)
yasm_bc_new_common(YASM_BC__OBJFMT_DATA, sizeof(bytecode_objfmt_data),
lindex);
objfmt_data->type = type;
objfmt_data->of = of;
/*@-mustfree@*/
objfmt_data->data = data;
/*@=mustfree@*/
/* Yes, this breaks the paradigm just a little. But this data is very
* unlike other bytecode data--it's internally generated after the
* other bytecodes have been resolved, and the length is ALWAYS known.
*/
objfmt_data->bc.len = len;
return (yasm_bytecode *)objfmt_data;
}
void
yasm_bc_delete(yasm_bytecode *bc)
{
bytecode_data *data;
bytecode_reserve *reserve;
bytecode_incbin *incbin;
bytecode_objfmt_data *objfmt_data;
if (!bc)
return;
/*@-branchstate@*/
switch (bc->type) {
case YASM_BC__EMPTY:
break;
case YASM_BC__DATA:
data = (bytecode_data *)bc;
yasm_dvs_delete(&data->datahead);
break;
case YASM_BC__RESERVE:
reserve = (bytecode_reserve *)bc;
yasm_expr_delete(reserve->numitems);
break;
case YASM_BC__INCBIN:
incbin = (bytecode_incbin *)bc;
yasm_xfree(incbin->filename);
yasm_expr_delete(incbin->start);
yasm_expr_delete(incbin->maxlen);
break;
case YASM_BC__ALIGN:
break;
case YASM_BC__OBJFMT_DATA:
objfmt_data = (bytecode_objfmt_data *)bc;
if (objfmt_data->of->bc_objfmt_data_delete)
objfmt_data->of->bc_objfmt_data_delete(objfmt_data->type,
objfmt_data->data);
else
yasm_internal_error(
N_("objfmt can't handle its own objfmt data bytecode"));
break;
default:
if ((unsigned int)bc->type < (unsigned int)cur_arch->bc_type_max)
cur_arch->bc_delete(bc);
else
yasm_internal_error(N_("Unknown bytecode type"));
break;
}
/*@=branchstate@*/
yasm_expr_delete(bc->multiple);
yasm_xfree(bc);
}
void
yasm_bc_print(FILE *f, int indent_level, const yasm_bytecode *bc)
{
const bytecode_data *data;
const bytecode_reserve *reserve;
const bytecode_incbin *incbin;
const bytecode_align *align;
const bytecode_objfmt_data *objfmt_data;
switch (bc->type) {
case YASM_BC__EMPTY:
fprintf(f, "%*s_Empty_\n", indent_level, "");
break;
case YASM_BC__DATA:
data = (const bytecode_data *)bc;
fprintf(f, "%*s_Data_\n", indent_level, "");
fprintf(f, "%*sFinal Element Size=%u\n", indent_level+1, "",
(unsigned int)data->size);
fprintf(f, "%*sElements:\n", indent_level+1, "");
yasm_dvs_print(f, indent_level+2, &data->datahead);
break;
case YASM_BC__RESERVE:
reserve = (const bytecode_reserve *)bc;
fprintf(f, "%*s_Reserve_\n", indent_level, "");
fprintf(f, "%*sNum Items=", indent_level, "");
yasm_expr_print(f, reserve->numitems);
fprintf(f, "\n%*sItem Size=%u\n", indent_level, "",
(unsigned int)reserve->itemsize);
break;
case YASM_BC__INCBIN:
incbin = (const bytecode_incbin *)bc;
fprintf(f, "%*s_IncBin_\n", indent_level, "");
fprintf(f, "%*sFilename=`%s'\n", indent_level, "",
incbin->filename);
fprintf(f, "%*sStart=", indent_level, "");
if (!incbin->start)
fprintf(f, "nil (0)");
else
yasm_expr_print(f, incbin->start);
fprintf(f, "%*sMax Len=", indent_level, "");
if (!incbin->maxlen)
fprintf(f, "nil (unlimited)");
else
yasm_expr_print(f, incbin->maxlen);
fprintf(f, "\n");
break;
case YASM_BC__ALIGN:
align = (const bytecode_align *)bc;
fprintf(f, "%*s_Align_\n", indent_level, "");
fprintf(f, "%*sBoundary=%lu\n", indent_level, "", align->boundary);
break;
case YASM_BC__OBJFMT_DATA:
objfmt_data = (const bytecode_objfmt_data *)bc;
fprintf(f, "%*s_ObjFmt_Data_\n", indent_level, "");
if (objfmt_data->of->bc_objfmt_data_print)
objfmt_data->of->bc_objfmt_data_print(f, indent_level,
objfmt_data->type,
objfmt_data->data);
else
fprintf(f, "%*sUNKNOWN\n", indent_level, "");
break;
default:
if ((unsigned int)bc->type < (unsigned int)cur_arch->bc_type_max)
cur_arch->bc_print(f, indent_level, bc);
else
fprintf(f, "%*s_Unknown_\n", indent_level, "");
break;
}
fprintf(f, "%*sMultiple=", indent_level, "");
if (!bc->multiple)
fprintf(f, "nil (1)");
else
yasm_expr_print(f, bc->multiple);
fprintf(f, "\n%*sLength=%lu\n", indent_level, "", bc->len);
fprintf(f, "%*sLine Index=%lu\n", indent_level, "", bc->line);
fprintf(f, "%*sOffset=%lx\n", indent_level, "", bc->offset);
}
/*@null@*/ yasm_intnum *
yasm_common_calc_bc_dist(yasm_section *sect, /*@null@*/ yasm_bytecode *precbc1,
/*@null@*/ yasm_bytecode *precbc2)
{
unsigned int dist;
yasm_intnum *intn;
if (precbc2) {
dist = precbc2->offset + precbc2->len;
if (precbc1) {
if (dist < precbc1->offset + precbc1->len) {
intn = yasm_intnum_new_uint(precbc1->offset + precbc1->len
- dist);
yasm_intnum_calc(intn, YASM_EXPR_NEG, NULL, precbc1->line);
return intn;
}
dist -= precbc1->offset + precbc1->len;
}
return yasm_intnum_new_uint(dist);
} else {
if (precbc1) {
intn = yasm_intnum_new_uint(precbc1->offset + precbc1->len);
yasm_intnum_calc(intn, YASM_EXPR_NEG, NULL, precbc1->line);
return intn;
} else {
return yasm_intnum_new_uint(0);
}
}
}
static yasm_bc_resolve_flags
bc_resolve_data(bytecode_data *bc_data, unsigned long *len)
{
yasm_dataval *dv;
size_t slen;
/* Count up element sizes, rounding up string length. */
STAILQ_FOREACH(dv, &bc_data->datahead, link) {
switch (dv->type) {
case DV_EMPTY:
break;
case DV_EXPR:
*len += bc_data->size;
break;
case DV_STRING:
slen = strlen(dv->data.str_val);
/* find count, rounding up to nearest multiple of size */
slen = (slen + bc_data->size - 1) / bc_data->size;
*len += slen*bc_data->size;
break;
}
}
return YASM_BC_RESOLVE_MIN_LEN;
}
static yasm_bc_resolve_flags
bc_resolve_reserve(bytecode_reserve *reserve, unsigned long *len,
int save, unsigned long line, const yasm_section *sect,
yasm_calc_bc_dist_func calc_bc_dist)
{
yasm_bc_resolve_flags retval = YASM_BC_RESOLVE_MIN_LEN;
/*@null@*/ yasm_expr *temp;
yasm_expr **tempp;
/*@dependent@*/ /*@null@*/ const yasm_intnum *num;
if (save) {
temp = NULL;
tempp = &reserve->numitems;
} else {
temp = yasm_expr_copy(reserve->numitems);
assert(temp != NULL);
tempp = &temp;
}
num = yasm_expr_get_intnum(tempp, calc_bc_dist);
if (!num) {
/* For reserve, just say non-constant quantity instead of allowing
* the circular reference error to filter through.
*/
if (temp && yasm_expr__contains(temp, YASM_EXPR_FLOAT))
yasm__error(line,
N_("expression must not contain floating point value"));
else
yasm__error(line,
N_("attempt to reserve non-constant quantity of space"));
retval = YASM_BC_RESOLVE_ERROR | YASM_BC_RESOLVE_UNKNOWN_LEN;
} else
*len += yasm_intnum_get_uint(num)*reserve->itemsize;
yasm_expr_delete(temp);
return retval;
}
static yasm_bc_resolve_flags
bc_resolve_incbin(bytecode_incbin *incbin, unsigned long *len, int save,
unsigned long line, const yasm_section *sect,
yasm_calc_bc_dist_func calc_bc_dist)
{
FILE *f;
/*@null@*/ yasm_expr *temp;
yasm_expr **tempp;
/*@dependent@*/ /*@null@*/ const yasm_intnum *num;
unsigned long start = 0, maxlen = 0xFFFFFFFFUL, flen;
/* Try to convert start to integer value */
if (incbin->start) {
if (save) {
temp = NULL;
tempp = &incbin->start;
} else {
temp = yasm_expr_copy(incbin->start);
assert(temp != NULL);
tempp = &temp;
}
num = yasm_expr_get_intnum(tempp, calc_bc_dist);
if (num)
start = yasm_intnum_get_uint(num);
yasm_expr_delete(temp);
if (!num)
return YASM_BC_RESOLVE_UNKNOWN_LEN;
}
/* Try to convert maxlen to integer value */
if (incbin->maxlen) {
if (save) {
temp = NULL;
tempp = &incbin->maxlen;
} else {
temp = yasm_expr_copy(incbin->maxlen);
assert(temp != NULL);
tempp = &temp;
}
num = yasm_expr_get_intnum(tempp, calc_bc_dist);
if (num)
maxlen = yasm_intnum_get_uint(num);
yasm_expr_delete(temp);
if (!num)
return YASM_BC_RESOLVE_UNKNOWN_LEN;
}
/* FIXME: Search include path for filename. Save full path back into
* filename if save is true.
*/
/* Open file and determine its length */
f = fopen(incbin->filename, "rb");
if (!f) {
yasm__error(line, N_("`incbin': unable to open file `%s'"),
incbin->filename);
return YASM_BC_RESOLVE_ERROR | YASM_BC_RESOLVE_UNKNOWN_LEN;
}
if (fseek(f, 0L, SEEK_END) < 0) {
yasm__error(line, N_("`incbin': unable to seek on file `%s'"),
incbin->filename);
return YASM_BC_RESOLVE_ERROR | YASM_BC_RESOLVE_UNKNOWN_LEN;
}
flen = (unsigned long)ftell(f);
fclose(f);
/* Compute length of incbin from start, maxlen, and len */
if (start > flen) {
yasm__warning(YASM_WARN_GENERAL, line,
N_("`incbin': start past end of file `%s'"),
incbin->filename);
start = flen;
}
flen -= start;
if (incbin->maxlen)
if (maxlen < flen)
flen = maxlen;
*len += flen;
return YASM_BC_RESOLVE_MIN_LEN;
}
yasm_bc_resolve_flags
yasm_bc_resolve(yasm_bytecode *bc, int save, const yasm_section *sect,
yasm_calc_bc_dist_func calc_bc_dist)
{
yasm_bc_resolve_flags retval = YASM_BC_RESOLVE_MIN_LEN;
/*@null@*/ yasm_expr *temp;
yasm_expr **tempp;
/*@dependent@*/ /*@null@*/ const yasm_intnum *num;
bc->len = 0; /* start at 0 */
switch (bc->type) {
case YASM_BC__EMPTY:
yasm_internal_error(N_("got empty bytecode in bc_calc_len"));
/*break;*/
case YASM_BC__DATA:
retval = bc_resolve_data((bytecode_data *)bc, &bc->len);
break;
case YASM_BC__RESERVE:
retval = bc_resolve_reserve((bytecode_reserve *)bc, &bc->len,
save, bc->line, sect, calc_bc_dist);
break;
case YASM_BC__INCBIN:
retval = bc_resolve_incbin((bytecode_incbin *)bc, &bc->len,
save, bc->line, sect, calc_bc_dist);
break;
case YASM_BC__ALIGN:
/* TODO */
yasm_internal_error(N_("TODO: align bytecode not implemented!"));
/*break;*/
case YASM_BC__OBJFMT_DATA:
yasm_internal_error(N_("resolving objfmt data bytecode?"));
/*break;*/
default:
if ((unsigned int)bc->type < (unsigned int)cur_arch->bc_type_max)
retval = cur_arch->bc_resolve(bc, save, sect, calc_bc_dist);
else
yasm_internal_error(N_("Unknown bytecode type"));
}
/* Multiply len by number of multiples */
if (bc->multiple) {
if (save) {
temp = NULL;
tempp = &bc->multiple;
} else {
temp = yasm_expr_copy(bc->multiple);
assert(temp != NULL);
tempp = &temp;
}
num = yasm_expr_get_intnum(tempp, calc_bc_dist);
if (!num) {
retval = YASM_BC_RESOLVE_UNKNOWN_LEN;
if (temp && yasm_expr__contains(temp, YASM_EXPR_FLOAT)) {
yasm__error(bc->line,
N_("expression must not contain floating point value"));
retval |= YASM_BC_RESOLVE_ERROR;
}
} else
bc->len *= yasm_intnum_get_uint(num);
yasm_expr_delete(temp);
}
/* If we got an error somewhere along the line, clear out any calc len */
if (retval & YASM_BC_RESOLVE_UNKNOWN_LEN)
bc->len = 0;
return retval;
}
static int
bc_tobytes_data(bytecode_data *bc_data, unsigned char **bufp,
const yasm_section *sect, yasm_bytecode *bc, void *d,
yasm_output_expr_func output_expr)
/*@sets **bufp@*/
{
yasm_dataval *dv;
size_t slen;
size_t i;
unsigned char *bufp_orig = *bufp;
STAILQ_FOREACH(dv, &bc_data->datahead, link) {
switch (dv->type) {
case DV_EMPTY:
break;
case DV_EXPR:
if (output_expr(&dv->data.expn, *bufp, bc_data->size,
bc_data->size*8, 0,
(unsigned long)(*bufp-bufp_orig), sect, bc, 0,
1, d))
return 1;
*bufp += bc_data->size;
break;
case DV_STRING:
slen = strlen(dv->data.str_val);
strncpy((char *)*bufp, dv->data.str_val, slen);
*bufp += slen;
/* pad with 0's to nearest multiple of size */
slen %= bc_data->size;
if (slen > 0) {
slen = bc_data->size-slen;
for (i=0; i<slen; i++)
YASM_WRITE_8(*bufp, 0);
}
break;
}
}
return 0;
}
static int
bc_tobytes_incbin(bytecode_incbin *incbin, unsigned char **bufp,
unsigned long len, unsigned long line)
/*@sets **bufp@*/
{
FILE *f;
/*@dependent@*/ /*@null@*/ const yasm_intnum *num;
unsigned long start = 0;
/* Convert start to integer value */
if (incbin->start) {
num = yasm_expr_get_intnum(&incbin->start, NULL);
if (!num)
yasm_internal_error(
N_("could not determine start in bc_tobytes_incbin"));
start = yasm_intnum_get_uint(num);
}
/* Open file */
f = fopen(incbin->filename, "rb");
if (!f) {
yasm__error(line, N_("`incbin': unable to open file `%s'"),
incbin->filename);
return 1;
}
/* Seek to start of data */
if (fseek(f, (long)start, SEEK_SET) < 0) {
yasm__error(line, N_("`incbin': unable to seek on file `%s'"),
incbin->filename);
fclose(f);
return 1;
}
/* Read len bytes */
if (fread(*bufp, (size_t)len, 1, f) < (size_t)len) {
yasm__error(line,
N_("`incbin': unable to read %lu bytes from file `%s'"),
len, incbin->filename);
fclose(f);
return 1;
}
*bufp += len;
fclose(f);
return 0;
}
/*@null@*/ /*@only@*/ unsigned char *
yasm_bc_tobytes(yasm_bytecode *bc, unsigned char *buf, unsigned long *bufsize,
/*@out@*/ unsigned long *multiple, /*@out@*/ int *gap,
const yasm_section *sect, void *d,
yasm_output_expr_func output_expr,
/*@null@*/ yasm_output_bc_objfmt_data_func
output_bc_objfmt_data)
/*@sets *buf@*/
{
/*@only@*/ /*@null@*/ unsigned char *mybuf = NULL;
unsigned char *origbuf, *destbuf;
/*@dependent@*/ /*@null@*/ const yasm_intnum *num;
bytecode_objfmt_data *objfmt_data;
unsigned long datasize;
int error = 0;
if (bc->multiple) {
num = yasm_expr_get_intnum(&bc->multiple, NULL);
if (!num)
yasm_internal_error(
N_("could not determine multiple in bc_tobytes"));
*multiple = yasm_intnum_get_uint(num);
if (*multiple == 0) {
*bufsize = 0;
return NULL;
}
} else
*multiple = 1;
datasize = bc->len / (*multiple);
*bufsize = datasize;
if (bc->type == YASM_BC__RESERVE) {
*gap = 1;
return NULL; /* we didn't allocate a buffer */
}
*gap = 0;
if (*bufsize < datasize) {
mybuf = yasm_xmalloc(sizeof(bc->len));
origbuf = mybuf;
destbuf = mybuf;
} else {
origbuf = buf;
destbuf = buf;
}
switch (bc->type) {
case YASM_BC__EMPTY:
yasm_internal_error(N_("got empty bytecode in bc_tobytes"));
/*break;*/
case YASM_BC__DATA:
error = bc_tobytes_data((bytecode_data *)bc, &destbuf, sect, bc, d,
output_expr);
break;
case YASM_BC__INCBIN:
error = bc_tobytes_incbin((bytecode_incbin *)bc, &destbuf, bc->len,
bc->line);
break;
case YASM_BC__ALIGN:
/* TODO */
yasm_internal_error(N_("TODO: align bytecode not implemented!"));
/*break;*/
case YASM_BC__OBJFMT_DATA:
objfmt_data = (bytecode_objfmt_data *)bc;
if (output_bc_objfmt_data)
error = output_bc_objfmt_data(objfmt_data->type,
objfmt_data->data, &destbuf);
else
yasm_internal_error(
N_("Have objfmt data bytecode but no way to output it"));
break;
default:
if ((unsigned int)bc->type < (unsigned int)cur_arch->bc_type_max)
error = cur_arch->bc_tobytes(bc, &destbuf, sect, d,
output_expr);
else
yasm_internal_error(N_("Unknown bytecode type"));
}
if (!error && ((unsigned long)(destbuf - origbuf) != datasize))
yasm_internal_error(
N_("written length does not match optimized length"));
return mybuf;
}
yasm_bytecode *
yasm_bcs_last(yasm_bytecodehead *headp)
{
return STAILQ_LAST(headp, yasm_bytecode, link);
}
void
yasm_bcs_delete(yasm_bytecodehead *headp)
{
yasm_bytecode *cur, *next;
cur = STAILQ_FIRST(headp);
while (cur) {
next = STAILQ_NEXT(cur, link);
yasm_bc_delete(cur);
cur = next;
}
STAILQ_INIT(headp);
yasm_xfree(headp);
}
yasm_bytecode *
yasm_bcs_append(yasm_bytecodehead *headp, yasm_bytecode *bc)
{
if (bc) {
if (bc->type != YASM_BC__EMPTY) {
STAILQ_INSERT_TAIL(headp, bc, link);
return bc;
} else {
yasm_xfree(bc);
}
}
return (yasm_bytecode *)NULL;
}
void
yasm_bcs_print(FILE *f, int indent_level, const yasm_bytecodehead *headp)
{
yasm_bytecode *cur;
STAILQ_FOREACH(cur, headp, link) {
fprintf(f, "%*sNext Bytecode:\n", indent_level, "");
yasm_bc_print(f, indent_level+1, cur);
}
}
int
yasm_bcs_traverse(yasm_bytecodehead *headp, void *d,
int (*func) (yasm_bytecode *bc, /*@null@*/ void *d))
{
yasm_bytecode *cur;
STAILQ_FOREACH(cur, headp, link) {
int retval = func(cur, d);
if (retval != 0)
return retval;
}
return 0;
}
yasm_dataval *
yasm_dv_new_expr(yasm_expr *expn)
{
yasm_dataval *retval = yasm_xmalloc(sizeof(yasm_dataval));
retval->type = DV_EXPR;
retval->data.expn = expn;
return retval;
}
yasm_dataval *
yasm_dv_new_string(char *str_val)
{
yasm_dataval *retval = yasm_xmalloc(sizeof(yasm_dataval));
retval->type = DV_STRING;
retval->data.str_val = str_val;
return retval;
}
void
yasm_dvs_delete(yasm_datavalhead *headp)
{
yasm_dataval *cur, *next;
cur = STAILQ_FIRST(headp);
while (cur) {
next = STAILQ_NEXT(cur, link);
switch (cur->type) {
case DV_EXPR:
yasm_expr_delete(cur->data.expn);
break;
case DV_STRING:
yasm_xfree(cur->data.str_val);
break;
default:
break;
}
yasm_xfree(cur);
cur = next;
}
STAILQ_INIT(headp);
}
yasm_dataval *
yasm_dvs_append(yasm_datavalhead *headp, yasm_dataval *dv)
{
if (dv) {
STAILQ_INSERT_TAIL(headp, dv, link);
return dv;
}
return (yasm_dataval *)NULL;
}
void
yasm_dvs_print(FILE *f, int indent_level, const yasm_datavalhead *head)
{
yasm_dataval *cur;
STAILQ_FOREACH(cur, head, link) {
switch (cur->type) {
case DV_EMPTY:
fprintf(f, "%*sEmpty\n", indent_level, "");
break;
case DV_EXPR:
fprintf(f, "%*sExpr=", indent_level, "");
yasm_expr_print(f, cur->data.expn);
fprintf(f, "\n");
break;
case DV_STRING:
fprintf(f, "%*sString=%s\n", indent_level, "",
cur->data.str_val);
break;
}
}
}
yasm_bytecodehead *
yasm_bcs_new(void)
{
yasm_bytecodehead *headp;
headp = yasm_xmalloc(sizeof(yasm_bytecodehead));
STAILQ_INIT(headp);
return headp;
}
/* Non-macro yasm_bcs_first() for non-YASM_LIB_INTERNAL users. */
#undef yasm_bcs_first
yasm_bytecode *
yasm_bcs_first(yasm_bytecodehead *headp)
{
return STAILQ_FIRST(headp);
}
/* Non-macro yasm_dvs_initialize() for non-YASM_LIB_INTERNAL users. */
#undef yasm_dvs_initialize
void
yasm_dvs_initialize(yasm_datavalhead *headp)
{
STAILQ_INIT(headp);
}