mirror of
https://github.com/yasm/yasm
synced 2026-08-26 22:26:05 -04:00
- 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
1015 lines
26 KiB
C
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);
|
|
}
|