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