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