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