/* ----------------------------------------------------------------------- * * * Copyright 1996-2017 The NASM Authors - All Rights Reserved * See the file AUTHORS included with the NASM distribution for * the specific copyright holders. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following * conditions are met: * * * Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * * 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 COPYRIGHT HOLDERS AND * 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 COPYRIGHT OWNER OR * 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. * * ----------------------------------------------------------------------- */ /* * outobj.c output routines for the Netwide Assembler to produce * .OBJ object files */ #include "compiler.h" #include <ctype.h> /* For toupper() */ #include "nctype.h" #include "nasm.h" #include "nasmlib.h" #include "error.h" #include "stdscan.h" #include "eval.h" #include "ver.h" #include "outform.h" #include "outlib.h" #ifdef OF_OBJ /* * outobj.c is divided into two sections. The first section is low level * routines for creating obj records; It has nearly zero NASM specific * code. The second section is high level routines for processing calls and * data structures from the rest of NASM into obj format. * * It should be easy (though not zero work) to lift the first section out for * use as an obj file writer for some other assembler or compiler. */ /* * These routines are built around the ObjRecord data struture. An ObjRecord * holds an object file record that may be under construction or complete. * * A major function of these routines is to support continuation of an obj * record into the next record when the maximum record size is exceeded. The * high level code does not need to worry about where the record breaks occur. * It does need to do some minor extra steps to make the automatic continuation * work. Those steps may be skipped for records where the high level knows no * continuation could be required. * * 1) An ObjRecord is allocated and cleared by obj_new, or an existing ObjRecord * is cleared by obj_clear. * * 2) The caller should fill in .type. * * 3) If the record is continuable and there is processing that must be done at * the start of each record then the caller should fill in .ori with the * address of the record initializer routine. * * 4) If the record is continuable and it should be saved (rather than emitted * immediately) as each record is done, the caller should set .up to be a * pointer to a location in which the caller keeps the master pointer to the * ObjRecord. When the record is continued, the obj_bump routine will then * allocate a new ObjRecord structure and update the master pointer. * * 5) If the .ori field was used then the caller should fill in the .parm with * any data required by the initializer. * * 6) The caller uses the routines: obj_byte, obj_word, obj_rword, obj_dword, * obj_x, obj_index, obj_value and obj_name to fill in the various kinds of * data required for this record. * * 7) If the record is continuable, the caller should call obj_commit at each * point where breaking the record is permitted. * * 8) To write out the record, the caller should call obj_emit2. If the * caller has called obj_commit for all data written then he can get slightly * faster code by calling obj_emit instead of obj_emit2. * * Most of these routines return an ObjRecord pointer. This will be the input * pointer most of the time and will be the new location if the ObjRecord * moved as a result of the call. The caller may ignore the return value in * three cases: It is a "Never Reallocates" routine; or The caller knows * continuation is not possible; or The caller uses the master pointer for the * next operation. */ #define RECORD_MAX … #define OBJ_PARMS … #define FIX_08_LOW … #define FIX_16_OFFSET … #define FIX_16_SELECTOR … #define FIX_32_POINTER … #define FIX_08_HIGH … #define FIX_32_OFFSET … #define FIX_48_POINTER … enum RecordID { … }; enum ComentID { … }; ObjRecord; ORI; struct ObjRecord { … }; static void obj_fwrite(ObjRecord * orp); static void ori_ledata(ObjRecord * orp); static void ori_pubdef(ObjRecord * orp); static void ori_null(ObjRecord * orp); static ObjRecord *obj_commit(ObjRecord * orp); static bool obj_uppercase; /* Flag: all names in uppercase */ static bool obj_use32; /* Flag: at least one segment is 32-bit */ static bool obj_nodepend; /* Flag: don't emit file dependencies */ /* * Clear an ObjRecord structure. (Never reallocates). * To simplify reuse of ObjRecord's, .type, .ori and .parm are not cleared. */ static ObjRecord *obj_clear(ObjRecord * orp) { … } /* * Emit an ObjRecord structure. (Never reallocates). * The record is written out preceeded (recursively) by its previous part (if * any) and followed (recursively) by its child (if any). * The previous part and the child are freed. The main ObjRecord is cleared, * not freed. */ static ObjRecord *obj_emit(ObjRecord * orp) { … } /* * Commit and Emit a record. (Never reallocates). */ static ObjRecord *obj_emit2(ObjRecord * orp) { … } /* * Allocate and clear a new ObjRecord; Also sets .ori to ori_null */ static ObjRecord *obj_new(void) { … } /* * Advance to the next record because the existing one is full or its x_size * is incompatible. * Any uncommited data is moved into the next record. */ static ObjRecord *obj_bump(ObjRecord * orp) { … } /* * Advance to the next record if necessary to allow the next field to fit. */ static ObjRecord *obj_check(ObjRecord * orp, int size) { … } /* * All data written so far is commited to the current record (won't be moved to * the next record in case of continuation). */ static ObjRecord *obj_commit(ObjRecord * orp) { … } /* * Write a byte */ static ObjRecord *obj_byte(ObjRecord * orp, uint8_t val) { … } /* * Write a word */ static ObjRecord *obj_word(ObjRecord * orp, unsigned int val) { … } /* * Write a reversed word */ static ObjRecord *obj_rword(ObjRecord * orp, unsigned int val) { … } /* * Write a dword */ static ObjRecord *obj_dword(ObjRecord * orp, uint32_t val) { … } /* * All fields of "size x" in one obj record must be the same size (either 16 * bits or 32 bits). There is a one bit flag in each record which specifies * which. * This routine is used to force the current record to have the desired * x_size. x_size is normally automatic (using obj_x), so that this * routine should be used outside obj_x, only to provide compatibility with * linkers that have bugs in their processing of the size bit. */ static ObjRecord *obj_force(ObjRecord * orp, int x) { … } /* * This routine writes a field of size x. The caller does not need to worry at * all about whether 16-bits or 32-bits are required. */ static ObjRecord *obj_x(ObjRecord * orp, uint32_t val) { … } /* * Writes an index */ static ObjRecord *obj_index(ObjRecord * orp, unsigned int val) { … } /* * Writes a variable length value */ static ObjRecord *obj_value(ObjRecord * orp, uint32_t val) { … } /* * Writes a counted string */ static ObjRecord *obj_name(ObjRecord * orp, const char *name) { … } /* * Initializer for an LEDATA record. * parm[0] = offset * parm[1] = segment index * During the use of a LEDATA ObjRecord, parm[0] is constantly updated to * represent the offset that would be required if the record were split at the * last commit point. * parm[2] is a copy of parm[0] as it was when the current record was initted. */ static void ori_ledata(ObjRecord * orp) { … } /* * Initializer for a PUBDEF record. * parm[0] = group index * parm[1] = segment index * parm[2] = frame (only used when both indexes are zero) */ static void ori_pubdef(ObjRecord * orp) { … } /* * Initializer for a LINNUM record. * parm[0] = group index * parm[1] = segment index */ static void ori_linnum(ObjRecord * orp) { … } /* * Initializer for a local vars record. */ static void ori_local(ObjRecord * orp) { … } /* * Null initializer for records that continue without any header info */ static void ori_null(ObjRecord * orp) { … } /* * This concludes the low level section of outobj.c */ static char obj_infile[FILENAME_MAX]; static int32_t first_seg; static bool any_segs; static int passtwo; static int arrindex; #define GROUP_MAX … #define EXT_BLKSIZ … struct Segment; /* need to know these structs exist */ struct Group; struct LineNumber { … }; static struct FileName { … } *fnhead, **fntail; static struct Array { … } *arrhead, **arrtail; #define ARRAYBOT … static struct Public { … } *fpubhead, **fpubtail, *last_defined; static struct External { … } *exthead, **exttail, *dws; static int externals; static struct ExtBack { … } *ebhead, **ebtail; static struct Segment { … } *seghead, **segtail, *obj_seg_needs_update; static struct Group { … } *grphead, **grptail, *obj_grp_needs_update; static struct ImpDef { … } *imphead, **imptail; static struct ExpDef { … } *exphead, **exptail; #define EXPDEF_FLAG_ORDINAL … #define EXPDEF_FLAG_RESIDENT … #define EXPDEF_FLAG_NODATA … #define EXPDEF_MASK_PARMCNT … static int32_t obj_entry_seg, obj_entry_ofs; const struct ofmt of_obj; static const struct dfmt borland_debug_form; /* The current segment */ static struct Segment *current_seg; static int32_t obj_segment(char *, int *); static void obj_write_file(void); static enum directive_result obj_directive(enum directive, char *); static void obj_init(void) { … } static void obj_cleanup(void) { … } static void obj_ext_set_defwrt(struct External *ext, char *id) { … } static void obj_deflabel(char *name, int32_t segment, int64_t offset, int is_global, char *special) { … } /* forward declaration */ static void obj_write_fixup(ObjRecord * orp, int bytes, int segrel, int32_t seg, int32_t wrt, struct Segment *segto); static void obj_out(int32_t segto, const void *data, enum out_type type, uint64_t size, int32_t segment, int32_t wrt) { … } static void obj_write_fixup(ObjRecord * orp, int bytes, int segrel, int32_t seg, int32_t wrt, struct Segment *segto) { … } static int32_t obj_segment(char *name, int *bits) { … } static enum directive_result obj_directive(enum directive directive, char *value) { … } static void obj_sectalign(int32_t seg, unsigned int value) { … } static int32_t obj_segbase(int32_t segment) { … } /* Get a file timestamp in MS-DOS format */ static uint32_t obj_file_timestamp(const char *pathname) { … } static void obj_write_file(void) { … } static void obj_fwrite(ObjRecord * orp) { … } static enum directive_result obj_pragma(const struct pragma *pragma) { … } extern macros_t obj_stdmac[]; static void dbgbi_init(void) { … } static void dbgbi_cleanup(void) { … } static void dbgbi_linnum(const char *lnfname, int32_t lineno, int32_t segto) { … } static void dbgbi_deflabel(char *name, int32_t segment, int64_t offset, int is_global, char *special) { … } static void dbgbi_typevalue(int32_t type) { … } static void dbgbi_output(int output_type, void *param) { … } static const struct dfmt borland_debug_form = …; static const struct dfmt * const borland_debug_arr[3] = …; static const struct pragma_facility obj_pragma_list[] = …; const struct ofmt of_obj = …; #endif /* OF_OBJ */