From: Peter Johnson Date: Tue, 17 Oct 2006 05:48:42 +0000 (-0000) Subject: Add support for RDOFF2 object format (#73). X-Git-Tag: v0.6.0~129 X-Git-Url: https://granicus.if.org/sourcecode?a=commitdiff_plain;h=59cf126f37281fb1bbe1591a7ed927ed995977b6;p=yasm Add support for RDOFF2 object format (#73). svn path=/trunk/yasm/; revision=1650 --- diff --git a/libyasm/symrec.c b/libyasm/symrec.c index 6028c4bc..2fbf6d2a 100644 --- a/libyasm/symrec.c +++ b/libyasm/symrec.c @@ -442,6 +442,12 @@ yasm_symrec_get_visibility(const yasm_symrec *sym) return sym->visibility; } +unsigned long +yasm_symrec_get_line(const yasm_symrec *sym) +{ + return sym->line; +} + const yasm_expr * yasm_symrec_get_equ(const yasm_symrec *sym) { diff --git a/libyasm/symrec.h b/libyasm/symrec.h index 04ec321b..a734a30f 100644 --- a/libyasm/symrec.h +++ b/libyasm/symrec.h @@ -217,6 +217,12 @@ void yasm_symtab_print(yasm_symtab *symtab, FILE *f, int indent_level); */ yasm_sym_vis yasm_symrec_get_visibility(const yasm_symrec *sym); +/** Get the virtual line of a symbol (where it was first declared or used). + * \param sym symbol + * \return line virtual line + */ +unsigned long yasm_symrec_get_line(const yasm_symrec *sym); + /** Get EQU value of a symbol. * \param sym symbol * \return EQU value, or NULL if symbol is not an EQU or is not defined. diff --git a/modules/objfmts/Makefile.inc b/modules/objfmts/Makefile.inc index b5b89945..c4e562b5 100644 --- a/modules/objfmts/Makefile.inc +++ b/modules/objfmts/Makefile.inc @@ -5,6 +5,7 @@ EXTRA_DIST += modules/objfmts/bin/Makefile.inc EXTRA_DIST += modules/objfmts/elf/Makefile.inc #!EXTRA_DIST += modules/objfmts/omf/Makefile.inc EXTRA_DIST += modules/objfmts/coff/Makefile.inc +EXTRA_DIST += modules/objfmts/rdf/Makefile.inc EXTRA_DIST += modules/objfmts/win32/Makefile.inc EXTRA_DIST += modules/objfmts/win64/Makefile.inc EXTRA_DIST += modules/objfmts/xdf/Makefile.inc @@ -14,6 +15,7 @@ include modules/objfmts/bin/Makefile.inc include modules/objfmts/elf/Makefile.inc #!include modules/objfmts/omf/Makefile.inc include modules/objfmts/coff/Makefile.inc +include modules/objfmts/rdf/Makefile.inc include modules/objfmts/win32/Makefile.inc include modules/objfmts/win64/Makefile.inc include modules/objfmts/xdf/Makefile.inc diff --git a/modules/objfmts/rdf/Makefile.inc b/modules/objfmts/rdf/Makefile.inc new file mode 100644 index 00000000..ef33dffb --- /dev/null +++ b/modules/objfmts/rdf/Makefile.inc @@ -0,0 +1,9 @@ +# $Id$ + +libyasm_a_SOURCES += modules/objfmts/rdf/rdf-objfmt.c + +YASM_MODULES += objfmt_rdf + +EXTRA_DIST += modules/objfmts/rdf/tests/Makefile.inc + +include modules/objfmts/rdf/tests/Makefile.inc diff --git a/modules/objfmts/rdf/rdf-objfmt.c b/modules/objfmts/rdf/rdf-objfmt.c new file mode 100644 index 00000000..0059f6ca --- /dev/null +++ b/modules/objfmts/rdf/rdf-objfmt.c @@ -0,0 +1,1178 @@ +/* + * Relocatable Dynamic Object File Format (RDOFF) version 2 format + * + * Copyright (C) 2006 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. + */ +#include +/*@unused@*/ RCSID("$Id$"); + +#define YASM_LIB_INTERNAL +#define YASM_BC_INTERNAL +#define YASM_EXPR_INTERNAL +#include + + +#define REGULAR_OUTBUF_SIZE 1024 + +#define RDF_MAGIC "RDOFF2" + +/* Maximum size of an import/export label (including trailing zero) */ +#define EXIM_LABEL_MAX 64 + +/* Maximum size of library or module name (including trailing zero) */ +#define MODLIB_NAME_MAX 128 + +/* Maximum number of segments that we can handle in one file */ +#define RDF_MAXSEGS 64 + +/* Record types that may present the RDOFF header */ +#define RDFREC_GENERIC 0 +#define RDFREC_RELOC 1 +#define RDFREC_IMPORT 2 +#define RDFREC_GLOBAL 3 +#define RDFREC_DLL 4 +#define RDFREC_BSS 5 +#define RDFREC_SEGRELOC 6 +#define RDFREC_FARIMPORT 7 +#define RDFREC_MODNAME 8 +#define RDFREC_COMMON 10 + +/* Flags for ExportRec/ImportRec */ +#define SYM_DATA 1 +#define SYM_FUNCTION 2 + +/* Flags for ExportRec */ +#define SYM_GLOBAL 4 + +/* Flags for ImportRec */ +#define SYM_IMPORT 8 +#define SYM_FAR 16 + +typedef struct rdf_reloc { + yasm_reloc reloc; + enum { + RDF_RELOC_NORM, /* normal */ + RDF_RELOC_REL, /* relative to current position */ + RDF_RELOC_SEG /* segment containing symbol */ + } type; /* type of relocation */ + unsigned int size; + unsigned int refseg; +} rdf_reloc; + +typedef struct rdf_section_data { + /*@dependent@*/ yasm_symrec *sym; /* symbol created for this section */ + long scnum; /* section number (0=first section) */ + enum { + RDF_SECT_BSS = 0, + RDF_SECT_CODE = 1, + RDF_SECT_DATA = 2, + RDF_SECT_COMMENT = 3, + RDF_SECT_LCOMMENT = 4, + RDF_SECT_PCOMMENT = 5, + RDF_SECT_SYMDEBUG = 6, + RDF_SECT_LINEDEBUG = 7 + } type; /* section type */ + unsigned int reserved; /* reserved data */ + unsigned long size; /* size of raw data (section data) in bytes */ + + unsigned char *raw_data; /* raw section data, only used during output */ +} rdf_section_data; + +typedef struct rdf_symrec_data { + /*@owned@*/ /*@null@*/ yasm_expr *size; /* size if COMMON declaration */ + unsigned long align; /* alignment if COMMON declaration */ + + unsigned int flags; /* import/export/type flags */ + unsigned int segment; /* assigned RDF "segment" index */ +} rdf_symrec_data; + +typedef STAILQ_HEAD(xdf_str_head, xdf_str) xdf_str_head; +typedef struct xdf_str { + STAILQ_ENTRY(xdf_str) link; + /*@owned@*/ char *str; +} xdf_str; + +typedef struct yasm_objfmt_rdf { + yasm_objfmt_base objfmt; /* base structure */ + + long parse_scnum; /* sect numbering in parser */ + + yasm_object *object; + yasm_symtab *symtab; + /*@dependent@*/ yasm_arch *arch; + + /*@owned@*/ xdf_str_head module_names; + /*@owned@*/ xdf_str_head library_names; +} yasm_objfmt_rdf; + +typedef struct rdf_objfmt_output_info { + yasm_objfmt_rdf *objfmt_rdf; + yasm_errwarns *errwarns; + /*@dependent@*/ FILE *f; + /*@only@*/ unsigned char *buf; + yasm_section *sect; + /*@dependent@*/ rdf_section_data *rsd; + + unsigned long indx; /* symbol "segment" (extern/common only) */ + + unsigned long bss_size; /* total BSS size */ +} rdf_objfmt_output_info; + +static void rdf_section_data_destroy(/*@only@*/ void *d); +static void rdf_section_data_print(void *data, FILE *f, int indent_level); + +static const yasm_assoc_data_callback rdf_section_data_cb = { + rdf_section_data_destroy, + rdf_section_data_print +}; + +static void rdf_symrec_data_destroy(/*@only@*/ void *d); +static void rdf_symrec_data_print(void *data, FILE *f, int indent_level); + +static const yasm_assoc_data_callback rdf_symrec_data_cb = { + rdf_symrec_data_destroy, + rdf_symrec_data_print +}; + +yasm_objfmt_module yasm_rdf_LTX_objfmt; + + +static /*@dependent@*/ rdf_symrec_data * +rdf_objfmt_sym_set_data(yasm_symrec *sym, + /*@only@*/ /*@null@*/ yasm_expr *size, + unsigned long align, unsigned int flags) +{ + rdf_symrec_data *rsymd = yasm_xmalloc(sizeof(rdf_symrec_data)); + + rsymd->size = size; + rsymd->align = align; + rsymd->flags = flags; + rsymd->segment = 0; + + yasm_symrec_add_data(sym, &rdf_symrec_data_cb, rsymd); + return rsymd; +} + +static yasm_objfmt * +rdf_objfmt_create(yasm_object *object, yasm_arch *a) +{ + yasm_objfmt_rdf *objfmt_rdf = yasm_xmalloc(sizeof(yasm_objfmt_rdf)); + + objfmt_rdf->object = object; + objfmt_rdf->symtab = yasm_object_get_symtab(object); + objfmt_rdf->arch = a; + + /* We theoretically support all arches, so don't check. + * Really we only support byte-addressable ones. + */ + + objfmt_rdf->parse_scnum = 0; /* section numbering starts at 0 */ + + STAILQ_INIT(&objfmt_rdf->module_names); + STAILQ_INIT(&objfmt_rdf->library_names); + + objfmt_rdf->objfmt.module = &yasm_rdf_LTX_objfmt; + + return (yasm_objfmt *)objfmt_rdf; +} + +static int +rdf_objfmt_output_value(yasm_value *value, unsigned char *buf, size_t destsize, + unsigned long offset, yasm_bytecode *bc, int warn, + /*@null@*/ void *d) +{ + /*@null@*/ rdf_objfmt_output_info *info = (rdf_objfmt_output_info *)d; + yasm_objfmt_rdf *objfmt_rdf; + /*@dependent@*/ /*@null@*/ yasm_intnum *intn; + unsigned long intn_minus; + unsigned long intn_plus; + int retval; + unsigned int valsize = value->size; + + assert(info != NULL); + objfmt_rdf = info->objfmt_rdf; + + if (value->abs) + value->abs = yasm_expr_simplify(value->abs, 1); + + /* Try to output constant and PC-relative section-local first. + * Note this does NOT output any value with a SEG, WRT, external, + * cross-section, or non-PC-relative reference (those are handled below). + */ + switch (yasm_value_output_basic(value, buf, destsize, bc, warn, + info->objfmt_rdf->arch)) { + case -1: + return 1; + case 0: + break; + default: + return 0; + } + + if (value->section_rel) { + yasm_error_set(YASM_ERROR_TOO_COMPLEX, + N_("rdf: relocation too complex")); + return 1; + } + + if (value->rel && value->wrt) { + yasm_error_set(YASM_ERROR_TOO_COMPLEX, + N_("rdf: WRT not supported")); + return 1; + } + + intn_minus = 0; + intn_plus = 0; + if (value->rel) { + rdf_reloc *reloc; + /*@null@*/ rdf_symrec_data *rsymd; + /*@dependent@*/ yasm_bytecode *precbc; + + reloc = yasm_xmalloc(sizeof(rdf_reloc)); + reloc->reloc.addr = yasm_intnum_create_uint(bc->offset + offset); + reloc->reloc.sym = value->rel; + reloc->size = valsize/8; + + if (value->seg_of) + reloc->type = RDF_RELOC_SEG; + else if (value->curpos_rel) { + reloc->type = RDF_RELOC_REL; + /* Adjust to start of section, so subtract out the bytecode + * offset. + */ + intn_minus = bc->offset; + } else + reloc->type = RDF_RELOC_NORM; + + if (yasm_symrec_get_label(value->rel, &precbc)) { + /* local, set the value to be the offset, and the refseg to the + * segment number. + */ + /*@dependent@*/ /*@null@*/ rdf_section_data *csectd; + /*@dependent@*/ yasm_section *sect; + + sect = yasm_bc_get_section(precbc); + csectd = yasm_section_get_data(sect, &rdf_section_data_cb); + if (!csectd) + yasm_internal_error(N_("didn't understand section")); + reloc->refseg = csectd->scnum; + intn_plus = yasm_bc_next_offset(precbc); + } else { + /* must be common/external */ + rsymd = yasm_symrec_get_data(reloc->reloc.sym, + &rdf_symrec_data_cb); + if (!rsymd) + yasm_internal_error( + N_("rdf: no symbol data for relocated symbol")); + reloc->refseg = rsymd->segment; + } + + yasm_section_add_reloc(info->sect, (yasm_reloc *)reloc, yasm_xfree); + } + + if (intn_minus > 0) { + intn = yasm_intnum_create_uint(intn_minus); + yasm_intnum_calc(intn, YASM_EXPR_NEG, NULL); + } else + intn = yasm_intnum_create_uint(intn_plus); + + if (value->abs) { + yasm_intnum *intn2 = yasm_expr_get_intnum(&value->abs, 0); + if (!intn2) { + yasm_error_set(YASM_ERROR_TOO_COMPLEX, + N_("rdf: relocation too complex")); + yasm_intnum_destroy(intn); + return 1; + } + yasm_intnum_calc(intn, YASM_EXPR_ADD, intn2); + } + + retval = yasm_arch_intnum_tobytes(objfmt_rdf->arch, intn, buf, destsize, + valsize, 0, bc, warn); + yasm_intnum_destroy(intn); + return retval; +} + +static int +rdf_objfmt_output_bytecode(yasm_bytecode *bc, /*@null@*/ void *d) +{ + /*@null@*/ rdf_objfmt_output_info *info = (rdf_objfmt_output_info *)d; + /*@null@*/ /*@only@*/ unsigned char *bigbuf; + unsigned long size = REGULAR_OUTBUF_SIZE; + int gap; + + assert(info != NULL); + + bigbuf = yasm_bc_tobytes(bc, info->buf, &size, &gap, info, + rdf_objfmt_output_value, NULL); + + /* Don't bother doing anything else if size ended up being 0. */ + if (size == 0) { + if (bigbuf) + yasm_xfree(bigbuf); + return 0; + } + + /* Warn that gaps are converted to 0 and write out the 0's. */ + if (gap) { + unsigned long left; + yasm_warn_set(YASM_WARN_UNINIT_CONTENTS, + N_("uninitialized space: zeroing")); + /* Write out in chunks */ + memset(&info->rsd->raw_data[info->rsd->size], 0, size); + } else { + /* Output buf (or bigbuf if non-NULL) to file */ + memcpy(&info->rsd->raw_data[info->rsd->size], + bigbuf ? bigbuf : info->buf, (size_t)size); + } + + info->rsd->size += size; + + /* If bigbuf was allocated, free it */ + if (bigbuf) + yasm_xfree(bigbuf); + + return 0; +} + +static int +rdf_objfmt_output_section_mem(yasm_section *sect, /*@null@*/ void *d) +{ + /*@null@*/ rdf_objfmt_output_info *info = (rdf_objfmt_output_info *)d; + /*@dependent@*/ /*@null@*/ rdf_section_data *rsd; + unsigned long size; + rdf_reloc *reloc; + + /* Don't output absolute sections */ + if (yasm_section_is_absolute(sect)) + return 0; + + assert(info != NULL); + rsd = yasm_section_get_data(sect, &rdf_section_data_cb); + assert(rsd != NULL); + + size = yasm_bc_next_offset(yasm_section_bcs_last(sect)); + + if (rsd->type == RDF_SECT_BSS) { + /* Don't output BSS sections, but remember length + * TODO: Check for non-reserve bytecodes? + */ + info->bss_size += size; + return 0; + } + + /* Empty? Go on to next section */ + if (size == 0) + return 0; + + /* See UGH comment in output() for why we're doing this */ + rsd->raw_data = yasm_xmalloc(size); + rsd->size = 0; + + info->sect = sect; + info->rsd = rsd; + yasm_section_bcs_traverse(sect, info->errwarns, info, + rdf_objfmt_output_bytecode); + + /* Sanity check final section size */ + if (rsd->size != size) + yasm_internal_error( + N_("rdf: section computed size did not match actual size")); + + return 0; +} + +static int +rdf_objfmt_output_section_reloc(yasm_section *sect, /*@null@*/ void *d) +{ + /*@null@*/ rdf_objfmt_output_info *info = (rdf_objfmt_output_info *)d; + /*@dependent@*/ /*@null@*/ rdf_section_data *rsd; + long pos; + rdf_reloc *reloc; + + /* Don't output absolute sections */ + if (yasm_section_is_absolute(sect)) + return 0; + + assert(info != NULL); + rsd = yasm_section_get_data(sect, &rdf_section_data_cb); + assert(rsd != NULL); + + if (rsd->type == RDF_SECT_BSS) { + /* Don't output BSS sections. */ + return 0; + } + + /* Empty? Go on to next section */ + if (rsd->size == 0) + return 0; + + reloc = (rdf_reloc *)yasm_section_relocs_first(sect); + while (reloc) { + unsigned char *localbuf = info->buf; + + if (reloc->type == RDF_RELOC_SEG) + YASM_WRITE_8(localbuf, RDFREC_SEGRELOC); + else + YASM_WRITE_8(localbuf, RDFREC_RELOC); + YASM_WRITE_8(localbuf, 8); /* record length */ + /* Section number, +0x40 if relative reloc */ + YASM_WRITE_8(localbuf, rsd->scnum + + (reloc->type == RDF_RELOC_REL ? 0x40 : 0)); + yasm_intnum_get_sized(reloc->reloc.addr, localbuf, 4, 32, 0, 0, 0); + localbuf += 4; /* offset of relocation */ + YASM_WRITE_8(localbuf, reloc->size); /* size of relocation */ + YASM_WRITE_16_L(localbuf, reloc->refseg); /* relocated symbol */ + fwrite(info->buf, 10, 1, info->f); + + reloc = (rdf_reloc *)yasm_section_reloc_next((yasm_reloc *)reloc); + } + + return 0; +} + +static int +rdf_objfmt_output_section_file(yasm_section *sect, /*@null@*/ void *d) +{ + /*@null@*/ rdf_objfmt_output_info *info = (rdf_objfmt_output_info *)d; + /*@dependent@*/ /*@null@*/ rdf_section_data *rsd; + unsigned char *localbuf; + + /* Don't output absolute sections */ + if (yasm_section_is_absolute(sect)) + return 0; + + assert(info != NULL); + rsd = yasm_section_get_data(sect, &rdf_section_data_cb); + assert(rsd != NULL); + + if (rsd->type == RDF_SECT_BSS) { + /* Don't output BSS sections. */ + return 0; + } + + /* Empty? Go on to next section */ + if (rsd->size == 0) + return 0; + + /* Section header */ + localbuf = info->buf; + YASM_WRITE_16_L(localbuf, rsd->type); /* type */ + YASM_WRITE_16_L(localbuf, rsd->scnum); /* number */ + YASM_WRITE_16_L(localbuf, rsd->reserved); /* reserved */ + YASM_WRITE_32_L(localbuf, rsd->size); /* length */ + fwrite(info->buf, 10, 1, info->f); + + /* Section data */ + fwrite(rsd->raw_data, rsd->size, 1, info->f); + + /* Free section data */ + yasm_xfree(rsd->raw_data); + rsd->raw_data = NULL; + + return 0; +} + +static int +rdf_objfmt_output_sym(yasm_symrec *sym, /*@null@*/ void *d) +{ + /*@null@*/ rdf_objfmt_output_info *info = (rdf_objfmt_output_info *)d; + yasm_sym_vis vis = yasm_symrec_get_visibility(sym); + const char *name; + size_t len; + unsigned long value = 0; + unsigned int scnum = 0; + /*@dependent@*/ /*@null@*/ yasm_section *sect; + /*@dependent@*/ /*@null@*/ yasm_bytecode *precbc; + unsigned char *localbuf; + unsigned int rectype = RDFREC_GENERIC; + rdf_symrec_data *rsymd; + + assert(info != NULL); + + if (vis == YASM_SYM_LOCAL || vis == YASM_SYM_DLOCAL) + return 0; /* skip local syms */ + + /* Look at symrec for value/scnum/etc. */ + if (yasm_symrec_get_label(sym, &precbc)) { + /*@dependent@*/ /*@null@*/ rdf_section_data *csectd; + + if (precbc) + sect = yasm_bc_get_section(precbc); + else + sect = NULL; + if (!sect) + return 0; + + /* it's a label: get value and offset. */ + csectd = yasm_section_get_data(sect, &rdf_section_data_cb); + if (csectd) { + scnum = csectd->scnum; + } else if (yasm_section_is_absolute(sect)) { + yasm_warn_set(YASM_WARN_GENERAL, + N_("rdf does not support exporting absolutes")); + yasm_errwarn_propagate(info->errwarns, yasm_symrec_get_line(sym)); + return 0; + } else + yasm_internal_error(N_("didn't understand section")); + value = yasm_bc_next_offset(precbc); + } else if (yasm_symrec_get_equ(sym)) { + yasm_warn_set(YASM_WARN_GENERAL, + N_("rdf does not support exporting EQU/absolute values")); + yasm_errwarn_propagate(info->errwarns, yasm_symrec_get_line(sym)); + return 0; + } + + name = yasm_symrec_get_name(sym); + len = strlen(name); + + if (len > EXIM_LABEL_MAX-1) { + yasm_warn_set(YASM_WARN_GENERAL, + N_("label name too long, truncating to %d bytes"), + EXIM_LABEL_MAX); + yasm_errwarn_propagate(info->errwarns, yasm_symrec_get_line(sym)); + len = EXIM_LABEL_MAX-1; + } + + localbuf = info->buf; + if (vis & YASM_SYM_GLOBAL) { + rsymd = yasm_symrec_get_data(sym, &rdf_symrec_data_cb); + if (!rsymd) + yasm_internal_error(N_("rdf: no symbol data for global symbol")); + YASM_WRITE_8(localbuf, RDFREC_GLOBAL); + YASM_WRITE_8(localbuf, 6+len+1); /* record length */ + YASM_WRITE_8(localbuf, rsymd->flags); /* flags */ + YASM_WRITE_8(localbuf, scnum); /* segment referred to */ + YASM_WRITE_32_L(localbuf, value); /* offset */ + } else { + /* Create new symrec data if it doesn't already exist */ + rsymd = yasm_symrec_get_data(sym, &rdf_symrec_data_cb); + if (!rsymd) + rsymd = rdf_objfmt_sym_set_data(sym, NULL, 0, 0); + + /* Save symbol segment in symrec data (for later reloc gen) */ + rsymd->segment = info->indx++; + scnum = rsymd->segment; + + if (vis & YASM_SYM_COMMON) { + const yasm_intnum *intn; + + YASM_WRITE_8(localbuf, RDFREC_COMMON); + YASM_WRITE_8(localbuf, 8+len+1); /* record length */ + YASM_WRITE_16_L(localbuf, scnum); /* segment allocated */ + + /* size */ + intn = yasm_expr_get_intnum(&rsymd->size, 1); + if (!intn) { + yasm_error_set(YASM_ERROR_NOT_CONSTANT, + N_("COMMON data size not an integer expression")); + yasm_errwarn_propagate(info->errwarns, + yasm_symrec_get_line(sym)); + } else + value = yasm_intnum_get_uint(intn); + YASM_WRITE_32_L(localbuf, value); + YASM_WRITE_16_L(localbuf, rsymd->align); /* alignment */ + } else if (vis & YASM_SYM_EXTERN) { + unsigned int flags = rsymd->flags; + if (flags & SYM_FAR) { + YASM_WRITE_8(localbuf, RDFREC_FARIMPORT); + flags &= ~SYM_FAR; + } else + YASM_WRITE_8(localbuf, RDFREC_IMPORT); + YASM_WRITE_8(localbuf, 3+len+1); /* record length */ + YASM_WRITE_8(localbuf, flags); /* flags */ + YASM_WRITE_16_L(localbuf, scnum); /* segment allocated */ + } + } + + /* Symbol name */ + memcpy(localbuf, name, len); + localbuf += len; + YASM_WRITE_8(localbuf, 0); /* 0-terminated name */ + + fwrite(info->buf, (unsigned long)(localbuf-info->buf), 1, info->f); + return 0; +} + +static void +rdf_objfmt_output(yasm_objfmt *objfmt, FILE *f, int all_syms, + /*@unused@*/ yasm_dbgfmt *df, yasm_errwarns *errwarns) +{ + yasm_objfmt_rdf *objfmt_rdf = (yasm_objfmt_rdf *)objfmt; + rdf_objfmt_output_info info; + unsigned char *localbuf; + long headerlen, filelen; + xdf_str *cur; + size_t len; + + info.objfmt_rdf = objfmt_rdf; + info.errwarns = errwarns; + info.f = f; + info.buf = yasm_xmalloc(REGULAR_OUTBUF_SIZE); + info.bss_size = 0; + + /* Allocate space for file header by seeking forward */ + if (fseek(f, (long)strlen(RDF_MAGIC)+8, SEEK_SET) < 0) { + yasm__fatal(N_("could not seek on output file")); + /*@notreached@*/ + return; + } + + /* Output custom header records (library and module, etc) */ + cur = STAILQ_FIRST(&objfmt_rdf->module_names); + while (cur) { + len = strlen(cur->str)+1; + localbuf = info.buf; + YASM_WRITE_8(localbuf, RDFREC_MODNAME); /* record type */ + YASM_WRITE_8(localbuf, len); /* record length */ + fwrite(info.buf, 2, 1, f); + fwrite(cur->str, len, 1, f); + cur = STAILQ_NEXT(cur, link); + } + + cur = STAILQ_FIRST(&objfmt_rdf->library_names); + while (cur) { + len = strlen(cur->str)+1; + localbuf = info.buf; + YASM_WRITE_8(localbuf, RDFREC_DLL); /* record type */ + YASM_WRITE_8(localbuf, len); /* record length */ + fwrite(info.buf, 2, 1, f); + fwrite(cur->str, len, 1, f); + cur = STAILQ_NEXT(cur, link); + } + + /* Output symbol table */ + info.indx = objfmt_rdf->parse_scnum; + yasm_symtab_traverse(objfmt_rdf->symtab, &info, rdf_objfmt_output_sym); + + /* UGH! Due to the fact the relocs go at the beginning of the file, and + * we only know if we have relocs when we output the sections, we have + * to output the section data before we have output the relocs. But + * we also don't know how much space to preallocate for relocs, so.... + * we output into memory buffers first (thus the UGH). + * + * Stupid object format design, if you ask me (basically all other + * object formats put the relocs *after* the section data to avoid this + * exact problem). + * + * We also calculate the total size of all BSS sections here. + */ + if (yasm_object_sections_traverse(objfmt_rdf->object, &info, + rdf_objfmt_output_section_mem)) + return; + + /* Output all relocs */ + if (yasm_object_sections_traverse(objfmt_rdf->object, &info, + rdf_objfmt_output_section_reloc)) + return; + + /* Output BSS record */ + if (info.bss_size > 0) { + localbuf = info.buf; + YASM_WRITE_8(localbuf, RDFREC_BSS); /* record type */ + YASM_WRITE_8(localbuf, 4); /* record length */ + YASM_WRITE_32_L(localbuf, info.bss_size); /* total BSS size */ + fwrite(info.buf, 6, 1, f); + } + + /* Determine header length */ + headerlen = ftell(f); + if (headerlen == -1) { + yasm__fatal(N_("could not get file position on output file")); + /*@notreached@*/ + return; + } + + /* Section data (to file) */ + if (yasm_object_sections_traverse(objfmt_rdf->object, &info, + rdf_objfmt_output_section_file)) + return; + + /* NULL section to end file */ + memset(info.buf, 0, 10); + fwrite(info.buf, 10, 1, f); + + /* Determine object length */ + filelen = ftell(f); + if (filelen == -1) { + yasm__fatal(N_("could not get file position on output file")); + /*@notreached@*/ + return; + } + + /* Write file header */ + if (fseek(f, 0, SEEK_SET) < 0) { + yasm__fatal(N_("could not seek on output file")); + /*@notreached@*/ + return; + } + + fwrite(RDF_MAGIC, strlen(RDF_MAGIC), 1, f); + localbuf = info.buf; + YASM_WRITE_32_L(localbuf, filelen-10); /* object size */ + YASM_WRITE_32_L(localbuf, headerlen-14); /* header size */ + fwrite(info.buf, 8, 1, f); + + yasm_xfree(info.buf); +} + +static void +rdf_objfmt_destroy(yasm_objfmt *objfmt) +{ + yasm_objfmt_rdf *objfmt_rdf = (yasm_objfmt_rdf *)objfmt; + xdf_str *cur, *next; + + cur = STAILQ_FIRST(&objfmt_rdf->module_names); + while (cur) { + next = STAILQ_NEXT(cur, link); + yasm_xfree(cur->str); + yasm_xfree(cur); + cur = next; + } + + cur = STAILQ_FIRST(&objfmt_rdf->library_names); + while (cur) { + next = STAILQ_NEXT(cur, link); + yasm_xfree(cur->str); + yasm_xfree(cur); + cur = next; + } + + yasm_xfree(objfmt); +} + +static rdf_section_data * +rdf_objfmt_init_new_section(yasm_objfmt_rdf *objfmt_rdf, yasm_section *sect, + const char *sectname, unsigned long line) +{ + rdf_section_data *data; + yasm_symrec *sym; + + data = yasm_xmalloc(sizeof(rdf_section_data)); + data->scnum = objfmt_rdf->parse_scnum++; + data->type = 0; + data->reserved = 0; + data->size = 0; + data->raw_data = NULL; + yasm_section_add_data(sect, &rdf_section_data_cb, data); + + sym = yasm_symtab_define_label(objfmt_rdf->symtab, sectname, + yasm_section_bcs_first(sect), 1, line); + data->sym = sym; + return data; +} + +static yasm_section * +rdf_objfmt_add_default_section(yasm_objfmt *objfmt) +{ + yasm_objfmt_rdf *objfmt_rdf = (yasm_objfmt_rdf *)objfmt; + yasm_section *retval; + rdf_section_data *rsd; + int isnew; + + retval = yasm_object_get_general(objfmt_rdf->object, ".text", 0, 0, 1, 0, + &isnew, 0); + if (isnew) { + rsd = rdf_objfmt_init_new_section(objfmt_rdf, retval, ".text", 0); + rsd->type = RDF_SECT_CODE; + rsd->reserved = 0; + yasm_section_set_default(retval, 1); + } + return retval; +} + +static /*@observer@*/ /*@null@*/ yasm_section * +rdf_objfmt_section_switch(yasm_objfmt *objfmt, yasm_valparamhead *valparams, + /*@unused@*/ /*@null@*/ + yasm_valparamhead *objext_valparams, + unsigned long line) +{ + yasm_objfmt_rdf *objfmt_rdf = (yasm_objfmt_rdf *)objfmt; + yasm_valparam *vp = yasm_vps_first(valparams); + yasm_section *retval; + int isnew; + unsigned int type = 0xffff; + unsigned int reserved = 0; + int flags_override = 0; + char *sectname; + rdf_section_data *rsd; + + static const struct { + const char *name; + unsigned int type; + } typenames[] = { + { "bss", RDF_SECT_BSS }, + { "code", RDF_SECT_CODE }, + { "text", RDF_SECT_CODE }, + { "data", RDF_SECT_DATA }, + { "comment", RDF_SECT_COMMENT }, + { "lcomment", RDF_SECT_LCOMMENT }, + { "pcomment", RDF_SECT_PCOMMENT }, + { "symdebug", RDF_SECT_SYMDEBUG }, + { "linedebug", RDF_SECT_LINEDEBUG }, + }; + + if (!vp || vp->param || !vp->val) + return NULL; + + sectname = vp->val; + + if (strcmp(sectname, ".text") == 0) + type = RDF_SECT_CODE; + else if (strcmp(sectname, ".data") == 0) + type = RDF_SECT_DATA; + else if (strcmp(sectname, ".bss") == 0) + type = RDF_SECT_BSS; + + /* Look for section type */ + if ((vp = yasm_vps_next(vp))) { + size_t i; + int match; + if (vp->val) { + match = 0; + for (i=0; ival, typenames[i].name) == 0) { + type = typenames[i].type; + flags_override = 1; + match = 1; + } + } + if (!match) + yasm_warn_set(YASM_WARN_GENERAL, + N_("Unrecognized RDF segment type `%s'"), + vp->val); + } else + yasm_warn_set(YASM_WARN_GENERAL, + N_("Unrecognized numeric qualifier")); + } + + if (type == 0xffff) { + yasm_error_set(YASM_ERROR_VALUE, + N_("new segment declared without type code")); + type = RDF_SECT_DATA; + } + + /* Look for reserved value */ + if (vp && (vp = yasm_vps_next(vp))) { + if (!vp->val && vp->param) { + /*@dependent@*/ /*@null@*/ const yasm_intnum *reserved_expr; + + reserved_expr = yasm_expr_get_intnum(&vp->param, 0); + if (!reserved_expr) + yasm_error_set(YASM_ERROR_VALUE, + N_("reserved value must be numeric")); + else + reserved = yasm_intnum_get_uint(reserved_expr); + } else if (vp->val) + yasm_warn_set(YASM_WARN_GENERAL, N_("Unrecognized qualifier `%s'"), + vp->val); + } + + retval = yasm_object_get_general(objfmt_rdf->object, sectname, 0, 0, 1, + type == RDF_SECT_BSS, &isnew, line); + + if (isnew) + rsd = rdf_objfmt_init_new_section(objfmt_rdf, retval, sectname, line); + else + rsd = yasm_section_get_data(retval, &rdf_section_data_cb); + + if (isnew || yasm_section_is_default(retval)) { + yasm_section_set_default(retval, 0); + rsd->type = type; + rsd->reserved = reserved; + } else if (flags_override) + yasm_warn_set(YASM_WARN_GENERAL, + N_("section flags ignored on section redeclaration")); + return retval; +} + +static void +rdf_section_data_destroy(void *data) +{ + rdf_section_data *rsd = (rdf_section_data *)data; + if (rsd->raw_data) + yasm_xfree(rsd->raw_data); + yasm_xfree(data); +} + +static void +rdf_section_data_print(void *data, FILE *f, int indent_level) +{ + rdf_section_data *rsd = (rdf_section_data *)data; + + fprintf(f, "%*ssym=\n", indent_level, ""); + yasm_symrec_print(rsd->sym, f, indent_level+1); + fprintf(f, "%*sscnum=%ld\n", indent_level, "", rsd->scnum); + fprintf(f, "%*stype=0x%x\n", indent_level, "", rsd->type); + fprintf(f, "%*sreserved=0x%x\n", indent_level, "", rsd->reserved); + fprintf(f, "%*ssize=%ld\n", indent_level, "", rsd->size); +} + +static yasm_symrec * +rdf_objfmt_extern_declare(yasm_objfmt *objfmt, const char *name, /*@unused@*/ + /*@null@*/ yasm_valparamhead *objext_valparams, + unsigned long line) +{ + yasm_objfmt_rdf *objfmt_rdf = (yasm_objfmt_rdf *)objfmt; + yasm_symrec *sym; + unsigned int flags = 0; + + static const struct { + const char *name; + unsigned int flags; + } flagnames[] = { + { "data", SYM_DATA }, + { "object", SYM_DATA }, + { "proc", SYM_FUNCTION }, + { "function", SYM_FUNCTION }, + { "import", SYM_IMPORT }, + { "far", SYM_FAR }, + }; + + sym = yasm_symtab_declare(objfmt_rdf->symtab, name, YASM_SYM_EXTERN, line); + + if (objext_valparams) { + yasm_valparam *vp = yasm_vps_first(objext_valparams); + for (; vp; vp = yasm_vps_next(vp)) { + size_t i; + int match; + + if (!vp->val) { + yasm_warn_set(YASM_WARN_GENERAL, + N_("Unrecognized numeric qualifier")); + continue; + } + + match = 0; + for (i=0; ival, flagnames[i].name) == 0) { + flags |= flagnames[i].flags; + match = 1; + } + } + + if (yasm__strcasecmp(vp->val, "near") == 0) { + flags &= ~SYM_FAR; + match = 1; + } + + if (!match) + yasm_warn_set(YASM_WARN_GENERAL, + N_("Unrecognized qualifier `%s'"), vp->val); + } + } + + /* Remember flags */ + rdf_objfmt_sym_set_data(sym, NULL, 0, flags); + return sym; +} + +static yasm_symrec * +rdf_objfmt_global_declare(yasm_objfmt *objfmt, const char *name, /*@unused@*/ + /*@null@*/ yasm_valparamhead *objext_valparams, + unsigned long line) +{ + yasm_objfmt_rdf *objfmt_rdf = (yasm_objfmt_rdf *)objfmt; + yasm_symrec *sym; + unsigned int flags = 0; + + static const struct { + const char *name; + unsigned int flags; + } flagnames[] = { + { "data", SYM_DATA }, + { "object", SYM_DATA }, + { "proc", SYM_FUNCTION }, + { "function", SYM_FUNCTION }, + { "export", SYM_GLOBAL }, + }; + + sym = yasm_symtab_declare(objfmt_rdf->symtab, name, YASM_SYM_GLOBAL, line); + + if (objext_valparams) { + yasm_valparam *vp = yasm_vps_first(objext_valparams); + for (; vp; vp = yasm_vps_next(vp)) { + size_t i; + int match; + + if (!vp->val) { + yasm_warn_set(YASM_WARN_GENERAL, + N_("Unrecognized numeric qualifier")); + continue; + } + + match = 0; + for (i=0; ival, flagnames[i].name) == 0) { + flags |= flagnames[i].flags; + match = 1; + } + } + if (!match) + yasm_warn_set(YASM_WARN_GENERAL, + N_("Unrecognized qualifier `%s'"), vp->val); + } + } + + /* Remember flags */ + rdf_objfmt_sym_set_data(sym, NULL, 0, flags); + return sym; +} + +static yasm_symrec * +rdf_objfmt_common_declare(yasm_objfmt *objfmt, const char *name, + /*@only@*/ yasm_expr *size, + yasm_valparamhead *objext_valparams, + unsigned long line) +{ + yasm_objfmt_rdf *objfmt_rdf = (yasm_objfmt_rdf *)objfmt; + yasm_symrec *sym; + rdf_symrec_data *rsymd; + unsigned long addralign = 0; + + sym = yasm_symtab_declare(objfmt_rdf->symtab, name, YASM_SYM_COMMON, line); + + if (objext_valparams) { + yasm_valparam *vp = yasm_vps_first(objext_valparams); + for (; vp; vp = yasm_vps_next(vp)) { + if (!vp->val && vp->param) { + /*@dependent@*/ /*@null@*/ const yasm_intnum *align_expr; + + align_expr = yasm_expr_get_intnum(&vp->param, 0); + if (!align_expr) { + yasm_error_set(YASM_ERROR_VALUE, + N_("alignment constraint is not a power of two")); + return sym; + } + addralign = yasm_intnum_get_uint(align_expr); + + /* Alignments must be a power of two. */ + if ((addralign & (addralign - 1)) != 0) { + yasm_error_set(YASM_ERROR_VALUE, + N_("alignment constraint is not a power of two")); + return sym; + } + } else if (vp->val) + yasm_warn_set(YASM_WARN_GENERAL, + N_("Unrecognized qualifier `%s'"), vp->val); + } + } + + /* Remember size and alignment */ + rdf_objfmt_sym_set_data(sym, size, addralign, 0); + return sym; +} + +static void +rdf_symrec_data_destroy(void *data) +{ + rdf_symrec_data *rsymd = (rdf_symrec_data *)data; + if (rsymd->size) + yasm_expr_destroy(rsymd->size); + yasm_xfree(data); +} + +static void +rdf_symrec_data_print(void *data, FILE *f, int indent_level) +{ + rdf_symrec_data *rsymd = (rdf_symrec_data *)data; + + fprintf(f, "%*ssymtab segment=%u\n", indent_level, "", rsymd->segment); + fprintf(f, "%*ssize=", indent_level, ""); + if (rsymd->size) + yasm_expr_print(rsymd->size, f); + else + fprintf(f, "nil"); + fprintf(f, "%*salign=%lu\n", indent_level, "", rsymd->align); +} + +static int +rdf_objfmt_directive(yasm_objfmt *objfmt, const char *name, + yasm_valparamhead *valparams, + /*@unused@*/ /*@null@*/ + yasm_valparamhead *objext_valparams, unsigned long line) +{ + yasm_objfmt_rdf *objfmt_rdf = (yasm_objfmt_rdf *)objfmt; + int lib; + yasm_valparam *vp; + xdf_str *str; + + if (yasm__strcasecmp(name, "library") == 0) + lib = 1; + else if (yasm__strcasecmp(name, "module") == 0) + lib = 0; + else + return 1; + + vp = yasm_vps_first(valparams); + if (!vp->val) { + yasm_error_set(YASM_ERROR_SYNTAX, N_("argument to [%s] must be name"), + name); + return 0; + } + + /* Add to list */ + str = yasm_xmalloc(sizeof(xdf_str)); + str->str = vp->val; + if (lib) + STAILQ_INSERT_TAIL(&objfmt_rdf->library_names, str, link); + else + STAILQ_INSERT_TAIL(&objfmt_rdf->module_names, str, link); + + if (strlen(str->str) > MODLIB_NAME_MAX-1) { + yasm_warn_set(YASM_WARN_GENERAL, + N_("name too long, truncating to %d bytes"), + MODLIB_NAME_MAX); + str->str[MODLIB_NAME_MAX-1] = '\0'; + } + + vp->val = NULL; /* don't free it */ + return 0; +} + + +/* Define valid debug formats to use with this object format */ +static const char *rdf_objfmt_dbgfmt_keywords[] = { + "null", + NULL +}; + +/* Define objfmt structure -- see objfmt.h for details */ +yasm_objfmt_module yasm_rdf_LTX_objfmt = { + "Relocatable Dynamic Object File Format (RDOFF) v2.0", + "rdf", + "rdf", + 32, + rdf_objfmt_dbgfmt_keywords, + "null", + rdf_objfmt_create, + rdf_objfmt_output, + rdf_objfmt_destroy, + rdf_objfmt_add_default_section, + rdf_objfmt_section_switch, + rdf_objfmt_extern_declare, + rdf_objfmt_global_declare, + rdf_objfmt_common_declare, + rdf_objfmt_directive +}; diff --git a/modules/objfmts/rdf/tests/Makefile.inc b/modules/objfmts/rdf/tests/Makefile.inc new file mode 100644 index 00000000..39f6aab3 --- /dev/null +++ b/modules/objfmts/rdf/tests/Makefile.inc @@ -0,0 +1,25 @@ +# $Id$ + +TESTS += modules/objfmts/rdf/tests/rdf_test.sh + +EXTRA_DIST += modules/objfmts/rdf/tests/rdf_test.sh +EXTRA_DIST += modules/objfmts/rdf/tests/rdfabs.asm +EXTRA_DIST += modules/objfmts/rdf/tests/rdfabs.errwarn +EXTRA_DIST += modules/objfmts/rdf/tests/rdfabs.hex +EXTRA_DIST += modules/objfmts/rdf/tests/rdfext.asm +EXTRA_DIST += modules/objfmts/rdf/tests/rdfext.hex +EXTRA_DIST += modules/objfmts/rdf/tests/rdfseg.asm +EXTRA_DIST += modules/objfmts/rdf/tests/rdfseg.hex +EXTRA_DIST += modules/objfmts/rdf/tests/rdfseg2.asm +EXTRA_DIST += modules/objfmts/rdf/tests/rdfseg2.hex +EXTRA_DIST += modules/objfmts/rdf/tests/rdftest1.asm +EXTRA_DIST += modules/objfmts/rdf/tests/rdftest1.hex +EXTRA_DIST += modules/objfmts/rdf/tests/rdftest2.asm +EXTRA_DIST += modules/objfmts/rdf/tests/rdftest2.hex +EXTRA_DIST += modules/objfmts/rdf/tests/rdtlib.asm +EXTRA_DIST += modules/objfmts/rdf/tests/rdtlib.hex +EXTRA_DIST += modules/objfmts/rdf/tests/rdtmain.asm +EXTRA_DIST += modules/objfmts/rdf/tests/rdtmain.hex +EXTRA_DIST += modules/objfmts/rdf/tests/testlib.asm +EXTRA_DIST += modules/objfmts/rdf/tests/testlib.hex + diff --git a/modules/objfmts/rdf/tests/rdf_test.sh b/modules/objfmts/rdf/tests/rdf_test.sh new file mode 100755 index 00000000..9161c378 --- /dev/null +++ b/modules/objfmts/rdf/tests/rdf_test.sh @@ -0,0 +1,4 @@ +#! /bin/sh +# $Id$ +${srcdir}/out_test.sh rdf_test modules/objfmts/rdf/tests "rdf objfmt" "-f rdf" ".rdf" +exit $? diff --git a/modules/objfmts/rdf/tests/rdfabs.asm b/modules/objfmts/rdf/tests/rdfabs.asm new file mode 100644 index 00000000..c6de90d4 --- /dev/null +++ b/modules/objfmts/rdf/tests/rdfabs.asm @@ -0,0 +1,7 @@ +absolute 0x5000 +label + +label2 equ 0x9999 + +global label +global label2 diff --git a/modules/objfmts/rdf/tests/rdfabs.errwarn b/modules/objfmts/rdf/tests/rdfabs.errwarn new file mode 100644 index 00000000..19ecde39 --- /dev/null +++ b/modules/objfmts/rdf/tests/rdfabs.errwarn @@ -0,0 +1,2 @@ +-:2: warning: rdf does not support exporting EQU/absolute values +-:4: warning: rdf does not support exporting EQU/absolute values diff --git a/modules/objfmts/rdf/tests/rdfabs.hex b/modules/objfmts/rdf/tests/rdfabs.hex new file mode 100644 index 00000000..ad42b027 --- /dev/null +++ b/modules/objfmts/rdf/tests/rdfabs.hex @@ -0,0 +1,24 @@ +52 +44 +4f +46 +46 +32 +0e +00 +00 +00 +00 +00 +00 +00 +00 +00 +00 +00 +00 +00 +00 +00 +00 +00 diff --git a/modules/objfmts/rdf/tests/rdfext.asm b/modules/objfmts/rdf/tests/rdfext.asm new file mode 100644 index 00000000..8bf5ea0f --- /dev/null +++ b/modules/objfmts/rdf/tests/rdfext.asm @@ -0,0 +1,63 @@ +module thismodule +module $thismodule +global foo:export +global bar:export proc +global bar2:export function +global baz:export data +global baz2:export object +extern extvar:import +extern func:proc +extern farfunc:far +library alib.rdl +common cvar 16:32 + +foo: +dd 0 +bar: +dd 0 +bar2: +dd 0 +call func +call farfunc ; generates a near call! +call far farfunc + +mov ax, seg farfunc +mov ax, farfunc +mov eax, farfunc + +mov eax, cvar + +section .data +baz: +dd 0 +baz2: +dd 0 + +section .bss +resb 4 + +;section a null + +section b text +dd 0 + +section c code +dd 0 + +section d data +dd 0 + +section e comment,5 ; after comma is reserved value +dd 0 + +section f lcomment +dd 0 + +section g pcomment,8 +dd 0 + +section h symdebug +dd 0 + +section i linedebug +dd 0 diff --git a/modules/objfmts/rdf/tests/rdfext.hex b/modules/objfmts/rdf/tests/rdfext.hex new file mode 100644 index 00000000..13693134 --- /dev/null +++ b/modules/objfmts/rdf/tests/rdfext.hex @@ -0,0 +1,447 @@ +52 +44 +4f +46 +46 +32 +b5 +01 +00 +00 +ec +00 +00 +00 +08 +0b +74 +68 +69 +73 +6d +6f +64 +75 +6c +65 +00 +08 +0c +24 +74 +68 +69 +73 +6d +6f +64 +75 +6c +65 +00 +04 +09 +61 +6c +69 +62 +2e +72 +64 +6c +00 +03 +0a +04 +00 +00 +00 +00 +00 +66 +6f +6f +00 +03 +0a +06 +00 +04 +00 +00 +00 +62 +61 +72 +00 +03 +0b +06 +00 +08 +00 +00 +00 +62 +61 +72 +32 +00 +03 +0a +05 +01 +00 +00 +00 +00 +62 +61 +7a +00 +03 +0b +05 +01 +04 +00 +00 +00 +62 +61 +7a +32 +00 +02 +0a +08 +0b +00 +65 +78 +74 +76 +61 +72 +00 +02 +08 +02 +0c +00 +66 +75 +6e +63 +00 +07 +0b +00 +0d +00 +66 +61 +72 +66 +75 +6e +63 +00 +0a +0d +0e +00 +10 +00 +00 +00 +20 +00 +63 +76 +61 +72 +00 +01 +08 +40 +0d +00 +00 +00 +04 +0c +00 +01 +08 +40 +12 +00 +00 +00 +04 +0d +00 +01 +08 +00 +17 +00 +00 +00 +04 +0d +00 +06 +08 +00 +1b +00 +00 +00 +02 +0d +00 +06 +08 +00 +1f +00 +00 +00 +02 +0d +00 +01 +08 +00 +23 +00 +00 +00 +02 +0d +00 +01 +08 +00 +26 +00 +00 +00 +04 +0d +00 +01 +08 +00 +2b +00 +00 +00 +04 +0e +00 +05 +04 +04 +00 +00 +00 +01 +00 +00 +00 +00 +00 +2f +00 +00 +00 +00 +00 +00 +00 +00 +00 +00 +00 +00 +00 +00 +00 +e8 +ef +ff +ff +ff +e8 +ea +ff +ff +ff +9a +00 +00 +00 +00 +00 +00 +66 +b8 +00 +00 +66 +b8 +00 +00 +b8 +00 +00 +00 +00 +b8 +00 +00 +00 +00 +02 +00 +01 +00 +00 +00 +08 +00 +00 +00 +00 +00 +00 +00 +00 +00 +00 +00 +01 +00 +03 +00 +00 +00 +04 +00 +00 +00 +00 +00 +00 +00 +01 +00 +04 +00 +00 +00 +04 +00 +00 +00 +00 +00 +00 +00 +02 +00 +05 +00 +00 +00 +04 +00 +00 +00 +00 +00 +00 +00 +03 +00 +06 +00 +05 +00 +04 +00 +00 +00 +00 +00 +00 +00 +04 +00 +07 +00 +00 +00 +04 +00 +00 +00 +00 +00 +00 +00 +05 +00 +08 +00 +08 +00 +04 +00 +00 +00 +00 +00 +00 +00 +06 +00 +09 +00 +00 +00 +04 +00 +00 +00 +00 +00 +00 +00 +07 +00 +0a +00 +00 +00 +04 +00 +00 +00 +00 +00 +00 +00 +00 +00 +00 +00 +00 +00 +00 +00 +00 +00 diff --git a/modules/objfmts/rdf/tests/rdfseg.asm b/modules/objfmts/rdf/tests/rdfseg.asm new file mode 100644 index 00000000..4c6f587b --- /dev/null +++ b/modules/objfmts/rdf/tests/rdfseg.asm @@ -0,0 +1,20 @@ + ;; program to test inter-segment production and linkage of RDF objects + + ;; [1] should produce segment base ref + ;; [2] should produce standard relocation + +[GLOBAL _main] +[EXTERN _puts: far] +[BITS 16] + +_main: + mov ax, seg _message ; 0000 [1] + mov ds, ax ; 0003 + mov dx, _message ; 0005 [2] + call far _puts ; 0008 [2][1] + xor ax,ax ; 000D + int 21h ; 000F + +[SECTION .data] +_message: db 'Hello, World', 10, 13, 0 + \ No newline at end of file diff --git a/modules/objfmts/rdf/tests/rdfseg.hex b/modules/objfmts/rdf/tests/rdfseg.hex new file mode 100644 index 00000000..302ceb5b --- /dev/null +++ b/modules/objfmts/rdf/tests/rdfseg.hex @@ -0,0 +1,141 @@ +52 +44 +4f +46 +46 +32 +83 +00 +00 +00 +41 +00 +00 +00 +03 +0c +00 +00 +00 +00 +00 +00 +5f +6d +61 +69 +6e +00 +07 +09 +00 +02 +00 +5f +70 +75 +74 +73 +00 +06 +08 +00 +01 +00 +00 +00 +02 +01 +00 +01 +08 +00 +06 +00 +00 +00 +02 +01 +00 +01 +08 +00 +09 +00 +00 +00 +02 +02 +00 +06 +08 +00 +0b +00 +00 +00 +02 +02 +00 +01 +00 +00 +00 +00 +00 +11 +00 +00 +00 +b8 +00 +00 +8e +d8 +ba +00 +00 +9a +00 +00 +00 +00 +31 +c0 +cd +21 +02 +00 +01 +00 +00 +00 +0f +00 +00 +00 +48 +65 +6c +6c +6f +2c +20 +57 +6f +72 +6c +64 +0a +0d +00 +00 +00 +00 +00 +00 +00 +00 +00 +00 +00 diff --git a/modules/objfmts/rdf/tests/rdfseg2.asm b/modules/objfmts/rdf/tests/rdfseg2.asm new file mode 100644 index 00000000..2b9e4fd0 --- /dev/null +++ b/modules/objfmts/rdf/tests/rdfseg2.asm @@ -0,0 +1,12 @@ + ;; library function for rdfseg - this file is linked as a far segment + +[BITS 16] +[GLOBAL _puts] +_puts: + ;; can't remember how to print a string in DOS, but if anyone wants + ;; to actually test this program, it should be fairly easy to put + ;; in here! + + retf + + \ No newline at end of file diff --git a/modules/objfmts/rdf/tests/rdfseg2.hex b/modules/objfmts/rdf/tests/rdfseg2.hex new file mode 100644 index 00000000..157a99a5 --- /dev/null +++ b/modules/objfmts/rdf/tests/rdfseg2.hex @@ -0,0 +1,49 @@ +52 +44 +4f +46 +46 +32 +27 +00 +00 +00 +0e +00 +00 +00 +03 +0c +00 +00 +00 +00 +00 +00 +5f +70 +75 +74 +73 +00 +01 +00 +00 +00 +00 +00 +01 +00 +00 +00 +cb +00 +00 +00 +00 +00 +00 +00 +00 +00 +00 diff --git a/modules/objfmts/rdf/tests/rdftest1.asm b/modules/objfmts/rdf/tests/rdftest1.asm new file mode 100644 index 00000000..76f1e43e --- /dev/null +++ b/modules/objfmts/rdf/tests/rdftest1.asm @@ -0,0 +1,54 @@ + ;; program to test RDOFF production and linkage + + ;; items to test include: + ;; [1] relocation within the same segment in each module + ;; [2] relocation to different segments in same module + ;; [3] relocation to same segment in different module + ;; [4] relocation to different segment in different module + ;; [5] relative relocation to same module + ;; [6] relative relocation to different module + ;; [7] correct generation of BSS addresses + +[SECTION .text] +[BITS 32] + +_main: + mov ax,localdata ; [2] (16 bit) => 66 b8 0000 + mov eax,localdata2 ; [2] (32 bit) => b8 0000000a + +[EXTERN _fardata] + + mov eax,[_fardata] ; [4] => a1 00000000 (+20) + mov cx,next ; [1] => 66 b9 0012 +next: + call localproc ; [5] => e8 00000019 + +[EXTERN _farproc] + mov eax,_farproc ; [3] => b8 00000000 (+40+0) + call _farproc ; [6] => e8 -$ (-0+40+0) (=1f) + + mov eax,localbss ; [7] => b8 00000000 + +[GLOBAL _term] +_term: xor ax,ax ; => 66 31 c0 + int 21h ; => cd 21 + jmp _term ; => e9 -0a (=fffffff6) + +localproc: + ret ; => c3 + +[GLOBAL _test1proc] +_test1proc: + call localproc ; [5] => e8 -$ (-0+0+?) (=-6=fffffffa) + ret ; => c3 + +[SECTION .data] +[GLOBAL localdata2] +localdata: db 'localdata',0 +localdata2: db 'localdata2',0 +farref: dd _fardata ; [3] => 0 (+20) +localref: dd _main ; [2] => 0 (+0) + +[SECTION .bss] +localbss: resw 4 ; reserve 8 bytes BSS + \ No newline at end of file diff --git a/modules/objfmts/rdf/tests/rdftest1.hex b/modules/objfmts/rdf/tests/rdftest1.hex new file mode 100644 index 00000000..a8a86bc7 --- /dev/null +++ b/modules/objfmts/rdf/tests/rdftest1.hex @@ -0,0 +1,301 @@ +52 +44 +4f +46 +46 +32 +23 +01 +00 +00 +b0 +00 +00 +00 +03 +11 +00 +01 +0a +00 +00 +00 +6c +6f +63 +61 +6c +64 +61 +74 +61 +32 +00 +02 +0c +00 +03 +00 +5f +66 +61 +72 +64 +61 +74 +61 +00 +02 +0c +00 +04 +00 +5f +66 +61 +72 +70 +72 +6f +63 +00 +03 +0c +00 +00 +26 +00 +00 +00 +5f +74 +65 +72 +6d +00 +03 +11 +00 +00 +2e +00 +00 +00 +5f +74 +65 +73 +74 +31 +70 +72 +6f +63 +00 +01 +08 +00 +02 +00 +00 +00 +02 +01 +00 +01 +08 +00 +05 +00 +00 +00 +04 +01 +00 +01 +08 +00 +0a +00 +00 +00 +04 +03 +00 +01 +08 +00 +10 +00 +00 +00 +02 +00 +00 +01 +08 +00 +18 +00 +00 +00 +04 +04 +00 +01 +08 +40 +1d +00 +00 +00 +04 +04 +00 +01 +08 +00 +22 +00 +00 +00 +04 +02 +00 +01 +08 +01 +15 +00 +00 +00 +04 +03 +00 +01 +08 +01 +19 +00 +00 +00 +04 +00 +00 +05 +04 +08 +00 +00 +00 +01 +00 +00 +00 +00 +00 +34 +00 +00 +00 +66 +b8 +00 +00 +b8 +0a +00 +00 +00 +a1 +00 +00 +00 +00 +66 +b9 +12 +00 +e8 +16 +00 +00 +00 +b8 +00 +00 +00 +00 +e8 +df +ff +ff +ff +b8 +00 +00 +00 +00 +66 +31 +c0 +cd +21 +eb +f9 +c3 +e8 +fa +ff +ff +ff +c3 +02 +00 +01 +00 +00 +00 +1d +00 +00 +00 +6c +6f +63 +61 +6c +64 +61 +74 +61 +00 +6c +6f +63 +61 +6c +64 +61 +74 +61 +32 +00 +00 +00 +00 +00 +00 +00 +00 +00 +00 +00 +00 +00 +00 +00 +00 +00 +00 +00 diff --git a/modules/objfmts/rdf/tests/rdftest2.asm b/modules/objfmts/rdf/tests/rdftest2.asm new file mode 100644 index 00000000..25b8c189 --- /dev/null +++ b/modules/objfmts/rdf/tests/rdftest2.asm @@ -0,0 +1,33 @@ + ;; rdftest2.asm - test linkage and generation of RDOFF files + +[SECTION .text] +[BITS 32] + +[GLOBAL _farproc] +[EXTERN _test1proc] +[EXTERN localdata2] +[EXTERN _term] +_farproc: + + mov bx,localdata2 ; [4] 0 => 66 bb 000a(+0) + mov eax,_term ; [3] 5 => b8 00000000(+26+0) + call _test1proc ; [6] A => e8 fffffff2(-40+0+31)(=ffffffe3) + + mov eax,_farproc ; [1] => b8 00000000(+40) + add eax,[_fardata] ; [2] => 03 05 00000000(+20) + + mov ebx,mybssdata ; [7] => bb 00000000(+08) + call myproc ; [5] => e8 00000001 + ret + +myproc: + add eax,ebx + ret + +[SECTION .data] +[GLOBAL _fardata] +_fardata: dw _term ; [4] +_localref: dd _farproc ; [2] + +[SECTION .bss] +mybssdata: resw 1 diff --git a/modules/objfmts/rdf/tests/rdftest2.hex b/modules/objfmts/rdf/tests/rdftest2.hex new file mode 100644 index 00000000..1e6b89f9 --- /dev/null +++ b/modules/objfmts/rdf/tests/rdftest2.hex @@ -0,0 +1,252 @@ +52 +44 +4f +46 +46 +32 +f2 +00 +00 +00 +a3 +00 +00 +00 +03 +0f +00 +00 +00 +00 +00 +00 +5f +66 +61 +72 +70 +72 +6f +63 +00 +02 +0e +00 +03 +00 +5f +74 +65 +73 +74 +31 +70 +72 +6f +63 +00 +02 +0e +00 +04 +00 +6c +6f +63 +61 +6c +64 +61 +74 +61 +32 +00 +02 +09 +00 +05 +00 +5f +74 +65 +72 +6d +00 +03 +0f +00 +01 +00 +00 +00 +00 +5f +66 +61 +72 +64 +61 +74 +61 +00 +01 +08 +00 +02 +00 +00 +00 +02 +04 +00 +01 +08 +00 +05 +00 +00 +00 +04 +05 +00 +01 +08 +40 +0a +00 +00 +00 +04 +03 +00 +01 +08 +00 +0f +00 +00 +00 +04 +00 +00 +01 +08 +00 +15 +00 +00 +00 +04 +01 +00 +01 +08 +00 +1a +00 +00 +00 +04 +02 +00 +01 +08 +01 +00 +00 +00 +00 +02 +05 +00 +01 +08 +01 +02 +00 +00 +00 +04 +00 +00 +05 +04 +02 +00 +00 +00 +01 +00 +00 +00 +00 +00 +27 +00 +00 +00 +66 +bb +00 +00 +b8 +00 +00 +00 +00 +e8 +f2 +ff +ff +ff +b8 +00 +00 +00 +00 +03 +05 +00 +00 +00 +00 +bb +00 +00 +00 +00 +e8 +01 +00 +00 +00 +c3 +01 +d8 +c3 +02 +00 +01 +00 +00 +00 +06 +00 +00 +00 +00 +00 +00 +00 +00 +00 +00 +00 +00 +00 +00 +00 +00 +00 +00 +00 diff --git a/modules/objfmts/rdf/tests/rdtlib.asm b/modules/objfmts/rdf/tests/rdtlib.asm new file mode 100644 index 00000000..6c2b8ec9 --- /dev/null +++ b/modules/objfmts/rdf/tests/rdtlib.asm @@ -0,0 +1,48 @@ + ;; library functions for rdtmain - test of rdx linking and execution + + ;; library function = _strcmp, defined as in C + +[SECTION .text] +[BITS 32] + +[GLOBAL _strcmp] +_strcmp: + push ebp + mov ebp,esp + + ;; ebp+8 = first paramater, ebp+12 = second + + mov esi,[ebp+8] + mov edi,[ebp+12] + +.loop: + mov cl,byte [esi] + mov dl,byte [edi] + cmp cl,dl + jb .below + ja .above + or cl,cl + jz .match + inc esi + inc edi + jmp .loop + +.below: + mov eax,-1 + pop ebp + ret + +.above: + mov eax,1 + pop ebp + ret + +.match: + xor eax,eax + pop ebp + ret + +[SECTION .data] +[GLOBAL _message] + +_message: db 'hello',0 \ No newline at end of file diff --git a/modules/objfmts/rdf/tests/rdtlib.hex b/modules/objfmts/rdf/tests/rdtlib.hex new file mode 100644 index 00000000..107b0ab5 --- /dev/null +++ b/modules/objfmts/rdf/tests/rdtlib.hex @@ -0,0 +1,128 @@ +52 +44 +4f +46 +46 +32 +76 +00 +00 +00 +21 +00 +00 +00 +03 +0e +00 +00 +00 +00 +00 +00 +5f +73 +74 +72 +63 +6d +70 +00 +03 +0f +00 +01 +00 +00 +00 +00 +5f +6d +65 +73 +73 +61 +67 +65 +00 +01 +00 +00 +00 +00 +00 +2d +00 +00 +00 +55 +89 +e5 +8b +75 +08 +8b +7d +0c +8a +0e +8a +17 +38 +d1 +72 +0a +77 +0f +08 +c9 +74 +12 +46 +47 +eb +ee +b8 +ff +ff +ff +ff +5d +c3 +b8 +01 +00 +00 +00 +5d +c3 +31 +c0 +5d +c3 +02 +00 +01 +00 +00 +00 +06 +00 +00 +00 +68 +65 +6c +6c +6f +00 +00 +00 +00 +00 +00 +00 +00 +00 +00 +00 diff --git a/modules/objfmts/rdf/tests/rdtmain.asm b/modules/objfmts/rdf/tests/rdtmain.asm new file mode 100644 index 00000000..626a2e29 --- /dev/null +++ b/modules/objfmts/rdf/tests/rdtmain.asm @@ -0,0 +1,47 @@ + ;; rdtmain - main part of test program for RDX execution. + ;; returns true (0) if its parameter equals the phrase "hello" + ;; "hello" is stored in the library part, to complicate the + ;; linkage. + + ;; assemble and link with the following commands: + ;; nasm -f rdf rdtmain.asm + ;; nasm -f rdf rdtlib.asm + ;; ldrdf rdtmain.rdf rdtlib.rdf -o rdxtest.rdx + + ;; run with 'rdx rdxtest.rdx [parameters]' on a Linux (or possibly + ;; other 32 bit OS) systems (x86 architectures only!) + ;; try using '&& echo Yes' afterwards to find out when it returns 0. + +[EXTERN _strcmp] ; strcmp is an imported function +[EXTERN _message] ; imported data +[SECTION .text] +[BITS 32] + + ;; main(int argc,char **argv) +[GLOBAL _main] +_main: + push ebp + mov ebp,esp + + ;; ebp+8 = argc, ebp+12 = argv + + cmp dword [ebp+8],2 + jb error ; cause error if < 1 parameters + + mov eax, [ebp+12] ; eax = argv + + mov ebx, [eax+4] ; ebx = argv[1] + mov ecx, _message ; ecx = "hello" + + push ecx + push ebx + call _strcmp ; compare strings + add esp,8 ; caller clears stack + + pop ebp + ret ; return return value of _strcmp + +error: + mov eax,2 ; return 2 on error + pop ebp + ret diff --git a/modules/objfmts/rdf/tests/rdtmain.hex b/modules/objfmts/rdf/tests/rdtmain.hex new file mode 100644 index 00000000..5af817d9 --- /dev/null +++ b/modules/objfmts/rdf/tests/rdtmain.hex @@ -0,0 +1,134 @@ +52 +44 +4f +46 +46 +32 +7c +00 +00 +00 +3d +00 +00 +00 +02 +0b +00 +01 +00 +5f +73 +74 +72 +63 +6d +70 +00 +02 +0c +00 +02 +00 +5f +6d +65 +73 +73 +61 +67 +65 +00 +03 +0c +00 +00 +00 +00 +00 +00 +5f +6d +61 +69 +6e +00 +01 +08 +00 +10 +00 +00 +00 +04 +02 +00 +01 +08 +40 +17 +00 +00 +00 +04 +01 +00 +01 +00 +00 +00 +00 +00 +27 +00 +00 +00 +55 +89 +e5 +83 +7d +08 +02 +72 +17 +8b +45 +0c +8b +58 +04 +b9 +00 +00 +00 +00 +51 +53 +e8 +e5 +ff +ff +ff +83 +c4 +08 +5d +c3 +b8 +02 +00 +00 +00 +5d +c3 +00 +00 +00 +00 +00 +00 +00 +00 +00 +00 diff --git a/modules/objfmts/rdf/tests/testlib.asm b/modules/objfmts/rdf/tests/testlib.asm new file mode 100644 index 00000000..6ee3d89a --- /dev/null +++ b/modules/objfmts/rdf/tests/testlib.asm @@ -0,0 +1,18 @@ +; program to test retrieval of and linkage to modules in libraries by +; ldrdf + +[SECTION .text] +[GLOBAL _main] +[EXTERN _strcmp] + +_main: + push dword string1 + push dword string2 + call _strcmp + add esp,8 ; doh! clear up stack ;-) + ret + +[SECTION .data] + +string1: db 'abc',0 ; try changing these strings and see +string2: db 'abd',0 ; what happens! diff --git a/modules/objfmts/rdf/tests/testlib.hex b/modules/objfmts/rdf/tests/testlib.hex new file mode 100644 index 00000000..0067d611 --- /dev/null +++ b/modules/objfmts/rdf/tests/testlib.hex @@ -0,0 +1,128 @@ +52 +44 +4f +46 +46 +32 +76 +00 +00 +00 +39 +00 +00 +00 +03 +0c +00 +00 +00 +00 +00 +00 +5f +6d +61 +69 +6e +00 +02 +0b +00 +02 +00 +5f +73 +74 +72 +63 +6d +70 +00 +01 +08 +00 +01 +00 +00 +00 +04 +01 +00 +01 +08 +00 +06 +00 +00 +00 +04 +01 +00 +01 +08 +40 +0b +00 +00 +00 +04 +02 +00 +01 +00 +00 +00 +00 +00 +13 +00 +00 +00 +68 +00 +00 +00 +00 +68 +04 +00 +00 +00 +e8 +f1 +ff +ff +ff +83 +c4 +08 +c3 +02 +00 +01 +00 +00 +00 +08 +00 +00 +00 +61 +62 +63 +00 +61 +62 +64 +00 +00 +00 +00 +00 +00 +00 +00 +00 +00 +00 diff --git a/modules/preprocs/nasm/standard.mac b/modules/preprocs/nasm/standard.mac index 01ea7fe2..56323a31 100644 --- a/modules/preprocs/nasm/standard.mac +++ b/modules/preprocs/nasm/standard.mac @@ -177,3 +177,12 @@ __SECT__ %endmacro %endif +%ifidn __YASM_OBJFMT__,rdf +%imacro library 1+.nolist +[library %1] +%endmacro +%imacro module 1+.nolist +[module %1] +%endmacro +%endif +