]> granicus.if.org Git - yasm/commitdiff
Add support for LEB128 encoded integers (both signed and unsigned). This
authorPeter Johnson <peter@tortall.net>
Mon, 17 Oct 2005 07:43:16 +0000 (07:43 -0000)
committerPeter Johnson <peter@tortall.net>
Mon, 17 Oct 2005 07:43:16 +0000 (07:43 -0000)
is needed for the GAS .uleb128 and .sleb128 directives.

* intnum.c (yasm_intnum_sign): New signedness discovery function.
* intnum.h (yasm_intnum_sign): Prototype.

* intnum.c (yasm_intnum_get_leb128, yasm_intnum_size_leb128): New.
* intnum.h (yasm_intnum_get_leb128, yasm_intnum_size_leb128): Prototype.
* leb128_test.c: New test for intnum-level LEB128 functions.

* bytecode.c (bytecode_leb128): New bytecode and supporting functions.
(yasm_bc_create_leb128): New creation function.
* bytecode.h (yasm_bc_create_leb128): Prototype.

* gas-token.re: Recognize .uleb128 and .sleb128.
* gas-bison.y: Ditto.
(gas_define_leb128): New.
* leb128.asm: New test for GAS .uleb128 and .sleb128 directives.

svn path=/trunk/yasm/; revision=1287

12 files changed:
libyasm/bytecode.c
libyasm/bytecode.h
libyasm/intnum.c
libyasm/intnum.h
libyasm/tests/Makefile.inc
libyasm/tests/leb128_test.c [new file with mode: 0644]
modules/parsers/gas/gas-bison.y
modules/parsers/gas/gas-token.re
modules/parsers/gas/tests/Makefile.inc
modules/parsers/gas/tests/leb128.asm [new file with mode: 0644]
modules/parsers/gas/tests/leb128.errwarn [new file with mode: 0644]
modules/parsers/gas/tests/leb128.hex [new file with mode: 0644]

index d1ea9f1552f381883babd44f740576b3a05f14a1..e86b9c777ed8e52de06a9de3cb7a03362c6b46dd 100644 (file)
@@ -65,6 +65,17 @@ typedef struct bytecode_data {
     unsigned char size;
 } bytecode_data;
 
