Home | History | Annotate | Download | only in nasm
      1 /*
      2  * NASM-style list format
      3  *
      4  *  Copyright (C) 2004-2007  Peter Johnson
      5  *
      6  * Redistribution and use in source and binary forms, with or without
      7  * modification, are permitted provided that the following conditions
      8  * are met:
      9  * 1. Redistributions of source code must retain the above copyright
     10  *    notice, this list of conditions and the following disclaimer.
     11  * 2. Redistributions in binary form must reproduce the above copyright
     12  *    notice, this list of conditions and the following disclaimer in the
     13  *    documentation and/or other materials provided with the distribution.
     14  *
     15  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND OTHER CONTRIBUTORS ``AS IS''
     16  * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
     17  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
     18  * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR OTHER CONTRIBUTORS BE
     19  * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
     20  * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
     21  * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
     22  * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
     23  * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
     24  * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
     25  * POSSIBILITY OF SUCH DAMAGE.
     26  */
     27 #include <util.h>
     28 
     29 #include <libyasm.h>
     30 
     31 /* NOTE: For this code to generate relocation information, the relocations
     32  * have to be added by the object format to each section in program source
     33  * order.
     34  *
     35  * This should not be an issue, as program source order == section bytecode
     36  * order, so unless the object formats are very obtuse with their bytecode
     37  * iteration, this should just happen.
     38  */
     39 
     40 #define REGULAR_BUF_SIZE    1024
     41 
     42 yasm_listfmt_module yasm_nasm_LTX_listfmt;
     43 
     44 typedef struct sectreloc {
     45     /*@reldef@*/ SLIST_ENTRY(sectreloc) link;
     46     yasm_section *sect;
     47     /*@null@*/ yasm_reloc *next_reloc;  /* next relocation in section */
     48     unsigned long next_reloc_addr;
     49 } sectreloc;
     50 
     51 typedef struct bcreloc {
     52     /*@reldef@*/ STAILQ_ENTRY(bcreloc) link;
     53     unsigned long offset;       /* start of reloc from start of bytecode */
     54     size_t size;                /* size of reloc in bytes */
     55     int rel;                    /* PC/IP-relative or "absolute" */
     56 } bcreloc;
     57 
     58 typedef struct nasm_listfmt_output_info {
     59     yasm_arch *arch;
     60     /*@reldef@*/ STAILQ_HEAD(bcrelochead, bcreloc) bcrelocs;
     61     /*@null@*/ yasm_reloc *next_reloc;  /* next relocation in section */
     62     unsigned long next_reloc_addr;
     63 } nasm_listfmt_output_info;
     64 
     65 
     66 static /*@null@*/ /*@only@*/ yasm_listfmt *
     67 nasm_listfmt_create(const char *in_filename, const char *obj_filename)
     68 {
     69     yasm_listfmt_base *listfmt = yasm_xmalloc(sizeof(yasm_listfmt_base));
     70     listfmt->module = &yasm_nasm_LTX_listfmt;
     71     return (yasm_listfmt *)listfmt;
     72 }
     73 
     74 static void
     75 nasm_listfmt_destroy(/*@only@*/ yasm_listfmt *listfmt)
     76 {
     77     yasm_xfree(listfmt);
     78 }
     79 
     80 static int
     81 nasm_listfmt_output_value(yasm_value *value, unsigned char *buf,
     82                           unsigned int destsize, unsigned long offset,
     83                           yasm_bytecode *bc, int warn, /*@null@*/ void *d)
     84 {
     85     /*@null@*/ nasm_listfmt_output_info *info = (nasm_listfmt_output_info *)d;
     86     /*@dependent@*/ /*@null@*/ yasm_intnum *intn;
     87     unsigned int valsize = value->size;
     88 
     89     assert(info != NULL);
     90 
     91     /* Output */
     92     switch (yasm_value_output_basic(value, buf, destsize, bc, warn,
     93                                     info->arch)) {
     94         case -1:
     95             return 1;
     96         case 0:
     97             break;
     98         default:
     99             return 0;
    100     }
    101 
    102     /* Generate reloc if needed */
    103     if (info->next_reloc && info->next_reloc_addr == bc->offset+offset) {
    104         bcreloc *reloc = yasm_xmalloc(sizeof(bcreloc));
    105         reloc->offset = offset;
    106         reloc->size = destsize;
    107         reloc->rel = value->curpos_rel;
    108         STAILQ_INSERT_TAIL(&info->bcrelocs, reloc, link);
    109 
    110         /* Get next reloc's info */
    111         info->next_reloc = yasm_section_reloc_next(info->next_reloc);
    112         if (info->next_reloc) {
    113             yasm_intnum *addr;
    114             yasm_symrec *sym;
    115             yasm_reloc_get(info->next_reloc, &addr, &sym);
    116             info->next_reloc_addr = yasm_intnum_get_uint(addr);
    117         }
    118     }
    119 
    120     if (value->abs) {
    121         intn = yasm_expr_get_intnum(&value->abs, 0);
    122         if (intn)
    123             return yasm_arch_intnum_tobytes(info->arch, intn, buf, destsize,
    124                                             valsize, 0, bc, 0);
    125         else {
    126             yasm_error_set(YASM_ERROR_TOO_COMPLEX,
    127                            N_("relocation too complex"));
    128             return 1;
    129         }
    130     } else {
    131         int retval;
    132         intn = yasm_intnum_create_uint(0);
    133         retval = yasm_arch_intnum_tobytes(info->arch, intn, buf, destsize,
    134                                           valsize, 0, bc, 0);
    135         yasm_intnum_destroy(intn);
    136         return retval;
    137     }
    138 
    139     return 0;
    140 }
    141 
    142 static void
    143 nasm_listfmt_output(yasm_listfmt *listfmt, FILE *f, yasm_linemap *linemap,
    144                     yasm_arch *arch)
    145 {
    146     yasm_bytecode *bc;
    147     const char *source;
    148     unsigned long line = 1;
    149     unsigned long listline = 1;
    150     /*@only@*/ unsigned char *buf;
    151     nasm_listfmt_output_info info;
    152     /*@reldef@*/ SLIST_HEAD(sectrelochead, sectreloc) reloc_hist;
    153     /*@null@*/ sectreloc *last_hist = NULL;
    154     /*@null@*/ bcreloc *reloc = NULL;
    155     yasm_section *sect;
    156 
    157     SLIST_INIT(&reloc_hist);
    158 
    159     info.arch = arch;
    160 
    161     buf = yasm_xmalloc(REGULAR_BUF_SIZE);
    162 
    163     while (!yasm_linemap_get_source(linemap, line, &bc, &source)) {
    164         if (!bc) {
    165             fprintf(f, "%6lu %*s%s\n", listline++, 32, "", source);
    166         } else {
    167             /* get the next relocation for the bytecode's section */
    168             sect = yasm_bc_get_section(bc);
    169             if (!last_hist || last_hist->sect != sect) {
    170                 int found = 0;
    171 
    172                 /* look through reloc_hist for matching section */
    173                 SLIST_FOREACH(last_hist, &reloc_hist, link) {
    174                     if (last_hist->sect == sect) {
    175                         found = 1;
    176                         break;
    177                     }
    178                 }
    179 
    180                 if (!found) {
    181                     /* not found, add to list*/
    182                     last_hist = yasm_xmalloc(sizeof(sectreloc));
    183                     last_hist->sect = sect;
    184                     last_hist->next_reloc = yasm_section_relocs_first(sect);
    185 
    186                     if (last_hist->next_reloc) {
    187                         yasm_intnum *addr;
    188                         yasm_symrec *sym;
    189                         yasm_reloc_get(last_hist->next_reloc, &addr, &sym);
    190                         last_hist->next_reloc_addr =
    191                             yasm_intnum_get_uint(addr);
    192                     }
    193 
    194                     SLIST_INSERT_HEAD(&reloc_hist, last_hist, link);
    195                 }
    196             }
    197 
    198             info.next_reloc = last_hist->next_reloc;
    199             info.next_reloc_addr = last_hist->next_reloc_addr;
    200             STAILQ_INIT(&info.bcrelocs);
    201 
    202             /* loop over bytecodes on this line (usually only one) */
    203             while (bc && bc->line == line) {
    204                 /*@null@*/ /*@only@*/ unsigned char *bigbuf;
    205                 unsigned long size = REGULAR_BUF_SIZE;
    206                 long multiple;
    207                 unsigned long offset = bc->offset;
    208                 unsigned char *origp, *p;
    209                 int gap;
    210 
    211                 /* convert bytecode into bytes, recording relocs along the
    212                  * way
    213                  */
    214                 bigbuf = yasm_bc_tobytes(bc, buf, &size, &gap, &info,
    215                                          nasm_listfmt_output_value, NULL);
    216                 yasm_bc_get_multiple(bc, &multiple, 1);
    217                 if (multiple <= 0)
    218                     size = 0;
    219                 else
    220                     size /= multiple;
    221 
    222                 /* output bytes with reloc information */
    223                 origp = bigbuf ? bigbuf : buf;
    224                 p = origp;
    225                 reloc = STAILQ_FIRST(&info.bcrelocs);
    226                 if (gap) {
    227                     fprintf(f, "%6lu %08lX <gap>%*s%s\n", listline++, offset,
    228                             18, "", source ? source : "");
    229                 } else while (size > 0) {
    230                     int i;
    231 
    232                     fprintf(f, "%6lu %08lX ", listline++, offset);
    233                     for (i=0; i<18 && size > 0; size--) {
    234                         if (reloc && (unsigned long)(p-origp) ==
    235                                      reloc->offset) {
    236                             fprintf(f, "%c", reloc->rel ? '(' : '[');
    237                             i++;
    238                         }
    239                         fprintf(f, "%02X", *(p++));
    240                         i+=2;
    241                         if (reloc && (unsigned long)(p-origp) ==
    242                                      reloc->offset+reloc->size) {
    243                             fprintf(f, "%c", reloc->rel ? ')' : ']');
    244                             i++;
    245                             reloc = STAILQ_NEXT(reloc, link);
    246                         }
    247                     }
    248                     if (size > 0)
    249                         fprintf(f, "-");
    250                     else {
    251                         if (multiple > 1) {
    252                             fprintf(f, "<rept>");
    253                             i += 6;
    254                         }
    255                         fprintf(f, "%*s", 18-i+1, "");
    256                     }
    257                     if (source) {
    258                         fprintf(f, "    %s", source);
    259                         source = NULL;
    260                     }
    261                     fprintf(f, "\n");
    262                 }
    263 
    264                 if (bigbuf)
    265                     yasm_xfree(bigbuf);
    266                 bc = STAILQ_NEXT(bc, link);
    267             }
    268 
    269             /* delete bcrelocs (newly generated next bytecode if any) */
    270             reloc = STAILQ_FIRST(&info.bcrelocs);
    271             while (reloc) {
    272                 bcreloc *reloc2 = STAILQ_NEXT(reloc, link);
    273                 yasm_xfree(reloc);
    274                 reloc = reloc2;
    275             }
    276 
    277             /* save reloc context */
    278             last_hist->next_reloc = info.next_reloc;
    279             last_hist->next_reloc_addr = info.next_reloc_addr;
    280         }
    281         line++;
    282     }
    283 
    284     /* delete reloc history */
    285     while (!SLIST_EMPTY(&reloc_hist)) {
    286         last_hist = SLIST_FIRST(&reloc_hist);
    287         SLIST_REMOVE_HEAD(&reloc_hist, link);
    288         yasm_xfree(last_hist);
    289     }
    290 
    291     yasm_xfree(buf);
    292 }
    293 
    294 /* Define listfmt structure -- see listfmt.h for details */
    295 yasm_listfmt_module yasm_nasm_LTX_listfmt = {
    296     "NASM-style list format",
    297     "nasm",
    298     nasm_listfmt_create,
    299     nasm_listfmt_destroy,
    300     nasm_listfmt_output
    301 };
    302