blob: fe7741a4aaf017f0228dd350557bb394f1d463b8 [file] [log] [blame]
/* ----------------------------------------------------------------------- *
*
* 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);
}
void saa_write16(struct SAA *s, uint16_t v)
{
v = cpu_to_le16(v);
saa_wbytes(s, &v, 2);
}
void saa_write32(struct SAA *s, uint32_t v)
{
v = cpu_to_le32(v);
saa_wbytes(s, &v, 4);
}
void saa_write64(struct SAA *s, uint64_t v)
{
v = cpu_to_le64(v);
saa_wbytes(s, &v, 8);
}
void saa_writeaddr(struct SAA *s, uint64_t v, size_t len)
{
v = cpu_to_le64(v);
saa_wbytes(s, &v, len);
}
/* 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);
}