blob: d7880cefd33377c61061728fa87c386b5d67e9bf [file] [log] [blame]
/*
* 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("$Id$");
#include "coretype.h"
#include "file.h"
#include "errwarn.h"
#include "intnum.h"
#include "expr.h"
#include "bytecode.h"
#include "objfmt.h"
#include "dbgfmt.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;
};
/* Standard bytecode types */
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;
/* Standard bytecode callback function prototypes */
static void bc_data_destroy(yasm_bytecode *bc);
static void bc_data_print(const yasm_bytecode *bc, FILE *f, int indent_level);
static yasm_bc_resolve_flags bc_data_resolve
(yasm_bytecode *bc, int save, yasm_calc_bc_dist_func calc_bc_dist);
static int bc_data_tobytes(yasm_bytecode *bc, unsigned char **bufp, void *d,
yasm_output_expr_func output_expr,
/*@null@*/ yasm_output_reloc_func output_reloc);
static void bc_reserve_destroy(yasm_bytecode *bc);
static void bc_reserve_print(const yasm_bytecode *bc, FILE *f,
int indent_level);
static yasm_bc_resolve_flags bc_reserve_resolve
(yasm_bytecode *bc, int save, yasm_calc_bc_dist_func calc_bc_dist);
static int bc_reserve_tobytes(yasm_bytecode *bc, unsigned char **bufp, void *d,
yasm_output_expr_func output_expr,
/*@null@*/ yasm_output_reloc_func output_reloc);
static void bc_incbin_destroy(yasm_bytecode *bc);
static void bc_incbin_print(const yasm_bytecode *bc, FILE *f,
int indent_level);
static yasm_bc_resolve_flags bc_incbin_resolve
(yasm_bytecode *bc, int save, yasm_calc_bc_dist_func calc_bc_dist);
static int bc_incbin_tobytes(yasm_bytecode *bc, unsigned char **bufp, void *d,
yasm_output_expr_func output_expr,
/*@null@*/ yasm_output_reloc_func output_reloc);
static void bc_align_destroy(yasm_bytecode *bc);
static void bc_align_print(const yasm_bytecode *bc, FILE *f, int indent_level);
static yasm_bc_resolve_flags bc_align_resolve
(yasm_bytecode *bc, int save, yasm_calc_bc_dist_func calc_bc_dist);
static int bc_align_tobytes(yasm_bytecode *bc, unsigned char **bufp, void *d,
yasm_output_expr_func output_expr,
/*@null@*/ yasm_output_reloc_func output_reloc);
/* Standard bytecode callback structures */
static const yasm_bytecode_callback bc_data_callback = {
bc_data_destroy,
bc_data_print,
bc_data_resolve,
bc_data_tobytes
};
static const yasm_bytecode_callback bc_reserve_callback = {
bc_reserve_destroy,
bc_reserve_print,
bc_reserve_resolve,
bc_reserve_tobytes
};
static const yasm_bytecode_callback bc_incbin_callback = {
bc_incbin_destroy,
bc_incbin_print,
bc_incbin_resolve,
bc_incbin_tobytes
};
static const yasm_bytecode_callback bc_align_callback = {
bc_align_destroy,
bc_align_print,
bc_align_resolve,
bc_align_tobytes
};
/* Static structures for when NULL is passed to conversion functions. */
/* for Convert*ToBytes() */
unsigned char bytes_static[16];
yasm_immval *
yasm_imm_create_int(unsigned long int_val, unsigned long line)
{
return yasm_imm_create_expr(
yasm_expr_create_ident(yasm_expr_int(yasm_intnum_create_uint(int_val)),
line));
}
yasm_immval *
yasm_imm_create_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_destroy(yasm_effaddr *ea)
{
ea->callback->destroy(ea);
yasm_expr_destroy(ea->disp);
yasm_xfree(ea);
}
/*@=nullstate@*/
/*@-nullstate@*/
void
yasm_ea_print(const yasm_effaddr *ea, FILE *f, int indent_level)
{
fprintf(f, "%*sDisp=", indent_level, "");
yasm_expr_print(ea->disp, f);
fprintf(f, "\n%*sLen=%u\n", indent_level, "", (unsigned int)ea->len);
fprintf(f, "%*sNoSplit=%u\n", indent_level, "", (unsigned int)ea->nosplit);
ea->callback->print(ea, f, indent_level);
}
/*@=nullstate@*/
void
yasm_bc_set_multiple(yasm_bytecode *bc, yasm_expr *e)
{
if (bc->multiple)
bc->multiple = yasm_expr_create_tree(bc->multiple, YASM_EXPR_MUL, e,
e->line);
else
bc->multiple = e;
}
yasm_bytecode *
yasm_bc_create_common(const yasm_bytecode_callback *callback, size_t size,
unsigned long line)
{
yasm_bytecode *bc = yasm_xmalloc(size);
bc->callback = callback;
bc->section = NULL;
bc->multiple = (yasm_expr *)NULL;
bc->len = 0;
bc->line = line;
bc->offset = 0;
bc->opt_flags = 0;
bc->symrecs = NULL;
return bc;
}
static void
bc_data_destroy(yasm_bytecode *bc)
{
bytecode_data *bc_data = (bytecode_data *)bc;
yasm_dvs_destroy(&bc_data->datahead);
}
static void
bc_data_print(const yasm_bytecode *bc, FILE *f, int indent_level)
{
const bytecode_data *bc_data = (const bytecode_data *)bc;
fprintf(f, "%*s_Data_\n", indent_level, "");
fprintf(f, "%*sFinal Element Size=%u\n", indent_level+1, "",
(unsigned int)bc_data->size);
fprintf(f, "%*sElements:\n", indent_level+1, "");
yasm_dvs_print(&bc_data->datahead, f, indent_level+2);
}
static yasm_bc_resolve_flags
bc_data_resolve(yasm_bytecode *bc, int save,
yasm_calc_bc_dist_func calc_bc_dist)
{
bytecode_data *bc_data = (bytecode_data *)bc;
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:
bc->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;
bc->len += slen*bc_data->size;
break;
}
}
return YASM_BC_RESOLVE_MIN_LEN;
}
static int
bc_data_tobytes(yasm_bytecode *bc, unsigned char **bufp, void *d,
yasm_output_expr_func output_expr,
/*@unused@*/ yasm_output_reloc_func output_reloc)
{
bytecode_data *bc_data = (bytecode_data *)bc;
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,
(size_t)(bc_data->size*8), 0,
(unsigned long)(*bufp-bufp_orig), 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;
}
yasm_bytecode *
yasm_bc_create_data(yasm_datavalhead *datahead, unsigned int size,
unsigned long line)
{
bytecode_data *data;
data = (bytecode_data *)
yasm_bc_create_common(&bc_data_callback, sizeof(bytecode_data), line);
data->datahead = *datahead;
data->size = (unsigned char)size;
return (yasm_bytecode *)data;
}
static void
bc_reserve_destroy(yasm_bytecode *bc)
{
bytecode_reserve *reserve = (bytecode_reserve *)bc;
yasm_expr_destroy(reserve->numitems);
}
static void
bc_reserve_print(const yasm_bytecode *bc, FILE *f, int indent_level)
{
const bytecode_reserve *reserve = (const bytecode_reserve *)bc;
fprintf(f, "%*s_Reserve_\n", indent_level, "");
fprintf(f, "%*sNum Items=", indent_level, "");
yasm_expr_print(reserve->numitems, f);
fprintf(f, "\n%*sItem Size=%u\n", indent_level, "",
(unsigned int)reserve->itemsize);
}
static yasm_bc_resolve_flags
bc_reserve_resolve(yasm_bytecode *bc, int save,
yasm_calc_bc_dist_func calc_bc_dist)
{
bytecode_reserve *reserve = (bytecode_reserve *)bc;
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(bc->line,
N_("expression must not contain floating point value"));
else
yasm__error(bc->line,
N_("attempt to reserve non-constant quantity of space"));
retval = YASM_BC_RESOLVE_ERROR | YASM_BC_RESOLVE_UNKNOWN_LEN;
} else
bc->len += yasm_intnum_get_uint(num)*reserve->itemsize;
yasm_expr_destroy(temp);
return retval;
}
static int
bc_reserve_tobytes(yasm_bytecode *bc, unsigned char **bufp, void *d,
yasm_output_expr_func output_expr,
/*@unused@*/ yasm_output_reloc_func output_reloc)
{
yasm_internal_error(N_("bc_reserve_tobytes called"));
/*@notreached@*/
return 1;
}
yasm_bytecode *
yasm_bc_create_reserve(yasm_expr *numitems, unsigned int itemsize,
unsigned long line)
{
bytecode_reserve *reserve;
reserve = (bytecode_reserve *)
yasm_bc_create_common(&bc_reserve_callback, sizeof(bytecode_reserve),
line);
/*@-mustfree@*/
reserve->numitems = numitems;
/*@=mustfree@*/
reserve->itemsize = (unsigned char)itemsize;
return (yasm_bytecode *)reserve;
}
static void
bc_incbin_destroy(yasm_bytecode *bc)
{
bytecode_incbin *incbin = (bytecode_incbin *)bc;
yasm_xfree(incbin->filename);
yasm_expr_destroy(incbin->start);
yasm_expr_destroy(incbin->maxlen);
}
static void
bc_incbin_print(const yasm_bytecode *bc, FILE *f, int indent_level)
{
const bytecode_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(incbin->start, f);
fprintf(f, "%*sMax Len=", indent_level, "");
if (!incbin->maxlen)
fprintf(f, "nil (unlimited)");
else
yasm_expr_print(incbin->maxlen, f);
fprintf(f, "\n");
}
static yasm_bc_resolve_flags
bc_incbin_resolve(yasm_bytecode *bc, int save,
yasm_calc_bc_dist_func calc_bc_dist)
{
bytecode_incbin *incbin = (bytecode_incbin *)bc;
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_destroy(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_destroy(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(bc->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(bc->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, bc->line,
N_("`incbin': start past end of file `%s'"),
incbin->filename);
start = flen;
}
flen -= start;
if (incbin->maxlen)
if (maxlen < flen)
flen = maxlen;
bc->len += flen;
return YASM_BC_RESOLVE_MIN_LEN;
}
static int
bc_incbin_tobytes(yasm_bytecode *bc, unsigned char **bufp, void *d,
yasm_output_expr_func output_expr,
/*@unused@*/ yasm_output_reloc_func output_reloc)
{
bytecode_incbin *incbin = (bytecode_incbin *)bc;
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(bc->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(bc->line, N_("`incbin': unable to seek on file `%s'"),
incbin->filename);
fclose(f);
return 1;
}
/* Read len bytes */
if (fread(*bufp, (size_t)bc->len, 1, f) < (size_t)bc->len) {
yasm__error(bc->line,
N_("`incbin': unable to read %lu bytes from file `%s'"),
bc->len, incbin->filename);
fclose(f);
return 1;
}
*bufp += bc->len;
fclose(f);
return 0;
}
yasm_bytecode *
yasm_bc_create_incbin(char *filename, yasm_expr *start, yasm_expr *maxlen,
unsigned long line)
{
bytecode_incbin *incbin;
incbin = (bytecode_incbin *)
yasm_bc_create_common(&bc_incbin_callback, sizeof(bytecode_incbin),
line);
/*@-mustfree@*/
incbin->filename = filename;
incbin->start = start;
incbin->maxlen = maxlen;
/*@=mustfree@*/
return (yasm_bytecode *)incbin;
}
static void
bc_align_destroy(yasm_bytecode *bc)
{
}
static void
bc_align_print(const yasm_bytecode *bc, FILE *f, int indent_level)
{
const bytecode_align *align = (const bytecode_align *)bc;
fprintf(f, "%*s_Align_\n", indent_level, "");
fprintf(f, "%*sBoundary=%lu\n", indent_level, "", align->boundary);
}
static yasm_bc_resolve_flags
bc_align_resolve(yasm_bytecode *bc, int save,
yasm_calc_bc_dist_func calc_bc_dist)
{
yasm_internal_error(N_("TODO: align bytecode not implemented!"));
/*@notreached@*/
return YASM_BC_RESOLVE_ERROR;
}
static int
bc_align_tobytes(yasm_bytecode *bc, unsigned char **bufp, void *d,
yasm_output_expr_func output_expr,
/*@unused@*/ yasm_output_reloc_func output_reloc)
{
yasm_internal_error(N_("TODO: align bytecode not implemented!"));
/*@notreached@*/
return 1;
}
yasm_bytecode *
yasm_bc_create_align(unsigned long boundary, unsigned long line)
{
bytecode_align *align;
align = (bytecode_align *)
yasm_bc_create_common(&bc_align_callback, sizeof(bytecode_align),
line);
align->boundary = boundary;
return (yasm_bytecode *)align;
}
yasm_section *
yasm_bc_get_section(yasm_bytecode *bc)
{
return bc->section;
}
void
yasm_bc__add_symrec(yasm_bytecode *bc, yasm_symrec *sym)
{
if (!bc->symrecs) {
bc->symrecs = yasm_xmalloc(2*sizeof(yasm_symrec *));
bc->symrecs[0] = sym;
bc->symrecs[1] = NULL;
} else {
/* Very inefficient implementation for large numbers of symbols. But
* that would be very unusual, so use the simple algorithm instead.
*/
size_t count = 1;
while (bc->symrecs[count])
count++;
bc->symrecs = yasm_xrealloc(bc->symrecs,
(count+2)*sizeof(yasm_symrec *));
bc->symrecs[count] = sym;
bc->symrecs[count+1] = NULL;
}
}
void
yasm_bc_destroy(yasm_bytecode *bc)
{
if (!bc)
return;
if (bc->callback)
bc->callback->destroy(bc);
yasm_expr_destroy(bc->multiple);
yasm_xfree(bc->symrecs);
yasm_xfree(bc);
}
void
yasm_bc_print(const yasm_bytecode *bc, FILE *f, int indent_level)
{
if (!bc->callback)
fprintf(f, "%*s_Empty_\n", indent_level, "");
else
bc->callback->print(bc, f, indent_level);
fprintf(f, "%*sMultiple=", indent_level, "");
if (!bc->multiple)
fprintf(f, "nil (1)");
else
yasm_expr_print(bc->multiple, f);
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(/*@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_create_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_create_uint(dist);
} else {
if (precbc1) {
intn = yasm_intnum_create_uint(precbc1->offset + precbc1->len);
yasm_intnum_calc(intn, YASM_EXPR_NEG, NULL, precbc1->line);
return intn;
} else {
return yasm_intnum_create_uint(0);
}
}
}
yasm_bc_resolve_flags
yasm_bc_resolve(yasm_bytecode *bc, int save,
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 */
if (!bc->callback)
yasm_internal_error(N_("got empty bytecode in bc_resolve"));
else
retval = bc->callback->resolve(bc, save, calc_bc_dist);
/* 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_destroy(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;
}
/*@null@*/ /*@only@*/ unsigned char *
yasm_bc_tobytes(yasm_bytecode *bc, unsigned char *buf, unsigned long *bufsize,
/*@out@*/ unsigned long *multiple, /*@out@*/ int *gap,
void *d, yasm_output_expr_func output_expr,
/*@null@*/ yasm_output_reloc_func output_reloc)
/*@sets *buf@*/
{
/*@only@*/ /*@null@*/ unsigned char *mybuf = NULL;
unsigned char *origbuf, *destbuf;
/*@dependent@*/ /*@null@*/ const yasm_intnum *num;
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;
/* special case for reserve bytecodes */
if (bc->callback == &bc_reserve_callback) {
*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;
}
if (!bc->callback)
yasm_internal_error(N_("got empty bytecode in bc_tobytes"));
else
error = bc->callback->tobytes(bc, &destbuf, d, output_expr,
output_reloc);
if (!error && ((unsigned long)(destbuf - origbuf) != datasize))
yasm_internal_error(
N_("written length does not match optimized length"));
return mybuf;
}
yasm_dataval *
yasm_dv_create_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_create_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_destroy(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_destroy(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(const yasm_datavalhead *head, FILE *f, int indent_level)
{
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(cur->data.expn, f);
fprintf(f, "\n");
break;
case DV_STRING:
fprintf(f, "%*sString=%s\n", indent_level, "",
cur->data.str_val);
break;
}
}
}
/* 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);
}