/* ----------------------------------------------------------------------- * * * Copyright 1996-2017 The NASM Authors - All Rights Reserved * See the file AUTHORS included with the NASM distribution for * the specific copyright holders. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following * conditions are met: * * * Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * * Redistributions in binary form must reproduce the above * copyright notice, this list of conditions and the following * disclaimer in the documentation and/or other materials provided * with the distribution. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND * CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. * * ----------------------------------------------------------------------- */ #include "compiler.h" #include "nasmlib.h" #include "saa.h" /* Aggregate SAA components smaller than this */ #define SAA_BLKSHIFT 16 #define SAA_BLKLEN ((size_t)1 << SAA_BLKSHIFT) struct SAA *saa_init(size_t elem_len) { struct SAA *s; char *data; s = nasm_zalloc(sizeof(struct SAA)); if (elem_len >= SAA_BLKLEN) s->blk_len = elem_len; else s->blk_len = SAA_BLKLEN - (SAA_BLKLEN % elem_len); s->elem_len = elem_len; s->length = s->blk_len; data = nasm_malloc(s->blk_len); s->nblkptrs = s->nblks = 1; s->blk_ptrs = nasm_malloc(sizeof(char *)); s->blk_ptrs[0] = data; s->wblk = s->rblk = &s->blk_ptrs[0]; return s; } void saa_free(struct SAA *s) { char **p; size_t n; for (p = s->blk_ptrs, n = s->nblks; n; p++, n--) nasm_free(*p); nasm_free(s->blk_ptrs); nasm_free(s); } /* Add one allocation block to an SAA */ static void saa_extend(struct SAA *s) { size_t blkn = s->nblks++; if (blkn >= s->nblkptrs) { size_t rindex = s->rblk - s->blk_ptrs; size_t windex = s->wblk - s->blk_ptrs; s->nblkptrs <<= 1; s->blk_ptrs = nasm_realloc(s->blk_ptrs, s->nblkptrs * sizeof(char *)); s->rblk = s->blk_ptrs + rindex; s->wblk = s->blk_ptrs + windex; } s->blk_ptrs[blkn] = nasm_malloc(s->blk_len); s->length += s->blk_len; } void *saa_wstruct(struct SAA *s) { void *p; nasm_assert((s->wpos % s->elem_len) == 0); if (s->wpos + s->elem_len > s->blk_len) { nasm_assert(s->wpos == s->blk_len); if (s->wptr + s->elem_len > s->length) saa_extend(s); s->wblk++; s->wpos = 0; } p = *s->wblk + s->wpos; s->wpos += s->elem_len; s->wptr += s->elem_len; if (s->wptr > s->datalen) s->datalen = s->wptr; return p; } void saa_wbytes(struct SAA *s, const void *data, size_t len) { const char *d = data; while (len) { size_t l = s->blk_len - s->wpos; if (l > len) l = len; if (l) { if (d) { memcpy(*s->wblk + s->wpos, d, l); d += l; } else memset(*s->wblk + s->wpos, 0, l); s->wpos += l; s->wptr += l; len -= l; if (s->datalen < s->wptr) s->datalen = s->wptr; } if (len) { if (s->wptr >= s->length) saa_extend(s); s->wblk++; s->wpos = 0; } } } /* * Writes a string, *including* the final null, to the specified SAA, * and return the number of bytes written. */ size_t saa_wcstring(struct SAA *s, const char *str) { size_t bytes = strlen(str) + 1; saa_wbytes(s, str, bytes); return bytes; } void saa_rewind(struct SAA *s) { s->rblk = s->blk_ptrs; s->rpos = s->rptr = 0; } void *saa_rstruct(struct SAA *s) { void *p; if (s->rptr + s->elem_len > s->datalen) return NULL; nasm_assert((s->rpos % s->elem_len) == 0); if (s->rpos + s->elem_len > s->blk_len) { s->rblk++; s->rpos = 0; } p = *s->rblk + s->rpos; s->rpos += s->elem_len; s->rptr += s->elem_len; return p; } const void *saa_rbytes(struct SAA *s, size_t * lenp) { const void *p; size_t len; if (s->rptr >= s->datalen) { *lenp = 0; return NULL; } if (s->rpos >= s->blk_len) { s->rblk++; s->rpos = 0; } len = *lenp; if (len > s->datalen - s->rptr) len = s->datalen - s->rptr; if (len > s->blk_len - s->rpos) len = s->blk_len - s->rpos; *lenp = len; p = *s->rblk + s->rpos; s->rpos += len; s->rptr += len; return p; } void saa_rnbytes(struct SAA *s, void *data, size_t len) { char *d = data; nasm_assert(s->rptr + len <= s->datalen); while (len) { size_t l; const void *p; l = len; p = saa_rbytes(s, &l); memcpy(d, p, l); d += l; len -= l; } } /* Same as saa_rnbytes, except position the counter first */ void saa_fread(struct SAA *s, size_t posn, void *data, size_t len) { size_t ix; nasm_assert(posn + len <= s->datalen); if (likely(s->blk_len == SAA_BLKLEN)) { ix = posn >> SAA_BLKSHIFT; s->rpos = posn & (SAA_BLKLEN - 1); } else { ix = posn / s->blk_len; s->rpos = posn % s->blk_len; } s->rptr = posn; s->rblk = &s->blk_ptrs[ix]; saa_rnbytes(s, data, len); } /* Same as saa_wbytes, except position the counter first */ void saa_fwrite(struct SAA *s, size_t posn, const void *data, size_t len) { size_t ix; /* Seek beyond the end of the existing array not supported */ nasm_assert(posn <= s->datalen); if (likely(s->blk_len == SAA_BLKLEN)) { ix = posn >> SAA_BLKSHIFT; s->wpos = posn & (SAA_BLKLEN - 1); } else { ix = posn / s->blk_len; s->wpos = posn % s->blk_len; } s->wptr = posn; s->wblk = &s->blk_ptrs[ix]; if (!s->wpos) { s->wpos = s->blk_len; s->wblk--; } saa_wbytes(s, data, len); } void saa_fpwrite(struct SAA *s, FILE * fp) { const char *data; size_t len; saa_rewind(s); while (len = s->datalen, (data = saa_rbytes(s, &len)) != NULL) nasm_write(data, len, fp); } void saa_write8(struct SAA *s, uint8_t v) { saa_wbytes(s, &v, 1); } #ifdef WORDS_LITTLEENDIAN void saa_write16(struct SAA *s, uint16_t v) { saa_wbytes(s, &v, 2); } void saa_write32(struct SAA *s, uint32_t v) { saa_wbytes(s, &v, 4); } void saa_write64(struct SAA *s, uint64_t v) { saa_wbytes(s, &v, 8); } void saa_writeaddr(struct SAA *s, uint64_t v, size_t len) { saa_wbytes(s, &v, len); } #else /* not WORDS_LITTLEENDIAN */ void saa_write16(struct SAA *s, uint16_t v) { uint8_t b[2]; b[0] = v; b[1] = v >> 8; saa_wbytes(s, b, 2); } void saa_write32(struct SAA *s, uint32_t v) { uint8_t b[4]; b[0] = v; b[1] = v >> 8; b[2] = v >> 16; b[3] = v >> 24; saa_wbytes(s, b, 4); } void saa_write64(struct SAA *s, uint64_t v) { uint8_t b[8]; b[0] = v; b[1] = v >> 8; b[2] = v >> 16; b[3] = v >> 24; b[4] = v >> 32; b[5] = v >> 40; b[6] = v >> 48; b[7] = v >> 56; saa_wbytes(s, b, 8); } void saa_writeaddr(struct SAA *s, uint64_t v, size_t len) { uint8_t b[8]; b[0] = v; b[1] = v >> 8; b[2] = v >> 16; b[3] = v >> 24; b[4] = v >> 32; b[5] = v >> 40; b[6] = v >> 48; b[7] = v >> 56; saa_wbytes(s, b, len); } #endif /* WORDS_LITTLEENDIAN */ /* write unsigned LEB128 value to SAA */ void saa_wleb128u(struct SAA *psaa, int value) { char temp[64], *ptemp; uint8_t byte; int len; ptemp = temp; len = 0; do { byte = value & 127; value >>= 7; if (value != 0) /* more bytes to come */ byte |= 0x80; *ptemp = byte; ptemp++; len++; } while (value != 0); saa_wbytes(psaa, temp, len); } /* write signed LEB128 value to SAA */ void saa_wleb128s(struct SAA *psaa, int value) { char temp[64], *ptemp; uint8_t byte; bool more, negative; int size, len; ptemp = temp; more = 1; negative = (value < 0); size = sizeof(int) * 8; len = 0; while (more) { byte = value & 0x7f; value >>= 7; if (negative) /* sign extend */ value |= -(1 << (size - 7)); /* sign bit of byte is second high order bit (0x40) */ if ((value == 0 && !(byte & 0x40)) || ((value == -1) && (byte & 0x40))) more = 0; else byte |= 0x80; *ptemp = byte; ptemp++; len++; } saa_wbytes(psaa, temp, len); }