+typedef struct bytecode_leb128 {
+    /* source data (linked list) */
+    yasm_datavalhead datahead;
+
+    /* signedness (0=unsigned, 1=signed) */
+    int sign;
+
+    /* total length (calculated at finalize time) */
+    unsigned long len;
+} bytecode_leb128;
+
 typedef struct bytecode_reserve {
     /*@only@*/ yasm_expr *numitems; /* number of items to reserve */
     unsigned char itemsize;        /* size of each item (in bytes) */
@@ -123,6 +134,15 @@ static int bc_data_tobytes(yasm_bytecode *bc, unsigned char **bufp, void *d,
                           yasm_output_expr_func output_expr,
                           /*@null@*/ yasm_output_reloc_func output_reloc);
 
+static void bc_leb128_destroy(void *contents);
+static void bc_leb128_print(const void *contents, FILE *f, int indent_level);
+static void bc_leb128_finalize(yasm_bytecode *bc, yasm_bytecode *prev_bc);
+static yasm_bc_resolve_flags bc_leb128_resolve
+    (yasm_bytecode *bc, int save, yasm_calc_bc_dist_func calc_bc_dist);
+static int bc_leb128_tobytes(yasm_bytecode *bc, unsigned char **bufp, void *d,
+                            yasm_output_expr_func output_expr,
+                            /*@null@*/ yasm_output_reloc_func output_reloc);
+
 static void bc_reserve_destroy(void *contents);
 static void bc_reserve_print(const void *contents, FILE *f, int indent_level);
 static yasm_bc_resolve_flags bc_reserve_resolve
@@ -175,6 +195,14 @@ static const yasm_bytecode_callback bc_data_callback = {
     bc_data_tobytes
 };
 
+static const yasm_bytecode_callback bc_leb128_callback = {
+    bc_leb128_destroy,
+    bc_leb128_print,
+    bc_leb128_finalize,
+    bc_leb128_resolve,
+    bc_leb128_tobytes
+};
+
 static const yasm_bytecode_callback bc_reserve_callback = {
     bc_reserve_destroy,
     bc_reserve_print,
@@ -462,6 +490,112 @@ yasm_bc_create_data(yasm_datavalhead *datahead, unsigned int size,
     return yasm_bc_create_common(&bc_data_callback, data, line);
 }
 
+static void
+bc_leb128_destroy(void *contents)
+{
+    bytecode_leb128 *bc_leb128 = (bytecode_leb128 *)contents;
+    yasm_dvs_destroy(&bc_leb128->datahead);
+    yasm_xfree(contents);
+}
+
+static void
+bc_leb128_print(const void *contents, FILE *f, int indent_level)
+{
+    const bytecode_leb128 *bc_leb128 = (const bytecode_leb128 *)contents;
+    fprintf(f, "%*s_Data_\n", indent_level, "");
+    fprintf(f, "%*sSign=%u\n", indent_level+1, "",
+           (unsigned int)bc_leb128->sign);
+    fprintf(f, "%*sElements:\n", indent_level+1, "");
+    yasm_dvs_print(&bc_leb128->datahead, f, indent_level+2);
+}
+
+static void
+bc_leb128_finalize(yasm_bytecode *bc, yasm_bytecode *prev_bc)
+{
+    bytecode_leb128 *bc_leb128 = (bytecode_leb128 *)bc->contents;
+    yasm_dataval *dv;
+    /*@dependent@*/ /*@null@*/ yasm_intnum *intn;
+
+    /* Only constant expressions are allowed.
+     * Because of this, go ahead and calculate length.
+     */
+    bc_leb128->len = 0;
+    STAILQ_FOREACH(dv, &bc_leb128->datahead, link) {
+       switch (dv->type) {
+           case DV_EMPTY:
+               break;
+           case DV_EXPR:
+               intn = yasm_expr_get_intnum(&dv->data.expn, NULL);
+               if (!intn) {
+                   yasm__error(bc->line,
+                               N_("LEB128 requires constant values"));
+                   return;
+               }
+               /* Warn for negative values in unsigned environment.
+                * This could be an error instead: the likelihood this is
+                * desired is very low!
+                */
+               if (yasm_intnum_sign(intn) == -1 && !bc_leb128->sign)
+                   yasm__warning(YASM_WARN_GENERAL, bc->line,
+                                 N_("negative value in unsigned LEB128"));
+               bc_leb128->len +=
+                   yasm_intnum_size_leb128(intn, bc_leb128->sign);
+               break;
+           case DV_STRING:
+               yasm__error(bc->line,
+                           N_("LEB128 does not allow string constants"));
+               return;
+       }
+    }
+}
+
+static yasm_bc_resolve_flags
+bc_leb128_resolve(yasm_bytecode *bc, int save,
+                 yasm_calc_bc_dist_func calc_bc_dist)
+{
+    bytecode_leb128 *bc_leb128 = (bytecode_leb128 *)bc->contents;
+    bc->len += bc_leb128->len;
+    return YASM_BC_RESOLVE_MIN_LEN;
+}
+
+static int
+bc_leb128_tobytes(yasm_bytecode *bc, unsigned char **bufp, void *d,
+                 yasm_output_expr_func output_expr,
+                 /*@unused@*/ yasm_output_reloc_func output_reloc)
+{
+    bytecode_leb128 *bc_leb128 = (bytecode_leb128 *)bc->contents;
+    yasm_dataval *dv;
+    /*@dependent@*/ /*@null@*/ yasm_intnum *intn;
+
+    STAILQ_FOREACH(dv, &bc_leb128->datahead, link) {
+       switch (dv->type) {
+           case DV_EMPTY:
+               break;
+           case DV_EXPR:
+               intn = yasm_expr_get_intnum(&dv->data.expn, NULL);
+               if (!intn)
+                   yasm_internal_error(N_("non-constant in leb128_tobytes"));
+               *bufp += yasm_intnum_get_leb128(intn, *bufp, bc_leb128->sign);
+               break;
+           case DV_STRING:
+               yasm_internal_error(N_("string in leb128_tobytes"));
+       }
+    }
+
+    return 0;
+}
+
+yasm_bytecode *
+yasm_bc_create_leb128(yasm_datavalhead *datahead, int sign, unsigned long line)
+{
+    bytecode_leb128 *leb128 = yasm_xmalloc(sizeof(bytecode_leb128));
+
+    leb128->datahead = *datahead;
+    leb128->sign = sign;
+
+    return yasm_bc_create_common(&bc_leb128_callback, leb128, line);
+}
+
 static void
 bc_reserve_destroy(void *contents)
 {
index c3b478bb7b0480fec76dc9bf716eb4d59dc71535..d5cd85523ed640c692cc1a627aa4f24da50160cb 100644 (file)
@@ -141,6 +141,15 @@ void yasm_bc_set_multiple(yasm_bytecode *bc, /*@keep@*/ yasm_expr *e);
 /*@only@*/ yasm_bytecode *yasm_bc_create_data
     (yasm_datavalhead *datahead, unsigned int size, unsigned long line);
 
+/** Create a bytecode containing LEB128-encoded data value(s).
+ * \param datahead     list of data values (kept, do not free)
+ * \param sign         signedness (1=signed, 0=unsigned) of each data value
+ * \param line         virtual line (from yasm_linemap)
+ * \return Newly allocated bytecode.
+ */
+/*@only@*/ yasm_bytecode *yasm_bc_create_leb128
+    (yasm_datavalhead *datahead, int sign, unsigned long line);
+
 /** Create a bytecode reserving space.
  * \param numitems     number of reserve "items" (kept, do not free)
  * \param itemsize     reserved size (in bytes) for each item
index 4c5c94e35e1e29f84186e1822392fe9a5b5bcf34..00e9ba1f6ce297d94676cfa3703310c0f2d15a03 100644 (file)
@@ -477,6 +477,18 @@ yasm_intnum_is_neg1(yasm_intnum *intn)
     return (intn->type == INTNUM_BV && BitVector_is_full(intn->val.bv));
 }
 
+int
+yasm_intnum_sign(yasm_intnum *intn)
+{
+    if (intn->type == INTNUM_UL) {
+       if (intn->val.ul == 0)
+           return 0;
+       else
+           return 1;
+    } else
+       return BitVector_Sign(intn->val.bv);
+}
+
 unsigned long
 yasm_intnum_get_uint(const yasm_intnum *intn)
 {
@@ -638,6 +650,86 @@ yasm_intnum_check_size(const yasm_intnum *intn, size_t size, size_t rshift,
     return (Set_Max(val) < (long)size);
 }
 
+unsigned long
+yasm_intnum_get_leb128(const yasm_intnum *intn, unsigned char *ptr, int sign)
+{
+    wordptr val = op1static;
+    unsigned long i, size;
+    unsigned char *ptr_orig = ptr;
+
+    /* Shortcut 0 */
+    if (intn->type == INTNUM_UL && intn->val.ul == 0) {
+       *ptr = 0;
+       return 1;
+    }
+
+    /* If not already a bitvect, convert value to be written to a bitvect */
+    if (intn->type == INTNUM_BV)
+       val = intn->val.bv;
+    else {
+       BitVector_Empty(val);
+       BitVector_Chunk_Store(val, 32, 0, intn->val.ul);
+    }
+
+    if (sign) {
+       /* Signed mode */
+       if (BitVector_msb_(val)) {
+           /* Negative */
+           BitVector_Negate(conv_bv, val);
+           size = Set_Max(conv_bv)+2;
+       } else {
+           /* Positive */
+           size = Set_Max(val)+2;
+       }
+    } else {
+       /* Unsigned mode */
+       size = Set_Max(val)+1;
+    }
+
+    /* Positive/Unsigned write */
+    for (i=0; i<size; i += 7) {
+       *ptr = (unsigned char)BitVector_Chunk_Read(val, 7, i);
+       *ptr |= 0x80;
+       ptr++;
+    }
+    *(ptr-1) &= 0x7F;  /* Clear MSB of last byte */
+    return (unsigned long)(ptr-ptr_orig);
+}
+
+unsigned long
+yasm_intnum_size_leb128(const yasm_intnum *intn, int sign)
+{
+    wordptr val = op1static;
+
+    /* Shortcut 0 */
+    if (intn->type == INTNUM_UL && intn->val.ul == 0) {
+       return 1;
+    }
+
+    /* If not already a bitvect, convert value to a bitvect */
+    if (intn->type == INTNUM_BV)
+       val = intn->val.bv;
+    else {
+       BitVector_Empty(val);
+       BitVector_Chunk_Store(val, 32, 0, intn->val.ul);
+    }
+
+    if (sign) {
+       /* Signed mode */
+       if (BitVector_msb_(val)) {
+           /* Negative */
+           BitVector_Negate(conv_bv, val);
+           return (Set_Max(conv_bv)+8)/7;
+       } else {
+           /* Positive */
+           return (Set_Max(val)+8)/7;
+       }
+    } else {
+       /* Unsigned mode */
+       return (Set_Max(val)+7)/7;
+    }
+}
+
 void
 yasm_intnum_print(const yasm_intnum *intn, FILE *f)
 {
index 0929af74c910007a3ca30b9aa71de09b049c68b5..779fd04919b69ecc0f4ae25c543b8d2bc275e456 100644 (file)
@@ -135,6 +135,12 @@ int yasm_intnum_is_pos1(yasm_intnum *acc);
  */
 int yasm_intnum_is_neg1(yasm_intnum *acc);
 
+/** Simple sign check.
+ * \param acc      intnum
+ * \return -1 if negative, 0 if zero, +1 if positive
+ */
+int yasm_intnum_sign(yasm_intnum *acc);
+
 /** Convert an intnum to an unsigned 32-bit value.  The value is in "standard"
  * C format (eg, of unknown endian).
  * \note Parameter intnum is truncated to fit into 32 bits.  Use
@@ -186,6 +192,22 @@ void yasm_intnum_get_sized(const yasm_intnum *intn, unsigned char *ptr,
 int yasm_intnum_check_size(const yasm_intnum *intn, size_t size,
                           size_t rshift, int rangetype);
 
+/** Output #yasm_intnum to buffer in LEB128-encoded form.
+ * \param intn     intnum
+ * \param ptr      pointer to storage for output bytes
+ * \param sign     signedness of LEB128 encoding (0=unsigned, 1=signed)
+ * \return Number of bytes generated.
+ */
+unsigned long yasm_intnum_get_leb128(const yasm_intnum *intn,
+                                    unsigned char *ptr, int sign);
+
+/** Calculate number of bytes LEB128-encoded form of #yasm_intnum will take.
+ * \param intn     intnum
+ * \param sign     signedness of LEB128 encoding (0=unsigned, 1=signed)
+ * \return Number of bytes.
+ */
+unsigned long yasm_intnum_size_leb128(const yasm_intnum *intn, int sign);
+
 /** Print an intnum.  For debugging purposes.
  * \param f    file
  * \param intn intnum
index ccf4f737e734607b572132192e711bfff81120ce..634bbbb5d70e39a3595b13802897902407c7a751 100644 (file)
@@ -2,6 +2,7 @@
 
 TESTS += bitvect_test
 TESTS += floatnum_test
+TESTS += leb128_test
 TESTS += libyasm/tests/libyasm_test.sh
 
 EXTRA_DIST += libyasm/tests/libyasm_test.sh
@@ -19,6 +20,7 @@ EXTRA_DIST += libyasm/tests/unary.hex
 
 check_PROGRAMS += bitvect_test
 check_PROGRAMS += floatnum_test
+check_PROGRAMS += leb128_test
 
 bitvect_test_SOURCES  = libyasm/tests/bitvect_test.c
 bitvect_test_LDADD = libyasm.a $(INTLLIBS)
@@ -26,3 +28,6 @@ bitvect_test_LDADD = libyasm.a $(INTLLIBS)
 floatnum_test_SOURCES  = libyasm/tests/floatnum_test.c
 floatnum_test_LDADD = libyasm.a $(INTLLIBS)
 
+leb128_test_SOURCES  = libyasm/tests/leb128_test.c
+leb128_test_LDADD = libyasm.a $(INTLLIBS)
+
diff --git a/libyasm/tests/leb128_test.c b/libyasm/tests/leb128_test.c
new file mode 100644 (file)
index 0000000..f8ab346
--- /dev/null
@@ -0,0 +1,159 @@
+/* $Id$
+ *
+ *  Copyright (C) 2005  Peter Johnson
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. 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 AUTHOR AND OTHER 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 AUTHOR OR OTHER 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.
+ */
+#ifdef HAVE_CONFIG_H
+# include <config.h>
+#endif
+
+#ifdef STDC_HEADERS
+# include <stdlib.h>
+# include <string.h>
+#endif
+
+#include <stdio.h>
+
+#include "libyasm/intnum.c"
+
+typedef struct Test_Entry {
+    /* signedness (0=unsigned, 1=signed) */
+    int sign;
+
+    /* whether input value should be negated */
+    int negate;
+
+    /* input value (as hex string) */
+    const char *input;
+
+    /* correct size returned from both size_leb128 and get_leb128 */
+    unsigned long outsize;
+
+    /* correct return data from get_leb128 */
+    const unsigned char *result;
+} Test_Entry;
+
+static Test_Entry tests[] = {
+    /* Unsigned values */
+    {0, 0, "0", 1, (const unsigned char *)"\x00"},
+    {0, 0, "2", 1, (const unsigned char *)"\x02"},
+    {0, 0, "7F", 1, (const unsigned char *)"\x7F"},
+    {0, 0, "80", 2, (const unsigned char *)"\x80\x01"},
+    {0, 0, "81", 2, (const unsigned char *)"\x81\x01"},
+    {0, 0, "82", 2, (const unsigned char *)"\x82\x01"},
+    {0, 0, "3239", 2, (const unsigned char *)"\xB9\x64"},
+    /* Signed zero value */
+    {1, 0, "0", 1, (const unsigned char *)"\x00"},
+    /* Signed positive values */
+    {1, 0, "2", 1, (const unsigned char *)"\x02"},
+    {1, 0, "7F", 2, (const unsigned char *)"\xFF\x00"},
+    {1, 0, "80", 2, (const unsigned char *)"\x80\x01"},
+    {1, 0, "81", 2, (const unsigned char *)"\x81\x01"},
+    /* Signed negative values */
+    {1, 1, "2", 1, (const unsigned char *)"\x7E"},
+    {1, 1, "7F", 2, (const unsigned char *)"\x81\x7F"},
+    {1, 1, "80", 2, (const unsigned char *)"\x80\x7F"},
+    {1, 1, "81", 2, (const unsigned char *)"\xFF\x7E"},
+};
+
+static char failed[1000];
+static char failmsg[100];
+
+static int
+run_test(Test_Entry *test)
+{
+    char *valstr = yasm__xstrdup(test->input);
+    yasm_intnum *intn = yasm_intnum_create_hex(valstr, 0);
+    unsigned long size, i;
+    unsigned char out[100];
+    int bad;
+
+    yasm_xfree(valstr);
+
+    if (test->negate)
+       yasm_intnum_calc(intn, YASM_EXPR_NEG, NULL, 0);
+
+    size = yasm_intnum_size_leb128(intn, test->sign);
+    if (size != test->outsize) {
+       yasm_intnum_destroy(intn);
+       sprintf(failmsg, "%ssigned %s%s size() bad size: expected %lu, got %lu!",
+               test->sign?"":"un", test->negate?"-":"", test->input,
+               test->outsize, size);
+       return 1;
+    }
+
+    for (i=0; i<sizeof(out); i++)
+       out[i] = 0xFF;
+    size = yasm_intnum_get_leb128(intn, out, test->sign);
+    if (size != test->outsize) {
+       yasm_intnum_destroy(intn);
+       sprintf(failmsg, "%ssigned %s%s get() bad size: expected %lu, got %lu!",
+               test->sign?"":"un", test->negate?"-":"", test->input,
+               test->outsize, size);
+       return 1;
+    }
+
+    bad = 0;
+    for (i=0; i<test->outsize && !bad; i++) {
+       if (out[i] != test->result[i])
+           bad = 1;
+    }
+    if (bad) {
+       yasm_intnum_destroy(intn);
+       sprintf(failmsg, "%ssigned %s%s get() bad output!",
+               test->sign?"":"un", test->negate?"-":"", test->input);
+       return 1;
+    }
+
+    yasm_intnum_destroy(intn);
+    return 0;
+}
+
+int
+main(void)
+{
+    int nf = 0;
+    int numtests = sizeof(tests)/sizeof(Test_Entry);
+    int i;
+
+    if (BitVector_Boot() != ErrCode_Ok)
+       return EXIT_FAILURE;
+    yasm_intnum_initialize();
+
+    failed[0] = '\0';
+    printf("Test leb128_test: ");
+    for (i=0; i<numtests; i++) {
+       int fail = run_test(&tests[i]);
+       printf("%c", fail>0 ? 'F':'.');
+       fflush(stdout);
+       if (fail)
+           sprintf(failed, "%s ** F: %s\n", failed, failmsg);
+       nf += fail;
+    }
+
+    yasm_intnum_cleanup();
+
+    printf(" +%d-%d/%d %d%%\n%s",
+          numtests-nf, nf, numtests, 100*(numtests-nf)/numtests, failed);
+    return (nf == 0) ? EXIT_SUCCESS : EXIT_FAILURE;
+}
index 794329a388cc3e7b554d6b3096f79c1d57e6cd45..af6a8dd18367f39ca2077f011b4674a928b89a74 100644 (file)
@@ -56,6 +56,9 @@ static yasm_bytecode *gas_define_strings(yasm_parser_gas *parser_gas,
 static yasm_bytecode *gas_define_data(yasm_parser_gas *parser_gas,
                                      yasm_valparamhead *vps,
                                      unsigned int size);
+static yasm_bytecode *gas_define_leb128(yasm_parser_gas *parser_gas,
+                                       yasm_valparamhead *vps,
+                                       int sign);
 static void gas_parser_directive
     (yasm_parser_gas *parser_gas, const char *name,
      yasm_valparamhead *valparams,
@@ -104,8 +107,9 @@ static void gas_parser_directive
 %token DIR_BSS DIR_BYTE DIR_COMM DIR_DATA DIR_DOUBLE DIR_ENDR DIR_EXTERN
 %token DIR_EQU DIR_FILE DIR_FLOAT DIR_GLOBAL DIR_IDENT DIR_INT DIR_LOC
 %token DIR_LCOMM DIR_OCTA DIR_ORG DIR_P2ALIGN DIR_REPT DIR_SECTION
-%token DIR_SHORT DIR_SIZE DIR_SKIP DIR_STRING
-%token DIR_TEXT DIR_TFLOAT DIR_TYPE DIR_QUAD DIR_WEAK DIR_WORD DIR_ZERO
+%token DIR_SHORT DIR_SIZE DIR_SKIP DIR_SLEB128 DIR_STRING
+%token DIR_TEXT DIR_TFLOAT DIR_TYPE DIR_QUAD DIR_ULEB128 DIR_WEAK DIR_WORD
+%token DIR_ZERO
 
 %type <bc> line lineexp instr
 
@@ -295,6 +299,14 @@ lineexp: instr
 
        yasm_bc_set_multiple($$, $2);
     }
+    | DIR_SLEB128 datavals {
+       $$ = gas_define_leb128(parser_gas, &$2, 1);
+       yasm_vps_delete(&$2);
+    }
+    | DIR_ULEB128 datavals {
+       $$ = gas_define_leb128(parser_gas, &$2, 0);
+       yasm_vps_delete(&$2);
+    }
     /* Floating point data definition directives */
     | DIR_FLOAT datavals {
        $$ = gas_define_data(parser_gas, &$2, 4);
@@ -812,6 +824,27 @@ gas_define_data(yasm_parser_gas *parser_gas, yasm_valparamhead *vps,
        return NULL;
 }
 
+static yasm_bytecode *
+gas_define_leb128(yasm_parser_gas *parser_gas, yasm_valparamhead *vps,
+                 int sign)
+{
+    if (yasm_vps_first(vps)) {
+       yasm_datavalhead dvs;
+       yasm_valparam *cur;
+
+       yasm_dvs_initialize(&dvs);
+       yasm_vps_foreach(cur, vps) {
+           if (!cur->param)
+               yasm__error(cur_line, N_("missing data value"));
+           else
+               yasm_dvs_append(&dvs, yasm_dv_create_expr(cur->param));
+           cur->param = NULL;
+       }
+       return yasm_bc_create_leb128(&dvs, sign, cur_line);
+    } else
+       return NULL;
+}
+
 static void
 gas_parser_directive(yasm_parser_gas *parser_gas, const char *name,
                      yasm_valparamhead *valparams,
index 48c489a17689c2e6d0b604790957f3cda50a5139..61edb0ed5caa6852a55a3478ed44cc945020dc91 100644 (file)
@@ -291,12 +291,14 @@ scan:
        '.single'       { RETURN(DIR_FLOAT); }
        '.size'         { RETURN(DIR_SIZE); }
        '.skip'         { RETURN(DIR_SKIP); }
+       '.sleb128'      { RETURN(DIR_SLEB128); }
        '.space'        { RETURN(DIR_SKIP); }
        '.string'       { RETURN(DIR_ASCIZ); }
        '.text'         { RETURN(DIR_TEXT); }
        '.tfloat'       { RETURN(DIR_TFLOAT); }
        '.type'         { RETURN(DIR_TYPE); }
        '.quad'         { RETURN(DIR_QUAD); }
+       '.uleb128'      { RETURN(DIR_ULEB128); }
        '.weak'         { RETURN(DIR_WEAK); }
        '.word'         { RETURN(DIR_WORD); }
        '.zero'         { RETURN(DIR_ZERO); }
index ac73742c852dc613b80ed94d6230e1b341732ba7..30ca0c2b8a971647c332dad5ee78fc5a82a660f4 100644 (file)
@@ -15,6 +15,9 @@ EXTRA_DIST += modules/parsers/gas/tests/datavis2.hex
 EXTRA_DIST += modules/parsers/gas/tests/jmpcall.asm
 EXTRA_DIST += modules/parsers/gas/tests/jmpcall.errwarn
 EXTRA_DIST += modules/parsers/gas/tests/jmpcall.hex
+EXTRA_DIST += modules/parsers/gas/tests/leb128.asm
+EXTRA_DIST += modules/parsers/gas/tests/leb128.errwarn
+EXTRA_DIST += modules/parsers/gas/tests/leb128.hex
 EXTRA_DIST += modules/parsers/gas/tests/reggroup-err.asm
 EXTRA_DIST += modules/parsers/gas/tests/reggroup-err.errwarn
 EXTRA_DIST += modules/parsers/gas/tests/reggroup.asm
diff --git a/modules/parsers/gas/tests/leb128.asm b/modules/parsers/gas/tests/leb128.asm
new file mode 100644 (file)
index 0000000..3cead76
--- /dev/null
@@ -0,0 +1,18 @@
+.data
+.uleb128 0
+.uleb128 2
+.uleb128 127
+.uleb128 128
+.uleb128 129
+.uleb128 130
+.uleb128 12857
+
+.sleb128 0
+.sleb128 2
+.sleb128 -2
+.sleb128 127
+.sleb128 -127
+.sleb128 128
+.sleb128 -128
+.sleb128 129
+.sleb128 -129
diff --git a/modules/parsers/gas/tests/leb128.errwarn b/modules/parsers/gas/tests/leb128.errwarn
new file mode 100644 (file)
index 0000000..e69de29
diff --git a/modules/parsers/gas/tests/leb128.hex b/modules/parsers/gas/tests/leb128.hex
new file mode 100644 (file)
index 0000000..30e5b7e
--- /dev/null
@@ -0,0 +1,448 @@
+7f 
+45 
+4c 
+46 
+01 
+01 
+01 
+00 
+00 
+00 
+00 
+00 
+00 
+00 
+00 
+00 
+01 
+00 
+03 
+00 
+01 
+00 
+00 
+00 
+00 
+00 
+00 
+00 
+00 
+00 
+00 
+00 
+d0 
+00 
+00 
+00 
+00 
+00 
+00 
+00 
+34 
+00 
+00 
+00 
+00 
+00 
+28 
+00 
+06 
+00 
+01 
+00 
+00 
+00 
+00 
+00 
+00 
+00 
+00 
+00 
+00 
+00 
+00 
+00 
+00 
+02 
+7f 
+80 
+01 
+81 
+01 
+82 
+01 
+b9 
+64 
+00 
+02 
+7e 
+ff 
+00 
+81 
+7f 
+80 
+01 
+80 
+7f 
+81 
+01 
+ff 
+7e 
+00 
+00 
+00 
+2e 
+74 
+65 
+78 
+74 
+00 
+2e 
+64 
+61 
+74 
+61 
+00 
+2e 
+73 
+74 
+72 
+74 
+61 
+62 
+00 
+2e 
+73 
+79 
+6d 
+74 
+61 
+62 
+00 
+2e 
+73 
+68 
+73 
+74 
+72 
+74 
+61 
+62 
+00 
+00 
+00 
+2d 
+00 
+00 
+00 
+00 
+00 
+00 
+00 
+00 
+00 
+00 
+00 
+00 
+00 
+00 
+00 
+00 
+00 
+00 
+01 
+00 
+00 
+00 
+00 
+00 
+00 
+00 
+00 
+00 
+00 
+00 
+04 
+00 
+f1 
+ff 
+00 
+00 
+00 
+00 
+00 
+00 
+00 
+00 
+00 
+00 
+00 
+00 
+03 
+00 
+05 
+00 
+00 
+00 
+00 
+00 
+00 
+00 
+00 
+00 
+00 
+00 
+00 
+00 
+03 
+00 
+04 
+00 
+00 
+00 
+00 
+00 
+00 
+00 
+00 
+00 
+00 
+00 
+00 
+00 
+00 
+00 
+00 
+00 
+00 
+00 
+00 
+00 
+00 
+00 
+00 
+00 
+00 
+00 
+00 
+00 
+00 
+00 
+00 
+00 
+00 
+00 
+00 
+00 
+00 
+00 
+00 
+00 
+00 
+00 
+00 
+00 
+00 
+00 
+00 
+00 
+1d 
+00 
+00 
+00 
+03 
+00 
+00 
+00 
+00 
+00 
+00 
+00 
+00 
+00 
+00 
+00 
+5c 
+00 
+00 
+00 
+27 
+00 
+00 
+00 
+00 
+00 
+00 
+00 
+00 
+00 
+00 
+00 
+00 
+00 
+00 
+00 
+00 
+00 
+00 
+00 
+0d 
+00 
+00 
+00 
+03 
+00 
+00 
+00 
+00 
+00 
+00 
+00 
+00 
+00 
+00 
+00 
+84 
+00 
+00 
+00 
+03 
+00 
+00 
+00 
+00 
+00 
+00 
+00 
+00 
+00 
+00 
+00 
+00 
+00 
+00 
+00 
+00 
+00 
+00 
+00 
+15 
+00 
+00 
+00 
+02 
+00 
+00 
+00 
+00 
+00 
+00 
+00 
+00 
+00 
+00 
+00 
+88 
+00 
+00 
+00 
+40 
+00 
+00 
+00 
+02 
+00 
+00 
+00 
+04 
+00 
+00 
+00 
+04 
+00 
+00 
+00 
+10 
+00 
+00 
+00 
+01 
+00 
+00 
+00 
+01 
+00 
+00 
+00 
+06 
+00 
+00 
+00 
+00 
+00 
+00 
+00 
+40 
+00 
+00 
+00 
+00 
+00 
+00 
+00 
+00 
+00 
+00 
+00 
+00 
+00 
+00 
+00 
+10 
+00 
+00 
+00 
+00 
+00 
+00 
+00 
+07 
+00 
+00 
+00 
+01 
+00 
+00 
+00 
+00 
+00 
+00 
+00 
+00 
+00 
+00 
+00 
+40 
+00 
+00 
+00 
+1a 
+00 
+00 
+00 
+00 
+00 
+00 
+00 
+00 
+00 
+00 
+00 
+04 
+00 
+00 
+00 
+00 
+00 
+00 
+00