1 /* ----------------------------------------------------------------------- *
2 *
3 * Copyright 1996-2017 The NASM Authors - All Rights Reserved
4 * See the file AUTHORS included with the NASM distribution for
5 * the specific copyright holders.
6 *
7 * Redistribution and use in source and binary forms, with or without
8 * modification, are permitted provided that the following
9 * conditions are met:
10 *
11 * * Redistributions of source code must retain the above copyright
12 * notice, this list of conditions and the following disclaimer.
13 * * Redistributions in binary form must reproduce the above
14 * copyright notice, this list of conditions and the following
15 * disclaimer in the documentation and/or other materials provided
16 * with the distribution.
17 *
18 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND
19 * CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES,
20 * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
21 * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
22 * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
23 * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
24 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
25 * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
26 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
27 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
28 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
29 * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE,
30 * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
31 *
32 * ----------------------------------------------------------------------- */
33
34 #include "compiler.h"
35 #include "nasmlib.h"
36 #include "saa.h"
37
38 /* Aggregate SAA components smaller than this */
39 #define SAA_BLKSHIFT 16
40 #define SAA_BLKLEN ((size_t)1 << SAA_BLKSHIFT)
41
saa_init(size_t elem_len)42 struct SAA *saa_init(size_t elem_len)
43 {
44 struct SAA *s;
45 char *data;
46
47 s = nasm_zalloc(sizeof(struct SAA));
48
49 if (elem_len >= SAA_BLKLEN)
50 s->blk_len = elem_len;
51 else
52 s->blk_len = SAA_BLKLEN - (SAA_BLKLEN % elem_len);
53
54 s->elem_len = elem_len;
55 s->length = s->blk_len;
56 data = nasm_malloc(s->blk_len);
57 s->nblkptrs = s->nblks = 1;
58 s->blk_ptrs = nasm_malloc(sizeof(char *));
59 s->blk_ptrs[0] = data;
60 s->wblk = s->rblk = &s->blk_ptrs[0];
61
62 return s;
63 }
64
saa_free(struct SAA * s)65 void saa_free(struct SAA *s)
66 {
67 char **p;
68 size_t n;
69
70 for (p = s->blk_ptrs, n = s->nblks; n; p++, n--)
71 nasm_free(*p);
72
73 nasm_free(s->blk_ptrs);
74 nasm_free(s);
75 }
76
77 /* Add one allocation block to an SAA */
saa_extend(struct SAA * s)78 static void saa_extend(struct SAA *s)
79 {
80 size_t blkn = s->nblks++;
81
82 if (blkn >= s->nblkptrs) {
83 size_t rindex = s->rblk - s->blk_ptrs;
84 size_t windex = s->wblk - s->blk_ptrs;
85
86 s->nblkptrs <<= 1;
87 s->blk_ptrs =
88 nasm_realloc(s->blk_ptrs, s->nblkptrs * sizeof(char *));
89
90 s->rblk = s->blk_ptrs + rindex;
91 s->wblk = s->blk_ptrs + windex;
92 }
93
94 s->blk_ptrs[blkn] = nasm_malloc(s->blk_len);
95 s->length += s->blk_len;
96 }
97
saa_wstruct(struct SAA * s)98 void *saa_wstruct(struct SAA *s)
99 {
100 void *p;
101
102 nasm_assert((s->wpos % s->elem_len) == 0);
103
104 if (s->wpos + s->elem_len > s->blk_len) {
105 nasm_assert(s->wpos == s->blk_len);
106 if (s->wptr + s->elem_len > s->length)
107 saa_extend(s);
108 s->wblk++;
109 s->wpos = 0;
110 }
111
112 p = *s->wblk + s->wpos;
113 s->wpos += s->elem_len;
114 s->wptr += s->elem_len;
115
116 if (s->wptr > s->datalen)
117 s->datalen = s->wptr;
118
119 return p;
120 }
121
saa_wbytes(struct SAA * s,const void * data,size_t len)122 void saa_wbytes(struct SAA *s, const void *data, size_t len)
123 {
124 const char *d = data;
125
126 while (len) {
127 size_t l = s->blk_len - s->wpos;
128 if (l > len)
129 l = len;
130 if (l) {
131 if (d) {
132 memcpy(*s->wblk + s->wpos, d, l);
133 d += l;
134 } else
135 memset(*s->wblk + s->wpos, 0, l);
136 s->wpos += l;
137 s->wptr += l;
138 len -= l;
139
140 if (s->datalen < s->wptr)
141 s->datalen = s->wptr;
142 }
143 if (len) {
144 if (s->wptr >= s->length)
145 saa_extend(s);
146 s->wblk++;
147 s->wpos = 0;
148 }
149 }
150 }
151
152 /*
153 * Writes a string, *including* the final null, to the specified SAA,
154 * and return the number of bytes written.
155 */
saa_wcstring(struct SAA * s,const char * str)156 size_t saa_wcstring(struct SAA *s, const char *str)
157 {
158 size_t bytes = strlen(str) + 1;
159
160 saa_wbytes(s, str, bytes);
161
162 return bytes;
163 }
164
saa_rewind(struct SAA * s)165 void saa_rewind(struct SAA *s)
166 {
167 s->rblk = s->blk_ptrs;
168 s->rpos = s->rptr = 0;
169 }
170
saa_rstruct(struct SAA * s)171 void *saa_rstruct(struct SAA *s)
172 {
173 void *p;
174
175 if (s->rptr + s->elem_len > s->datalen)
176 return NULL;
177
178 nasm_assert((s->rpos % s->elem_len) == 0);
179
180 if (s->rpos + s->elem_len > s->blk_len) {
181 s->rblk++;
182 s->rpos = 0;
183 }
184
185 p = *s->rblk + s->rpos;
186 s->rpos += s->elem_len;
187 s->rptr += s->elem_len;
188
189 return p;
190 }
191
saa_rbytes(struct SAA * s,size_t * lenp)192 const void *saa_rbytes(struct SAA *s, size_t * lenp)
193 {
194 const void *p;
195 size_t len;
196
197 if (s->rptr >= s->datalen) {
198 *lenp = 0;
199 return NULL;
200 }
201
202 if (s->rpos >= s->blk_len) {
203 s->rblk++;
204 s->rpos = 0;
205 }
206
207 len = *lenp;
208 if (len > s->datalen - s->rptr)
209 len = s->datalen - s->rptr;
210 if (len > s->blk_len - s->rpos)
211 len = s->blk_len - s->rpos;
212
213 *lenp = len;
214 p = *s->rblk + s->rpos;
215
216 s->rpos += len;
217 s->rptr += len;
218
219 return p;
220 }
221
saa_rnbytes(struct SAA * s,void * data,size_t len)222 void saa_rnbytes(struct SAA *s, void *data, size_t len)
223 {
224 char *d = data;
225
226 nasm_assert(s->rptr + len <= s->datalen);
227
228 while (len) {
229 size_t l;
230 const void *p;
231
232 l = len;
233 p = saa_rbytes(s, &l);
234
235 memcpy(d, p, l);
236 d += l;
237 len -= l;
238 }
239 }
240
241 /* Same as saa_rnbytes, except position the counter first */
saa_fread(struct SAA * s,size_t posn,void * data,size_t len)242 void saa_fread(struct SAA *s, size_t posn, void *data, size_t len)
243 {
244 size_t ix;
245
246 nasm_assert(posn + len <= s->datalen);
247
248 if (likely(s->blk_len == SAA_BLKLEN)) {
249 ix = posn >> SAA_BLKSHIFT;
250 s->rpos = posn & (SAA_BLKLEN - 1);
251 } else {
252 ix = posn / s->blk_len;
253 s->rpos = posn % s->blk_len;
254 }
255 s->rptr = posn;
256 s->rblk = &s->blk_ptrs[ix];
257
258 saa_rnbytes(s, data, len);
259 }
260
261 /* Same as saa_wbytes, except position the counter first */
saa_fwrite(struct SAA * s,size_t posn,const void * data,size_t len)262 void saa_fwrite(struct SAA *s, size_t posn, const void *data, size_t len)
263 {
264 size_t ix;
265 size_t padding = 0;
266
267 if (posn > s->datalen) {
268 padding = posn - s->datalen;
269 posn = s->datalen;
270 }
271
272 if (likely(s->blk_len == SAA_BLKLEN)) {
273 ix = posn >> SAA_BLKSHIFT;
274 s->wpos = posn & (SAA_BLKLEN - 1);
275 } else {
276 ix = posn / s->blk_len;
277 s->wpos = posn % s->blk_len;
278 }
279 s->wptr = posn;
280 s->wblk = &s->blk_ptrs[ix];
281
282 if (!s->wpos) {
283 s->wpos = s->blk_len;
284 s->wblk--;
285 }
286
287 if (padding)
288 saa_wbytes(s, NULL, padding);
289
290 saa_wbytes(s, data, len);
291 }
292
saa_fpwrite(struct SAA * s,FILE * fp)293 void saa_fpwrite(struct SAA *s, FILE * fp)
294 {
295 const char *data;
296 size_t len;
297
298 saa_rewind(s);
299 while (len = s->datalen, (data = saa_rbytes(s, &len)) != NULL)
300 nasm_write(data, len, fp);
301 }
302
saa_write8(struct SAA * s,uint8_t v)303 void saa_write8(struct SAA *s, uint8_t v)
304 {
305 saa_wbytes(s, &v, 1);
306 }
307
saa_write16(struct SAA * s,uint16_t v)308 void saa_write16(struct SAA *s, uint16_t v)
309 {
310 v = cpu_to_le16(v);
311 saa_wbytes(s, &v, 2);
312 }
313
saa_write32(struct SAA * s,uint32_t v)314 void saa_write32(struct SAA *s, uint32_t v)
315 {
316 v = cpu_to_le32(v);
317 saa_wbytes(s, &v, 4);
318 }
319
saa_write64(struct SAA * s,uint64_t v)320 void saa_write64(struct SAA *s, uint64_t v)
321 {
322 v = cpu_to_le64(v);
323 saa_wbytes(s, &v, 8);
324 }
325
saa_writeaddr(struct SAA * s,uint64_t v,size_t len)326 void saa_writeaddr(struct SAA *s, uint64_t v, size_t len)
327 {
328 v = cpu_to_le64(v);
329 saa_wbytes(s, &v, len);
330 }
331
332 /* write unsigned LEB128 value to SAA */
saa_wleb128u(struct SAA * psaa,int value)333 void saa_wleb128u(struct SAA *psaa, int value)
334 {
335 char temp[64], *ptemp;
336 uint8_t byte;
337 int len;
338
339 ptemp = temp;
340 len = 0;
341 do {
342 byte = value & 127;
343 value >>= 7;
344 if (value != 0) /* more bytes to come */
345 byte |= 0x80;
346 *ptemp = byte;
347 ptemp++;
348 len++;
349 } while (value != 0);
350 saa_wbytes(psaa, temp, len);
351 }
352
353 /* write signed LEB128 value to SAA */
saa_wleb128s(struct SAA * psaa,int value)354 void saa_wleb128s(struct SAA *psaa, int value)
355 {
356 char temp[64], *ptemp;
357 uint8_t byte;
358 bool more, negative;
359 int size, len;
360
361 ptemp = temp;
362 more = 1;
363 negative = (value < 0);
364 size = sizeof(int) * 8;
365 len = 0;
366 while (more) {
367 byte = value & 0x7f;
368 value >>= 7;
369 if (negative)
370 /* sign extend */
371 value |= -(1 << (size - 7));
372 /* sign bit of byte is second high order bit (0x40) */
373 if ((value == 0 && !(byte & 0x40)) ||
374 ((value == -1) && (byte & 0x40)))
375 more = 0;
376 else
377 byte |= 0x80;
378 *ptemp = byte;
379 ptemp++;
380 len++;
381 }
382 saa_wbytes(psaa, temp, len);
383 }
384