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 *
nasm_listfmt_create(const char * in_filename,const char * obj_filename)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
nasm_listfmt_destroy(yasm_listfmt * listfmt)75 nasm_listfmt_destroy(/*@only@*/ yasm_listfmt *listfmt)
76 {
77     yasm_xfree(listfmt);
78 }
79 
80 static int
nasm_listfmt_output_value(yasm_value * value,unsigned char * buf,unsigned int destsize,unsigned long offset,yasm_bytecode * bc,int warn,void * d)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
nasm_listfmt_output(yasm_listfmt * listfmt,FILE * f,yasm_linemap * linemap,yasm_arch * arch)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