mirror of
https://github.com/netwide-assembler/nasm
synced 2026-08-26 16:23:04 -04:00
ndisasm: make the assembler (hopefully) work again
- Significantly overhauled the disassembler internals to make better use of the information already in the instruction template and to reduce the implementation differences with the assembler - Add APX support to the disassembler - Fix problem with disassembler truncating addresses of jumps - Fix generation of invalid EAs in 16-bit mode - Fix array overrun for types in a few modules - Fix invalid ND flag on near JMP Signed-off-by: H. Peter Anvin (Intel) <hpa@zytor.com>
This commit is contained in:
parent
3efdd3cf9a
commit
e05867ce3d
17 changed files with 1410 additions and 779 deletions
11
Makefile.in
11
Makefile.in
|
|
@ -179,8 +179,8 @@ LIBOBJ_NW = \
|
|||
\
|
||||
common/common.$(O) \
|
||||
\
|
||||
x86/insnsa.$(O) x86/insnsb.$(O) x86/insnsd.$(O) x86/insnsn.$(O) \
|
||||
x86/regs.$(O) x86/regvals.$(O) x86/regflags.$(O) x86/regdis.$(O) \
|
||||
x86/insnsa.$(O) x86/insnsb.$(O) x86/insnsn.$(O) \
|
||||
x86/regs.$(O) x86/regvals.$(O) x86/regflags.$(O) \
|
||||
x86/iflag.$(O) \
|
||||
\
|
||||
$(OUTPUTOBJ) \
|
||||
|
|
@ -188,7 +188,10 @@ LIBOBJ_NW = \
|
|||
$(WARNOBJ)
|
||||
|
||||
# Objects which are only used for the disassembler
|
||||
LIBOBJ_DIS = disasm/disasm.$(O) disasm/sync.$(O) disasm/rexdis.$(O)
|
||||
LIBOBJ_DIS = \
|
||||
disasm/disasm.$(O) disasm/sync.$(O) disasm/prefix.$(O) \
|
||||
\
|
||||
x86/insnsd.$(O) x86/regdis.$(O)
|
||||
|
||||
# Objects for the local copy of zlib. The variable ZLIB is set to
|
||||
# $(ZLIBOBJ) if the internal version of zlib should be used.
|
||||
|
|
@ -232,7 +235,7 @@ $(DISLIB): $(LIBOBJ_DIS)
|
|||
nasm$(X): $(NASM) $(MANIFEST) $(NASMLIB)
|
||||
$(CC) $(ALL_LDFLAGS) -o nasm$(X) $^ $(LIBS)
|
||||
|
||||
ndisasm$(X): $(NDISASM) $(MANIFEST) $(NASMLIB) $(DISLIB)
|
||||
ndisasm$(X): $(NDISASM) $(MANIFEST) $(DISLIB) $(NASMLIB)
|
||||
$(CC) $(ALL_LDFLAGS) -o ndisasm$(X) $^ $(LIBS)
|
||||
|
||||
# These are specific to certain Makefile syntaxes...
|
||||
|
|
|
|||
|
|
@ -3796,11 +3796,11 @@ static bool parse_mmacro_spec(Token *tline, MMacro *def, const char *directive)
|
|||
* Decode a size directive
|
||||
*/
|
||||
static int parse_size(const char *str) {
|
||||
static const char *size_names[] =
|
||||
{ "byte", "dword", "oword", "qword", "tword", "word", "yword" };
|
||||
static const int sizes[] =
|
||||
{ 0, 1, 4, 16, 8, 10, 2, 32 };
|
||||
return str ? sizes[bsii(str, size_names, ARRAY_SIZE(size_names))+1] : 0;
|
||||
struct tokenval tv;
|
||||
if (nasm_token_hash(str, &tv) != TOKEN_SIZE)
|
||||
return 0;
|
||||
|
||||
return tv.t_inttwo;
|
||||
}
|
||||
|
||||
/*
|
||||
|
|
|
|||
|
|
@ -31,7 +31,7 @@
|
|||
##
|
||||
## --------------------------------------------------------------------------
|
||||
|
||||
# The token parameters are in the other:
|
||||
# The token parameters are in the order:
|
||||
# TOKEN_TYPE, t_inttwo, t_flags, t_integer
|
||||
#
|
||||
# * is replaced with the token name converted to upper case.
|
||||
|
|
@ -93,6 +93,7 @@ zu
|
|||
byte
|
||||
word
|
||||
dword
|
||||
long
|
||||
qword
|
||||
tword
|
||||
oword
|
||||
|
|
@ -102,7 +103,6 @@ zword
|
|||
% TOKEN_SPECIAL, 0, 0, S_*
|
||||
abs
|
||||
far
|
||||
long
|
||||
near
|
||||
nosplit
|
||||
rel
|
||||
|
|
|
|||
|
|
@ -73,7 +73,7 @@ close(ID);
|
|||
#
|
||||
open(RD, '<', $regs_dat) or die "$0: cannot open $regs_dat: $!\n";
|
||||
while (defined($line = <RD>)) {
|
||||
if ($line =~ /^([\?\@a-z0-9_-]+)\s*\S+\s*\S+\s*[0-9]+\s*(\S*)/) {
|
||||
if ($line =~ /^([\?\@a-z0-9_-]+)\s*\S+\s*\S+\s*[0-9]+\s*(?:\&\s*[0-9]+\s*)?(\S*)/) {
|
||||
$reg = $1;
|
||||
$reg_flag = $2;
|
||||
|
||||
|
|
|
|||
1119
disasm/disasm.c
1119
disasm/disasm.c
File diff suppressed because it is too large
Load diff
|
|
@ -1,6 +1,6 @@
|
|||
/* ----------------------------------------------------------------------- *
|
||||
*
|
||||
* Copyright 1996-2009 The NASM Authors - All Rights Reserved
|
||||
* Copyright 1996-2025 The NASM Authors - All Rights Reserved
|
||||
* See the file AUTHORS included with the NASM distribution for
|
||||
* the specific copyright holders.
|
||||
*
|
||||
|
|
@ -38,12 +38,82 @@
|
|||
#ifndef NASM_DISASM_H
|
||||
#define NASM_DISASM_H
|
||||
|
||||
#include "nasm.h"
|
||||
#include "insnsi.h"
|
||||
#include "iflag.h"
|
||||
|
||||
#define INSN_MAX 32 /* one instruction can't be longer than this */
|
||||
/*
|
||||
* This buffer must be at least twice as long as the max instruction,
|
||||
* which must include the WAIT pseudo-prefix, for a total of 15+1 = 16
|
||||
* bytes.
|
||||
*/
|
||||
#define INSN_MAX 32
|
||||
|
||||
int32_t disasm(uint8_t *data, int32_t data_size, char *output, int outbufsize, int segsize,
|
||||
int64_t offset, int autosync, iflag_t *prefer);
|
||||
int32_t eatbyte(uint8_t *data, char *output, int outbufsize, int segsize);
|
||||
int32_t disasm(const uint8_t *dp, int32_t data_size,
|
||||
char *output, int outbufsize,
|
||||
int segsize, int64_t offset, int autosync,
|
||||
iflag_t *prefer);
|
||||
int32_t eatbyte(uint8_t byte, char *output, int outbufsize, int segsize);
|
||||
|
||||
/* The rex types that matter for the purpose of decoding */
|
||||
enum rextype {
|
||||
REX_NONE,
|
||||
REX_REX,
|
||||
REX_REX2,
|
||||
REX_VEX, /* Includes XOP */
|
||||
REX_EVEX
|
||||
};
|
||||
|
||||
/*
|
||||
* Prefix information
|
||||
*/
|
||||
struct rexfields {
|
||||
uint32_t raw; /* Raw value */
|
||||
uint32_t flags; /* REX_ flags from nasm.h */
|
||||
enum rextype type;
|
||||
uint8_t len; /* Length of REX prefix */
|
||||
uint8_t breg; /* B register */
|
||||
uint8_t bregbv; /* B register if B is a vector */
|
||||
uint8_t xreg; /* X register */
|
||||
uint8_t xregxv; /* X register if X is a vector */
|
||||
uint8_t vreg; /* V register */
|
||||
uint8_t vregxv; /* V register if X is a vector */
|
||||
uint8_t rreg;
|
||||
uint8_t opc; /* Masked opcode */
|
||||
uint8_t map;
|
||||
uint8_t xmap; /* Extended map (base from insnsi.h added) */
|
||||
uint8_t pp;
|
||||
uint8_t w;
|
||||
uint8_t l;
|
||||
uint8_t z;
|
||||
uint8_t b;
|
||||
uint8_t nd;
|
||||
uint8_t aaa;
|
||||
uint8_t nf;
|
||||
uint8_t dfl;
|
||||
uint8_t scc;
|
||||
};
|
||||
|
||||
struct prefix_info {
|
||||
uint8_t osize; /* Operand size */
|
||||
uint8_t asize; /* Address size */
|
||||
uint8_t osp; /* Operand size prefix present */
|
||||
uint8_t asp; /* Address size prefix present */
|
||||
uint8_t rep; /* Rep prefix present */
|
||||
uint8_t seg; /* Segment override prefix present */
|
||||
uint8_t wait; /* WAIT "prefix" present */
|
||||
uint8_t lock; /* Lock prefix present */
|
||||
enum reg_enum segover; /* Segment override register enum */
|
||||
struct rexfields rex; /* REX/REX2/VEX/EVEX */
|
||||
};
|
||||
|
||||
const uint8_t *parse_prefixes(struct prefix_info *pf, const uint8_t *data,
|
||||
int bits);
|
||||
|
||||
#define fetch_safe(_start, _ptr, _size, _need, _op) \
|
||||
do { \
|
||||
if (((_ptr) - (_start)) >= ((_size) - (_need))) \
|
||||
_op; \
|
||||
} while (0)
|
||||
|
||||
#endif
|
||||
|
|
|
|||
|
|
@ -62,7 +62,7 @@ static const char *help =
|
|||
" -k avoids disassembling <bytes> bytes from position <start>\n"
|
||||
" -p selects the preferred vendor instruction set (intel, amd, cyrix, idt)\n";
|
||||
|
||||
static void output_ins(uint64_t, uint8_t *, int, char *);
|
||||
static void output_ins(uint64_t, const uint8_t *, int, const char *);
|
||||
static void skip(uint32_t dist, FILE * fp);
|
||||
|
||||
void nasm_verror(errflags severity, const char *fmt, va_list val)
|
||||
|
|
@ -82,7 +82,8 @@ fatal_func nasm_verror_critical(errflags severity, const char *fmt, va_list val)
|
|||
|
||||
int main(int argc, char **argv)
|
||||
{
|
||||
char buffer[INSN_MAX * 2], *p, *ep, *q;
|
||||
uint8_t buffer[INSN_MAX * 2], *p;
|
||||
const uint8_t *q;
|
||||
char outbuf[256];
|
||||
char *pname = *argv;
|
||||
char *filename = NULL;
|
||||
|
|
@ -135,8 +136,9 @@ int main(int argc, char **argv)
|
|||
pname);
|
||||
return 1;
|
||||
}
|
||||
b = strtoul(v, &ep, 10);
|
||||
if (*ep || !(bits == 16 || bits == 32 || bits == 64)) {
|
||||
b = readnum(v, &rn_error);
|
||||
if (rn_error ||
|
||||
!(bits == 16 || bits == 32 || bits == 64)) {
|
||||
fprintf(stderr, "%s: argument to `-b' should"
|
||||
" be 16, 32 or 64\n", pname);
|
||||
} else {
|
||||
|
|
@ -294,7 +296,7 @@ int main(int argc, char **argv)
|
|||
* find the energy...
|
||||
*/
|
||||
|
||||
p = q = buffer;
|
||||
q = p = buffer;
|
||||
nextsync = next_sync(offset, &synclen);
|
||||
do {
|
||||
int32_t to_read = buffer + sizeof(buffer) - p;
|
||||
|
|
@ -316,25 +318,23 @@ int main(int argc, char **argv)
|
|||
offset += synclen;
|
||||
skip(synclen, fp);
|
||||
}
|
||||
p = q = buffer;
|
||||
q = p = buffer;
|
||||
nextsync = next_sync(offset, &synclen);
|
||||
}
|
||||
while (p > q && (p - q >= INSN_MAX || lenread == 0)) {
|
||||
lendis = disasm((uint8_t *)q, INSN_MAX, outbuf, sizeof(outbuf),
|
||||
lendis = disasm(q, INSN_MAX, outbuf, sizeof(outbuf),
|
||||
bits, offset, autosync, &prefer);
|
||||
if (!lendis || lendis > (p - q)
|
||||
|| ((nextsync || synclen) &&
|
||||
(uint32_t)lendis > nextsync - offset))
|
||||
lendis = eatbyte((uint8_t *) q, outbuf, sizeof(outbuf), bits);
|
||||
output_ins(offset, (uint8_t *) q, lendis, outbuf);
|
||||
lendis = eatbyte(*q, outbuf, sizeof(outbuf), bits);
|
||||
output_ins(offset, q, lendis, outbuf);
|
||||
q += lendis;
|
||||
offset += lendis;
|
||||
}
|
||||
if (q >= buffer + INSN_MAX) {
|
||||
uint8_t *r = (uint8_t *) buffer, *s = (uint8_t *) q;
|
||||
int count = p - q;
|
||||
while (count--)
|
||||
*r++ = *s++;
|
||||
memmove(buffer, q, count);
|
||||
p -= (q - buffer);
|
||||
q = buffer;
|
||||
}
|
||||
|
|
@ -346,8 +346,8 @@ int main(int argc, char **argv)
|
|||
return 0;
|
||||
}
|
||||
|
||||
static void output_ins(uint64_t offset, uint8_t *data,
|
||||
int datalen, char *insn)
|
||||
static void output_ins(uint64_t offset, const uint8_t *data,
|
||||
int datalen, const char *insn)
|
||||
{
|
||||
int bytes;
|
||||
fprintf(stdout, "%08"PRIX64" ", offset);
|
||||
|
|
|
|||
501
disasm/prefix.c
Normal file
501
disasm/prefix.c
Normal file
|
|
@ -0,0 +1,501 @@
|
|||
/* ----------------------------------------------------------------------- *
|
||||
*
|
||||
* Copyright 2025 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 "disasm.h"
|
||||
#include "nasmlib.h"
|
||||
|
||||
/*
|
||||
* Parse various register combinations. Note that this does NOT
|
||||
* generate the REX_[BXR][1V] flags, as they are not used by the
|
||||
* disassembler.
|
||||
*/
|
||||
static uint32_t
|
||||
xbits(uint32_t val, unsigned int from, unsigned int count, unsigned int to)
|
||||
{
|
||||
const uint32_t tomask = ((UINT32_C(1) << count)-1) << to;
|
||||
|
||||
if (to < from)
|
||||
return (val >> (from-to)) & tomask;
|
||||
else
|
||||
return (val << (to-from)) & tomask;
|
||||
}
|
||||
|
||||
/* ------ EVEX decoding ------ */
|
||||
|
||||
#define EVEX_INVERTED 0x087cf000
|
||||
|
||||
static uint32_t
|
||||
evexbits(uint32_t val, unsigned int from, unsigned int count, unsigned int to)
|
||||
{
|
||||
return xbits(val ^ EVEX_INVERTED, from, count, to);
|
||||
}
|
||||
|
||||
static uint32_t evex_rreg(uint32_t evex)
|
||||
{
|
||||
return evexbits(evex,15,1,3) + evexbits(evex,12,1,4);
|
||||
}
|
||||
static uint32_t evex_xreg(uint32_t evex, bool xv)
|
||||
{
|
||||
uint32_t x = evexbits(evex,14,1,3);
|
||||
x += evexbits(evex,xv ? 27 : 18,1,4);
|
||||
return x;
|
||||
}
|
||||
static uint32_t evex_breg(uint32_t evex, bool bv)
|
||||
{
|
||||
uint32_t b = evexbits(evex,13,1,3);
|
||||
b += evexbits(evex,bv ? 14 : 11,1,4);
|
||||
return b;
|
||||
}
|
||||
static uint32_t evex_vreg(uint32_t evex, bool xv)
|
||||
{
|
||||
uint32_t v = evexbits(evex,19,4,0);
|
||||
if (!xv)
|
||||
v += evexbits(evex,27,1,4);
|
||||
return v;
|
||||
}
|
||||
static uint32_t evex_aaa(uint32_t evex)
|
||||
{
|
||||
return evexbits(evex,24,3,0);
|
||||
}
|
||||
static uint32_t evex_z(uint32_t evex)
|
||||
{
|
||||
return evexbits(evex,31,1,0);
|
||||
}
|
||||
static uint32_t evex_l(uint32_t evex)
|
||||
{
|
||||
return evexbits(evex,29,2,0);
|
||||
}
|
||||
static uint32_t evex_b(uint32_t evex)
|
||||
{
|
||||
return evexbits(evex,28,1,0);
|
||||
}
|
||||
static uint32_t evex_nf(uint32_t evex)
|
||||
{
|
||||
return evexbits(evex,26,1,0);
|
||||
}
|
||||
static uint32_t evex_scc(uint32_t evex)
|
||||
{
|
||||
return evexbits(evex,24,4,0);
|
||||
}
|
||||
static uint32_t evex_dfl(uint32_t evex)
|
||||
{
|
||||
return evexbits(evex,19,4,0);
|
||||
}
|
||||
static uint32_t evex_map(uint32_t evex)
|
||||
{
|
||||
return evexbits(evex,8,3,0);
|
||||
}
|
||||
static uint32_t evex_w(uint32_t evex)
|
||||
{
|
||||
return evexbits(evex,23,1,0);
|
||||
}
|
||||
static uint32_t evex_pp(uint32_t evex)
|
||||
{
|
||||
return evexbits(evex,16,2,0);
|
||||
}
|
||||
|
||||
/* ------ VEX3 decoding ------ */
|
||||
|
||||
static uint32_t vex2to3(uint32_t vex2)
|
||||
{
|
||||
return (vex2 & 0x80fe) + ((vex2 & 0x7f00) << 8) + 0x6100;
|
||||
}
|
||||
|
||||
static uint32_t vex3_rreg(uint32_t vex)
|
||||
{
|
||||
return xbits(~vex,15,1,3);
|
||||
}
|
||||
static uint32_t vex3_xreg(uint32_t vex)
|
||||
{
|
||||
return xbits(~vex,14,1,3);
|
||||
}
|
||||
static uint32_t vex3_breg(uint32_t vex)
|
||||
{
|
||||
return xbits(~vex,13,1,3);
|
||||
}
|
||||
static uint32_t vex3_map(uint32_t vex)
|
||||
{
|
||||
return xbits(~vex,8,5,0);
|
||||
}
|
||||
static uint32_t vex3_vreg(uint32_t vex)
|
||||
{
|
||||
return xbits(~vex,19,4,0);
|
||||
}
|
||||
static uint32_t vex3_l(uint32_t vex)
|
||||
{
|
||||
return xbits(vex,18,1,0);
|
||||
}
|
||||
static uint32_t vex3_pp(uint32_t vex)
|
||||
{
|
||||
return xbits(vex,16,2,0);
|
||||
}
|
||||
static uint32_t vex3_w(uint32_t vex)
|
||||
{
|
||||
return xbits(vex,23,1,0);
|
||||
}
|
||||
|
||||
/* ------ REX2 decoding ------ */
|
||||
|
||||
static uint32_t rex2_rreg(uint32_t rex)
|
||||
{
|
||||
return xbits(rex,14,1,4) + xbits(rex,10,1,3);
|
||||
}
|
||||
static uint32_t rex2_xreg(uint32_t rex)
|
||||
{
|
||||
return xbits(rex,13,1,4) + xbits(rex,9,1,3);
|
||||
}
|
||||
static uint32_t rex2_breg(uint32_t rex)
|
||||
{
|
||||
return xbits(rex,12,1,4) + xbits(rex,8,1,3);
|
||||
}
|
||||
static uint32_t rex2_w(uint32_t rex)
|
||||
{
|
||||
return xbits(rex,11,1,0);
|
||||
}
|
||||
static uint32_t rex2_map(uint32_t rex)
|
||||
{
|
||||
return xbits(rex,15,1,0);
|
||||
}
|
||||
|
||||
/* ------ REX decoding ------ */
|
||||
|
||||
static uint32_t rex_rreg(uint32_t rex)
|
||||
{
|
||||
return xbits(rex,2,1,3);
|
||||
}
|
||||
static uint32_t rex_xreg(uint32_t rex)
|
||||
{
|
||||
return xbits(rex,1,1,3);
|
||||
}
|
||||
static uint32_t rex_breg(uint32_t rex)
|
||||
{
|
||||
return xbits(rex,0,1,3);
|
||||
}
|
||||
static uint32_t rex_w(uint32_t rex)
|
||||
{
|
||||
return xbits(rex,3,1,0);
|
||||
}
|
||||
|
||||
/*
|
||||
* Parse an EVEX prefix.
|
||||
*/
|
||||
static void parse_evex(struct rexfields *rf, uint32_t val)
|
||||
{
|
||||
rf->type = REX_EVEX;
|
||||
rf->len = 4;
|
||||
rf->raw = val;
|
||||
rf->opc = (uint8_t)val;
|
||||
|
||||
rf->breg = evex_breg(val, false);
|
||||
rf->bregbv = evex_breg(val, true);
|
||||
rf->xreg = evex_xreg(val, false);
|
||||
rf->xregxv = evex_xreg(val, true);
|
||||
rf->vreg = evex_vreg(val, false);
|
||||
rf->vregxv = evex_vreg(val, true);
|
||||
|
||||
rf->rreg = evex_rreg(val);
|
||||
rf->map = evex_map(val);
|
||||
rf->xmap = rf->map + MAP_BASE_EVEX;
|
||||
rf->pp = evex_pp(val);
|
||||
rf->l = evex_l(val);
|
||||
rf->w = evex_w(val);
|
||||
rf->z = evex_z(val);
|
||||
rf->b = evex_b(val);
|
||||
rf->nd = rf->b;
|
||||
rf->aaa = evex_aaa(val);
|
||||
rf->scc = evex_scc(val);
|
||||
rf->dfl = evex_dfl(val);
|
||||
rf->nf = evex_nf(val);
|
||||
|
||||
rf->flags = REX_EV | REX_P | ((~val >> 8) & 7) | (rf->w << 3);
|
||||
}
|
||||
|
||||
/* ------ Set value for all moptypes ------ */
|
||||
|
||||
/* case statements for original REX */
|
||||
#define CASE_REX \
|
||||
case 0x40: case 0x41: case 0x42: case 0x43: \
|
||||
case 0x44: case 0x45: case 0x46: case 0x47: \
|
||||
case 0x48: case 0x49: case 0x4a: case 0x4b: \
|
||||
case 0x4c: case 0x4d: case 0x4e: case 0x4f
|
||||
|
||||
static const uint8_t *
|
||||
parse_rex(struct rexfields *rf, uint8_t op, const uint8_t *p)
|
||||
{
|
||||
uint32_t breg = 0;
|
||||
uint32_t xreg = 0;
|
||||
uint32_t vreg = 0;
|
||||
uint32_t val = op;
|
||||
|
||||
rf->opc = op;
|
||||
|
||||
switch (op) {
|
||||
CASE_REX:
|
||||
rf->type = REX_REX;
|
||||
rf->flags = op;
|
||||
rf->len = 1;
|
||||
rf->raw = op;
|
||||
rf->opc = 0x40; /* Mask out payload bits */
|
||||
breg = rex_breg(op);
|
||||
xreg = rex_xreg(op);
|
||||
rf->rreg = rex_rreg(op);
|
||||
rf->w = rex_w(op);
|
||||
break;
|
||||
|
||||
case 0xd5:
|
||||
rf->type = REX_REX2;
|
||||
rf->len = 2;
|
||||
rf->raw = val = getu16(p);
|
||||
rf->flags = REX_2 | REX_P | ((val >> 8) & 15);
|
||||
rf->opc = (uint8_t)val;
|
||||
breg = rex2_breg(val);
|
||||
xreg = rex2_xreg(val);
|
||||
rf->rreg = rex2_rreg(val);
|
||||
rf->w = rex2_w(val);
|
||||
rf->map = rex2_map(val);
|
||||
rf->xmap = rf->map + MAP_BASE_REX2;
|
||||
break;
|
||||
|
||||
case 0xc5:
|
||||
rf->raw = val = getu16(p);
|
||||
val = vex2to3(val);
|
||||
rf->map = 1;
|
||||
rf->xmap = rf->map + MAP_BASE_VEX;
|
||||
rf->len = 2;
|
||||
goto vex_common;
|
||||
|
||||
case 0x8f:
|
||||
rf->raw = val = op + (getu16(p+1) << 16);
|
||||
rf->map = vex3_map(val);
|
||||
if (rf->map < 8)
|
||||
return NULL;
|
||||
rf->xmap = rf->map + MAP_BASE_XOP;
|
||||
rf->len = 3;
|
||||
goto vex_common;
|
||||
|
||||
case 0xc4:
|
||||
rf->raw = val = op + (getu16(p+1) << 16);
|
||||
rf->map = vex3_map(val);
|
||||
rf->xmap = rf->map + MAP_BASE_VEX;
|
||||
rf->len = 3;
|
||||
vex_common:
|
||||
rf->type = REX_VEX;
|
||||
breg = vex3_breg(val);
|
||||
xreg = vex3_xreg(val);
|
||||
vreg = vex3_vreg(val);
|
||||
rf->rreg = vex3_rreg(val);
|
||||
rf->map += vex3_map(val);
|
||||
rf->pp = vex3_pp(val);
|
||||
rf->l = vex3_l(val);
|
||||
rf->w = vex3_w(val);
|
||||
rf->flags = REX_P | REX_V | ((~val >> 8) & 7) | (rf->w << 3);
|
||||
break;
|
||||
|
||||
case 0x62:
|
||||
parse_evex(rf, getu32(p));
|
||||
return p + rf->len;
|
||||
|
||||
default:
|
||||
return p; /* Not a prefix */
|
||||
}
|
||||
|
||||
rf->bregbv = rf->breg = breg;
|
||||
rf->xregxv = rf->xreg = xreg;
|
||||
rf->vregxv = rf->vreg = vreg;
|
||||
|
||||
return p + rf->len;
|
||||
}
|
||||
|
||||
/*
|
||||
* The buffer must contain at least 20 readable bytes, although the
|
||||
* actual values beyond the end of the current valid instruction do
|
||||
* not matter. This function returns NULL if the instruction is
|
||||
* inherently invalid.
|
||||
*/
|
||||
const uint8_t *
|
||||
parse_prefixes(struct prefix_info *pf, const uint8_t *data, int bits)
|
||||
{
|
||||
bool end_prefix;
|
||||
const uint8_t *p = data;
|
||||
const uint8_t *maxp;
|
||||
|
||||
nasm_zero(*pf);
|
||||
|
||||
/*
|
||||
* The maximum instruction length is 15 bytes; fail in parse_prefixes()
|
||||
* unless there is at least one byte left for the actual opcode.
|
||||
*/
|
||||
maxp = p + 15 - 1;
|
||||
|
||||
pf->asize = bits;
|
||||
pf->osize = (bits == 64) ? 32 : bits;
|
||||
|
||||
/*
|
||||
* WAIT is not really a prefix, but an instruction in its own
|
||||
* right. Only decode it as the very first byte (otherwise
|
||||
* prefixes apply to the WAIT instruction, not to anything
|
||||
* following it!) so that in case WAIT actually is prefixed with
|
||||
* something, those prefixes will be separately emitted by
|
||||
* eat_byte().
|
||||
*
|
||||
* Since WAIT is really an instruction, it doesn't count towards
|
||||
* the length of the following instruction, either.
|
||||
*/
|
||||
|
||||
if (*p == 0x9b) {
|
||||
pf->wait = *p++;
|
||||
maxp++; /* Does not count toward instruction length */
|
||||
}
|
||||
|
||||
end_prefix = false;
|
||||
while (!end_prefix) {
|
||||
uint8_t b = *p;
|
||||
|
||||
switch (b) {
|
||||
case 0xf2:
|
||||
case 0xf3:
|
||||
pf->rep = b;
|
||||
pf->rex.pp = b ^ 0xfd; /* F2 = 3, F3 = 2 */
|
||||
p++;
|
||||
break;
|
||||
|
||||
case 0xf0:
|
||||
pf->lock = b;
|
||||
p++;
|
||||
break;
|
||||
|
||||
case 0x26:
|
||||
pf->segover = R_ES;
|
||||
goto isseg;
|
||||
case 0x2e:
|
||||
pf->segover = R_CS;
|
||||
goto isseg;
|
||||
case 0x36:
|
||||
pf->segover = R_SS;
|
||||
goto isseg;
|
||||
case 0x3e:
|
||||
pf->segover = R_DS;
|
||||
goto isseg;
|
||||
case 0x64:
|
||||
pf->segover = R_FS;
|
||||
goto isseg;
|
||||
case 0x65:
|
||||
pf->segover = R_GS;
|
||||
isseg:
|
||||
pf->seg = b;
|
||||
p++;
|
||||
break;
|
||||
|
||||
case 0x66:
|
||||
pf->osize = (bits == 16) ? 32 : 16;
|
||||
pf->osp = b;
|
||||
pf->rex.pp = 1;
|
||||
p++;
|
||||
break;
|
||||
case 0x67:
|
||||
pf->asize = (bits == 32) ? 16 : 32;
|
||||
pf->asp = b;
|
||||
p++;
|
||||
break;
|
||||
|
||||
CASE_REX:
|
||||
case 0xd5: /* REX2 */
|
||||
if (bits == 64)
|
||||
p = parse_rex(&pf->rex, b, p);
|
||||
end_prefix = true;
|
||||
break;
|
||||
|
||||
case 0x8f: /* XOP */
|
||||
if (!(p[1] & 030)) {
|
||||
/* Only maps 8-31 valid to protect 8F /0 */
|
||||
end_prefix = true;
|
||||
break;
|
||||
}
|
||||
/* fall through */
|
||||
case 0xc4: /* VEX2 */
|
||||
case 0xc5: /* VEX3 */
|
||||
case 0x62: /* EVEX */
|
||||
if (bits == 64 || (p[1] & 0xe0) == 0xe0)
|
||||
p = parse_rex(&pf->rex, b, p);
|
||||
end_prefix = true;
|
||||
break;
|
||||
|
||||
default:
|
||||
end_prefix = true;
|
||||
break;
|
||||
}
|
||||
|
||||
if (p > maxp)
|
||||
return NULL; /* Invalid instruction */
|
||||
}
|
||||
|
||||
if (pf->rex.type > REX_REX) {
|
||||
if (pf->osp || pf->rep)
|
||||
return NULL; /* Invalid instruction (illegal prefix) */
|
||||
} else {
|
||||
/* Redundant REX prefixes are ignored */
|
||||
if (bits == 64) {
|
||||
while ((*p & 0xf0) == 0x40) {
|
||||
p++;
|
||||
if (p > maxp)
|
||||
return NULL;
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* Look for legacy map prefixes. These must come after all
|
||||
* possible REX prefixes.
|
||||
*/
|
||||
if (*p == 0x0f) {
|
||||
pf->rex.map = 1;
|
||||
p++;
|
||||
switch (*p) {
|
||||
case 0x38:
|
||||
pf->rex.map = 2;
|
||||
p++;
|
||||
break;
|
||||
case 0x3a:
|
||||
pf->rex.map = 3;
|
||||
p++;
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (p > maxp)
|
||||
return NULL;
|
||||
|
||||
return p;
|
||||
}
|
||||
|
|
@ -48,17 +48,16 @@ static inline unsigned int get_disp8_shift(const insn *ins)
|
|||
bool evex_b;
|
||||
unsigned int evex_w;
|
||||
unsigned int vectlen;
|
||||
enum ttypes tuple;
|
||||
enum ttypes tuple = ins->evex_tuple;
|
||||
|
||||
if (likely(!(ins->rex & REX_EV)))
|
||||
if (likely(!tuple))
|
||||
return 0;
|
||||
|
||||
evex_b = !!(ins->evex & EVEX_P2B);
|
||||
tuple = ins->evex_tuple;
|
||||
vectlen = (ins->evex & EVEX_P2LL) >> 29;
|
||||
evex_w = !!(ins->evex & EVEX_P1W);
|
||||
|
||||
switch(tuple) {
|
||||
switch (tuple) {
|
||||
/* Full, half vector unless broadcast */
|
||||
case FV:
|
||||
return evex_b ? 2 + evex_w : vectlen + 4;
|
||||
|
|
|
|||
|
|
@ -38,8 +38,7 @@ struct itemplate_list {
|
|||
extern const struct itemplate_list nasm_instructions[];
|
||||
|
||||
/* Instruction tables for the disassembler */
|
||||
extern const struct itemplate * const * const * const
|
||||
ndisasm_itable[NASM_VEX_CLASSES][NASM_MAX_MAPS];
|
||||
extern const struct itemplate * const * const * const ndisasm_itable[];
|
||||
|
||||
/* Common table for the byte codes */
|
||||
extern const uint8_t nasm_bytecodes[];
|
||||
|
|
|
|||
|
|
@ -612,7 +612,8 @@ enum {
|
|||
#define REX_rR (REX_R | REX_R1 | REX_RV | REX_H | REX_P)
|
||||
|
||||
/*
|
||||
* EVEX bit field
|
||||
* EVEX bit field. Note that the P[] numbers in the SDM does not include
|
||||
* the leading 0x62 byte.
|
||||
*/
|
||||
#define EVEX_P0MM 0x0700 /* EVEX P[2:0] : Opcode map */
|
||||
#define EVEX_P0BP 0x0800 /* EVEX P[3] : High-16 B register */
|
||||
|
|
@ -628,6 +629,7 @@ enum {
|
|||
#define EVEX_P2AAA 0x07000000 /* EVEX P[18:16] : Embedded opmask */
|
||||
#define EVEX_P2NF 0x04000000 /* EVEX P[18]: No flags bit */
|
||||
#define EVEX_P2VP 0x08000000 /* EVEX P[19] : High-16 NDS reg */
|
||||
#define EVEX_P2SCC 0x0f000000 /* EVEX P[19:16]: Modified condition */
|
||||
#define EVEX_P2B 0x10000000 /* EVEX P[20] : Broadcast / RC / SAE */
|
||||
#define EVEX_P2ND EVEX_P2B /* EVEX P[20] : New destination */
|
||||
#define EVEX_P2LL 0x60000000 /* EVEX P[22:21] : Vector length */
|
||||
|
|
@ -1329,6 +1331,7 @@ enum byte_sizes {
|
|||
SIZE_BYTE = 1,
|
||||
SIZE_WORD = 2,
|
||||
SIZE_DWORD = 4,
|
||||
SIZE_LONG = 4,
|
||||
SIZE_QWORD = 8,
|
||||
SIZE_TWORD = 10,
|
||||
SIZE_OWORD = 16,
|
||||
|
|
@ -1341,6 +1344,7 @@ enum special_tokens {
|
|||
S_BYTE = SIZE_ENUM_START,
|
||||
S_WORD,
|
||||
S_DWORD,
|
||||
S_LONG,
|
||||
S_QWORD,
|
||||
S_TWORD,
|
||||
S_OWORD,
|
||||
|
|
@ -1351,7 +1355,6 @@ enum special_tokens {
|
|||
SPECIAL_ENUM_START = SIZE_ENUM_LIMIT,
|
||||
S_ABS = SPECIAL_ENUM_START,
|
||||
S_FAR,
|
||||
S_LONG,
|
||||
S_NEAR,
|
||||
S_NOSPLIT,
|
||||
S_REL,
|
||||
|
|
|
|||
|
|
@ -412,9 +412,44 @@ dbg_pragma(const struct pragma *pragma)
|
|||
return DIRR_OK;
|
||||
}
|
||||
|
||||
static const char * const types[] = {
|
||||
"unknown", "label", "byte", "word", "dword", "float", "qword", "tbyte"
|
||||
};
|
||||
static const char *type_name(uint32_t type)
|
||||
{
|
||||
switch (TYM_TYPE(type)) {
|
||||
case TY_UNKNOWN:
|
||||
return "unknown";
|
||||
case TY_LABEL:
|
||||
return "label";
|
||||
case TY_BYTE:
|
||||
return "byte";
|
||||
case TY_WORD:
|
||||
return "word";
|
||||
case TY_DWORD:
|
||||
return "dword";
|
||||
case TY_FLOAT:
|
||||
return "float";
|
||||
case TY_QWORD:
|
||||
return "qword";
|
||||
case TY_TBYTE:
|
||||
return "tbyte";
|
||||
case TY_OWORD:
|
||||
return "oword";
|
||||
case TY_YWORD:
|
||||
return "yword";
|
||||
case TY_ZWORD:
|
||||
return "zword";
|
||||
case TY_COMMON:
|
||||
return "common";
|
||||
case TY_SEG:
|
||||
return "seg";
|
||||
case TY_EXTERN:
|
||||
return "extern";
|
||||
case TY_EQU:
|
||||
return "equ";
|
||||
default:
|
||||
return "<invalid type code>";
|
||||
}
|
||||
}
|
||||
|
||||
static void dbgdbg_init(void)
|
||||
{
|
||||
fprintf(ofile, "dbg init: debug information enabled\n");
|
||||
|
|
@ -461,7 +496,7 @@ static void dbgdbg_output(int output_type, void *param)
|
|||
static void dbgdbg_typevalue(int32_t type)
|
||||
{
|
||||
fprintf(ofile, "dbg typevalue: %s(%"PRIX32")\n",
|
||||
types[TYM_TYPE(type) >> 3], TYM_ELEMENTS(type));
|
||||
type_name(type), TYM_ELEMENTS(type));
|
||||
}
|
||||
|
||||
static void
|
||||
|
|
|
|||
|
|
@ -1,9 +1,23 @@
|
|||
bits 64
|
||||
_start:
|
||||
es add eax,eax
|
||||
add eax,[rdx]
|
||||
add eax,[fs:rdx]
|
||||
fs add eax,[rdx]
|
||||
movzx eax,word [fs:rdx]
|
||||
jz foo
|
||||
ds jz foo
|
||||
jmp bar
|
||||
db 0x48
|
||||
jmp bar
|
||||
cs jmp bar
|
||||
jmp strict near bar
|
||||
cs jmp strict near bar
|
||||
mov eax,[r15]
|
||||
mov eax,[r31]
|
||||
mov rax,[rdx]
|
||||
mov rax,[r15]
|
||||
mov rax,[r31]
|
||||
foo:
|
||||
hlt
|
||||
bar:
|
||||
|
|
|
|||
|
|
@ -257,7 +257,7 @@ $bwd CMPXCHG486 rm#,reg# [mr: 0f a6# /r] 486,SM,UNDOC,NOLONG,ND,LOCK,OBSOL
|
|||
; Call/jmp near imm/reg/mem are always 64-bit in long mode.
|
||||
JMP imm8|short [i: nw eb rel8] 8086,NOAPX
|
||||
JMP imm [i: jmp8 nw eb rel8] 8086,SX,ND,NOAPX
|
||||
$wdq JMP imm##|near [i: nw o# e9 rel] 8086,OSIZE,ND,BND,NOLONG16
|
||||
$wdq JMP imm##|near [i: nw o# e9 rel] 8086,OSIZE,BND,NOLONG16
|
||||
$wdq JMP rm#|near [m: nw o# ff /4] 8086,OSIZE,BND,NOLONG16
|
||||
$wd JMP imm#|far [i: o# ea iwd seg] 8086,OSIZE,ND,NOLONG
|
||||
$wd JMP imm16:imm# [ji: o# ea iwd iw] 8086,OSIZE,AR1,NOLONG
|
||||
|
|
|
|||
279
x86/insns.pl
279
x86/insns.pl
|
|
@ -1,7 +1,7 @@
|
|||
#!/usr/bin/perl
|
||||
## --------------------------------------------------------------------------
|
||||
##
|
||||
## Copyright 1996-2024 The NASM Authors - All Rights Reserved
|
||||
## Copyright 1996-2025 The NASM Authors - All Rights Reserved
|
||||
## See the file AUTHORS included with the NASM distribution for
|
||||
## the specific copyright holders.
|
||||
##
|
||||
|
|
@ -44,13 +44,15 @@
|
|||
require 'x86/insns-iflags.ph';
|
||||
|
||||
# Create disassembly root tables
|
||||
my @vex_class = ( 'novex', 'vex', 'xop', 'evex' );
|
||||
my @vex_class = ( 'novex', 'vex', 'xop', 'evex', 'rex2' );
|
||||
my $vex_classes = scalar(@vex_class);
|
||||
my $max_maps = 32;
|
||||
my @distable;
|
||||
my @map_count = ( 4, 32, 24, 8, 2 );
|
||||
my @map_start = ( 0, 0, 8, 0, 0 );
|
||||
my @map_max;
|
||||
for ($c = 0; $c < $vex_classes; $c++) {
|
||||
push(@distable, []);
|
||||
for ($m = 0; $m < $max_maps; $m++) {
|
||||
push(@distable, [(undef) x $map_start[$c]]);
|
||||
push(@map_max, $map_start[$c] + $map_count[$c] - 1);
|
||||
for ($m = $map_start[$c]; $m <= $map_max[$c]; $m++) {
|
||||
push(@{$distable[$c]}, {});
|
||||
}
|
||||
}
|
||||
|
|
@ -67,6 +69,98 @@ sub xpush($@) {
|
|||
return push(@$$ref, @_);
|
||||
}
|
||||
|
||||
#
|
||||
# Here we determine the set of possible [encoding, map, opcode] sets
|
||||
# for a given instruction, used to generate the disassembler tables.
|
||||
#
|
||||
# It is only necessary to take into account the following byte codes:
|
||||
# \[1234] mean literal bytes, of course
|
||||
# \1[0123] mean byte plus register value
|
||||
# \30[0123] 0F 1[8-F]
|
||||
# \35[01] REX2 prefix
|
||||
# \35[567] legacy map number
|
||||
# \26x \270 VEX prefix and map
|
||||
# \24x \250 EVEX prefix and map
|
||||
# prefixes ignored
|
||||
#
|
||||
my @skip_bytecode = ((0) x 256);
|
||||
map { $skip_bytecode[$_] = 1; }
|
||||
(05...07, 014...017, 0271...0273, 0310...0337,
|
||||
0341...0347, 0360...0372, 0374...0376);
|
||||
|
||||
# To assist with debugging...
|
||||
my %skipped_due_to;
|
||||
|
||||
# Create combinatorial sets of possible encodings
|
||||
sub genseqs($$$@) {
|
||||
my($flags, $enc, $map, @opcodes) = @_;
|
||||
my @encs = ($enc);
|
||||
|
||||
if ($enc == 0 && $map < 2 && $flags !~ /\bNO(?:APX|REX)\b/) {
|
||||
push(@encs, 4); # Allow REX2 encoding
|
||||
}
|
||||
|
||||
my @seqs = ();
|
||||
foreach my $enc (@encs) {
|
||||
push(@seqs, map { [$enc, $map, $_] } @opcodes);
|
||||
}
|
||||
|
||||
return @seqs;
|
||||
}
|
||||
|
||||
sub startseq($$) {
|
||||
my ($codestr,$flags) = @_;
|
||||
my $word;
|
||||
my @codes = ();
|
||||
my $c = $codestr;
|
||||
my($c0, $c1, $i);
|
||||
my $prefix = '';
|
||||
my $enc = 0; # Legacy
|
||||
my $map = 0; # Map 0
|
||||
|
||||
@codes = decodify(undef, $codestr, {});
|
||||
|
||||
while (defined($c0 = shift(@codes))) {
|
||||
$c1 = $codes[0]; # The immediate following code
|
||||
if ($c0 >= 01 && $c0 <= 04) {
|
||||
# Fixed byte string, this should be the opcode
|
||||
return genseqs($flags, $enc, $map, $c1);
|
||||
} elsif ($c0 >= 010 && $c0 <= 013) {
|
||||
return genseqs($flags, $enc, $map, $c1...($c1+7));
|
||||
} elsif (($c0 & ~013) == 0144) {
|
||||
return genseqs($flags, $enc, $map, $c1, $c1|2);
|
||||
} elsif (($c0 & ~3) == 0300) {
|
||||
return genseqs($flags, $enc, $map, 0x18...0x1f);
|
||||
} elsif ($c0 >= 0355 && $c0 <= 0357) {
|
||||
$map = $c0 - 0354;
|
||||
} elsif (($c0 & ~1) == 0350) {
|
||||
# REX2
|
||||
$enc = 4; # rex2 required
|
||||
} elsif (($c0 & ~3) == 0260 || $c0 == 0270) {
|
||||
# VEX/XOP
|
||||
my($cm,$wlp);
|
||||
$cm = shift(@codes);
|
||||
$wlp = shift(@codes);
|
||||
$enc = (($cm >> 6) & 1) + 1; # vex or xop
|
||||
$map = $cm & 31;
|
||||
} elsif (($c0 & ~3) == 0240 || $c0 == 0250) {
|
||||
# EVEX
|
||||
my @p;
|
||||
push(@p, shift(@codes));
|
||||
push(@p, shift(@codes));
|
||||
push(@p, shift(@codes));
|
||||
my $tuple = shift(@codes);
|
||||
$map = $p[0] & 7;
|
||||
$enc = 3; # evex
|
||||
} elsif (!$skip_bytecode[$c0]) {
|
||||
# This cannot be an opcode
|
||||
$skipped_due_to{$c0}++;
|
||||
last;
|
||||
}
|
||||
}
|
||||
return ();
|
||||
}
|
||||
|
||||
# Generate relaxed form patterns if applicable
|
||||
# * is used for an optional source operand, duplicating the previous one
|
||||
# in the encoding if it is missing.
|
||||
|
|
@ -447,6 +541,15 @@ if ( $output eq 'd' ) {
|
|||
print D "/* This file auto-generated from insns.dat by insns.pl" .
|
||||
" - don't edit it */\n\n";
|
||||
|
||||
my @skipped = sort { $a <=> $b } keys(%skipped_due_to);
|
||||
|
||||
if (scalar @skipped) {
|
||||
print D "/*\n";
|
||||
print D " * Note: skipped patterns due to byte codes:\n";
|
||||
print D " *", map { sprintf(' 0%o', $_) } @skipped;
|
||||
print D "\n */\n\n";
|
||||
}
|
||||
|
||||
print D "#include \"nasm.h\"\n";
|
||||
print D "#include \"insns.h\"\n\n";
|
||||
|
||||
|
|
@ -460,12 +563,12 @@ if ( $output eq 'd' ) {
|
|||
my @dinstname;
|
||||
for (my $c = 0; $c < $vex_classes; $c++) {
|
||||
push(@dinstname, []);
|
||||
for (my $m = 0; $m < $max_maps; $m++) {
|
||||
for (my $m = $map_base[$c]; $m <= $map_max[$c]; $m++) {
|
||||
my $ninst = scalar(keys %{$distable[$c][$m]});
|
||||
if (!$ninst) {
|
||||
push(@{$dinstname[$c]}, 'NULL');
|
||||
} else {
|
||||
my $tname = sprintf("itbl_%s%d", $vex_class[$c], $m);
|
||||
my $tname = sprintf("itbl_%s_map%d", $vex_class[$c], $m);
|
||||
push(@{$dinstname[$c]}, $tname);
|
||||
my @itbls = ();
|
||||
for (my $o = 0; $o < 256; $o++) {
|
||||
|
|
@ -491,13 +594,13 @@ if ( $output eq 'd' ) {
|
|||
}
|
||||
|
||||
print D "\nconst struct itemplate * const * const * const\n";
|
||||
print D "ndisasm_itable[NASM_VEX_CLASSES][NASM_MAX_MAPS] = {\n";
|
||||
print D "ndisasm_itable[] = {\n";
|
||||
for (my $c = 0; $c < $vex_classes; $c++) {
|
||||
print D " { /* ", $vex_class[$c], " */\n";
|
||||
for (my $m = 0; $m < $max_maps; $m++) {
|
||||
print D " ", $dinstname[$c][$m], ",\n";
|
||||
my $class = $vex_class[$c];
|
||||
printf D " /* ---- %s ---- */\n", $class;
|
||||
for (my $m = $map_start[$c]; $m <= $map_max[$c]; $m++) {
|
||||
printf D " /* %2d */ %s,\n", $m, $dinstname[$c][$m];
|
||||
}
|
||||
print D " },\n";
|
||||
}
|
||||
print D "};\n";
|
||||
|
||||
|
|
@ -528,7 +631,13 @@ if ( $output eq 'i' ) {
|
|||
print I "#define MAX_INSLEN ", $maxlen, "\n";
|
||||
print I "#define MAX_OPERANDS ", $MAX_OPERANDS, "\n";
|
||||
print I "#define NASM_VEX_CLASSES ", $vex_classes, "\n";
|
||||
print I "#define NASM_MAX_MAPS ", $max_maps, "\n";
|
||||
my $mapcnt = 0;
|
||||
for (my $c = 0; $c < $vex_classes; $c++) {
|
||||
printf I "#define MAP_BASE_%s (%d-%d)\n",
|
||||
uc($vex_class[$c]), $mapcnt, $map_start[$c];
|
||||
$mapcnt += $map_count[$c];
|
||||
}
|
||||
|
||||
print I "#define NO_DECORATOR\t{", join(',',(0) x $MAX_OPERANDS), "}\n";
|
||||
print I "\n#endif /* NASM_INSNSI_H */\n";
|
||||
|
||||
|
|
@ -596,6 +705,7 @@ sub format_insn($$$$) {
|
|||
my ($num, $flagsindex);
|
||||
my @bytecode;
|
||||
my ($op, @ops, @opsize, $opp, @opx, @oppx, @decos, @opevex);
|
||||
my %oppos;
|
||||
|
||||
return (undef, undef) if $operands eq 'ignore';
|
||||
|
||||
|
|
@ -606,12 +716,12 @@ sub format_insn($$$$) {
|
|||
set_implied_flags(\%flags);
|
||||
|
||||
# Generate byte code. This may modify the flags.
|
||||
@bytecode = (decodify($opcode, $codes, \%flags), 0);
|
||||
@bytecode = (decodify($opcode, $codes, \%flags, \%oppos), 0);
|
||||
push(@bytecode_list, [@bytecode]);
|
||||
$codes = hexstr(@bytecode);
|
||||
count_bytecodes(@bytecode);
|
||||
|
||||
my $nd = !!$flags{'ND'};
|
||||
my $nd = !!($flags{'ND'} || $flags{'PSEUDO'});
|
||||
delete $flags{'ND'};
|
||||
|
||||
# format the operands
|
||||
|
|
@ -621,6 +731,7 @@ sub format_insn($$$$) {
|
|||
@opsize = ();
|
||||
@decos = ();
|
||||
if ($operands ne 'void') {
|
||||
my $opnum = scalar(@ops);
|
||||
foreach $op (split(/,/, $operands)) {
|
||||
my $iszero = 0;
|
||||
my $opsz = 0;
|
||||
|
|
@ -663,6 +774,10 @@ sub format_insn($$$$) {
|
|||
# Register numbers >= 16 disallowed
|
||||
push(@oppx, 'rn_l16');
|
||||
}
|
||||
if ($isreg && $isvec &&
|
||||
defined($oppos->{'b'}) && $opnum == $oppos->{'b'}) {
|
||||
$flags{'MOPVEC'}++;
|
||||
}
|
||||
push(@opx, $opp, @oppx) if $opp;
|
||||
}
|
||||
$op = join('|', @opx);
|
||||
|
|
@ -852,68 +967,6 @@ sub hexstr(@) {
|
|||
return $s;
|
||||
}
|
||||
|
||||
# Here we determine the set of possible [encoding, map, opcode] sets
|
||||
# for a given instruction. We need only consider the codes:
|
||||
# \[1234] mean literal bytes, of course
|
||||
# \1[0123] mean byte plus register value
|
||||
# \35[567] legacy map number
|
||||
# \26x \270 VEX prefix and map
|
||||
# \24x \250 EVEX prefix and map
|
||||
# prefixes ignored
|
||||
my @ignore_bytecodes = (05...07, 014...017, 0271...0273, 0310...0337,
|
||||
0341...0351, 0360...0372, 0374..0376);
|
||||
my @ignore_bytecode = (0 x 256);
|
||||
foreach my $pfx (@ignore_bytecodes) {
|
||||
$ignore_bytecode[$pfx] = 1;
|
||||
}
|
||||
|
||||
sub startseq($) {
|
||||
my ($codestr) = @_;
|
||||
my $word;
|
||||
my @codes = ();
|
||||
my $c = $codestr;
|
||||
my($c0, $c1, $i);
|
||||
my $prefix = '';
|
||||
my $enc = 0; # Legacy
|
||||
my $map = 0; # Map 0
|
||||
|
||||
@codes = decodify(undef, $codestr, {});
|
||||
|
||||
while (defined($c0 = shift(@codes))) {
|
||||
$c1 = $codes[0];
|
||||
if ($c0 >= 01 && $c0 <= 04) {
|
||||
# Fixed byte string, this should be the opcode
|
||||
return ([$enc, $map, $c1]);
|
||||
} elsif ($c0 >= 010 && $c0 <= 013) {
|
||||
return map { [$enc, $map, $_] } ($c1..($c1+7));
|
||||
} elsif (($c0 & ~013) == 0144) {
|
||||
return map { [$enc, $map, $_] } ($c1, $c1|2);
|
||||
} elsif ($c0 >= 0355 && $c0 <= 0357) {
|
||||
$map = $c0 - 0354;
|
||||
} elsif (($c0 & ~3) == 0260 || $c0 == 0270) {
|
||||
# VEX/XOP
|
||||
my($cm,$wlp);
|
||||
$cm = shift(@codes);
|
||||
$wlp = shift(@codes);
|
||||
$enc = ($cm >> 6) + 1; # vex or xop
|
||||
$map = $cm & 31;
|
||||
} elsif (($c0 & ~3) == 0240 || $c0 == 0250) {
|
||||
# EVEX
|
||||
my @p;
|
||||
push(@p, shift(@codes));
|
||||
push(@p, shift(@codes));
|
||||
push(@p, shift(@codes));
|
||||
my $tuple = shift(@codes);
|
||||
$map = $p[0] & 7;
|
||||
$enc = 3; # evex
|
||||
} elsif (!$ignore_bytecode[$c0]) {
|
||||
# This cannot be an opcode
|
||||
last;
|
||||
}
|
||||
}
|
||||
return ();
|
||||
}
|
||||
|
||||
# EVEX tuple types offset is 0300. e.g. 0301 is for full vector(fv).
|
||||
sub tupletype($) {
|
||||
my ($tuplestr) = @_;
|
||||
|
|
@ -965,13 +1018,12 @@ sub tupletype($) {
|
|||
# For an operand that should be filled into more than one field,
|
||||
# enter it as e.g. "r+v".
|
||||
#
|
||||
sub byte_code_compile($$$) {
|
||||
my($opcode, $str, $flags) = @_;
|
||||
sub byte_code_compile($$$$) {
|
||||
my($opcode, $str, $flags, $oppos) = @_;
|
||||
my $opr;
|
||||
my $opc;
|
||||
my @codes = ();
|
||||
my $litix = undef;
|
||||
my %oppos = ();
|
||||
my $i;
|
||||
my ($op, $oq);
|
||||
my $opex;
|
||||
|
|
@ -1067,12 +1119,13 @@ sub byte_code_compile($$$) {
|
|||
$opc = lc($4);
|
||||
|
||||
$op = 0;
|
||||
$oppos = {};
|
||||
for ($i = 0; $i < length($opr); $i++) {
|
||||
my $c = substr($opr,$i,1);
|
||||
if ($c eq '+') {
|
||||
$op--;
|
||||
} else {
|
||||
$oppos{$c} = $op++;
|
||||
$oppos->{$c} = $op++;
|
||||
}
|
||||
}
|
||||
$tup = tupletype($tuple);
|
||||
|
|
@ -1130,30 +1183,30 @@ sub byte_code_compile($$$) {
|
|||
}
|
||||
$prefix_ok = 0;
|
||||
} elsif ($op eq '/r') {
|
||||
if (!defined($oppos{'r'}) || !defined($oppos{'m'})) {
|
||||
if (!defined($oppos->{'r'}) || !defined($oppos->{'m'})) {
|
||||
die "$fname:$line: $opcode: $op requires r and m operands\n";
|
||||
}
|
||||
$opex = (($oppos{'m'} & 4) ? 06 : 0) |
|
||||
(($oppos{'r'} & 4) ? 05 : 0);
|
||||
$opex = (($oppos->{'m'} & 4) ? 06 : 0) |
|
||||
(($oppos->{'r'} & 4) ? 05 : 0);
|
||||
push(@codes, $opex) if ($opex);
|
||||
# if mib is composed with two separate operands - ICC style
|
||||
push(@codes, 014 + ($oppos{'x'} & 3)) if (defined($oppos{'x'}));
|
||||
push(@codes, 0100 + (($oppos{'m'} & 3) << 3) + ($oppos{'r'} & 3));
|
||||
push(@codes, 014 + ($oppos->{'x'} & 3)) if (defined($oppos->{'x'}));
|
||||
push(@codes, 0100 + (($oppos->{'m'} & 3) << 3) + ($oppos->{'r'} & 3));
|
||||
$prefix_ok = 0;
|
||||
} elsif ($op =~ m:^/([0-7])$:) {
|
||||
if (!defined($oppos{'m'})) {
|
||||
if (!defined($oppos->{'m'})) {
|
||||
die "$fname:$line: $opcode: $op requires an m operand\n";
|
||||
}
|
||||
push(@codes, 06) if ($oppos{'m'} & 4);
|
||||
push(@codes, 0200 + (($oppos{'m'} & 3) << 3) + $1);
|
||||
push(@codes, 06) if ($oppos->{'m'} & 4);
|
||||
push(@codes, 0200 + (($oppos->{'m'} & 3) << 3) + $1);
|
||||
$prefix_ok = 0;
|
||||
} elsif ($op =~ m:^/([0-3]?)r([0-7])$:) {
|
||||
if (!defined($oppos{'r'})) {
|
||||
if (!defined($oppos->{'r'})) {
|
||||
die "$fname:$line: $opcode: $op requires an r operand\n";
|
||||
}
|
||||
push(@codes, 05) if ($oppos{'r'} & 4);
|
||||
push(@codes, 05) if ($oppos->{'r'} & 4);
|
||||
push(@codes, 0171);
|
||||
push(@codes, (($1+0) << 6) + (($oppos{'r'} & 3) << 3) + $2);
|
||||
push(@codes, (($1+0) << 6) + (($oppos->{'r'} & 3) << 3) + $2);
|
||||
$prefix_ok = 0;
|
||||
} elsif ($op =~ /^(vex|xop)(|\..*)$/) {
|
||||
my $vexname = $1;
|
||||
|
|
@ -1228,7 +1281,7 @@ sub byte_code_compile($$$) {
|
|||
} elsif ($oq =~ /^(m|map)([0-9]+)$/) {
|
||||
$m = $2+0;
|
||||
} elsif ($oq eq 'nds' || $oq eq 'ndd' || $oq eq 'dds') {
|
||||
if (!defined($oppos{'v'})) {
|
||||
if (!defined($oppos->{'v'})) {
|
||||
die "$fname:$line: $opcode: $vexname.$oq without 'v' operand\n";
|
||||
}
|
||||
$has_nds = 1;
|
||||
|
|
@ -1249,8 +1302,8 @@ sub byte_code_compile($$$) {
|
|||
if ($m < $minmap || $m > 31) {
|
||||
die "$fname:$line: $opcode: Only maps ${minmap}-31 are valid for \U${vexname}\n";
|
||||
}
|
||||
push(@codes, 05) if ($oppos{'v'} > 3);
|
||||
push(@codes, defined($oppos{'v'}) ? 0260+$oppos{'v'} : 0270,
|
||||
push(@codes, 05) if ($oppos->{'v'} > 3);
|
||||
push(@codes, defined($oppos->{'v'}) ? 0260+$oppos->{'v'} : 0270,
|
||||
($c << 6)+$m, ($w << 7)+($l << 2)+$p);
|
||||
|
||||
push(@codes, $opsize) if (defined($opsize));
|
||||
|
|
@ -1357,7 +1410,7 @@ sub byte_code_compile($$$) {
|
|||
# Set .ND if {zu} prefix is present
|
||||
$flags->{'ZU_E'}++;
|
||||
} elsif ($oq =~ /^(nds|ndd|nd|dds)$/) {
|
||||
if (!defined($oppos{'v'})) {
|
||||
if (!defined($oppos->{'v'})) {
|
||||
die "$fname:$line: $opcode: evex.$oq without 'v' operand\n";
|
||||
}
|
||||
$nds = 1;
|
||||
|
|
@ -1377,7 +1430,7 @@ sub byte_code_compile($$$) {
|
|||
}
|
||||
foreach my $bad (@bad_op) {
|
||||
my($what, $because) = @$inv;
|
||||
if (defined($oppos{$what})) {
|
||||
if (defined($oppos->{$what})) {
|
||||
die "$fname:$line: $opcode: $what and evex.$because are mutually incompatible\n";
|
||||
}
|
||||
}
|
||||
|
|
@ -1395,8 +1448,8 @@ sub byte_code_compile($$$) {
|
|||
$p[2] |= 0x04 if ($nf);
|
||||
$p[2] |= 0x10 if ($nd);
|
||||
|
||||
push(@codes, 05) if ($oppos{'v'} > 3);
|
||||
push(@codes, defined($oppos{'v'}) ? 0240+$oppos{'v'} : 0250, @p);
|
||||
push(@codes, 05) if ($oppos->{'v'} > 3);
|
||||
push(@codes, defined($oppos->{'v'}) ? 0240+$oppos->{'v'} : 0250, @p);
|
||||
push(@codes, $tup);
|
||||
|
||||
push(@codes, $opsize) if (defined($opsize));
|
||||
|
|
@ -1434,39 +1487,39 @@ sub byte_code_compile($$$) {
|
|||
die "$fname:$line: $opcode: too many immediate operands\n";
|
||||
}
|
||||
}
|
||||
if (!defined($oppos{$last_imm})) {
|
||||
if (!defined($oppos->{$last_imm})) {
|
||||
die "$fname:$line: $opcode: $op without '$last_imm' operand\n";
|
||||
}
|
||||
push(@codes, 05) if ($oppos{$last_imm} & 4);
|
||||
push(@codes, $imm_codes{$op} + ($oppos{$last_imm} & 3));
|
||||
push(@codes, 05) if ($oppos->{$last_imm} & 4);
|
||||
push(@codes, $imm_codes{$op} + ($oppos->{$last_imm} & 3));
|
||||
$prefix_ok = 0;
|
||||
} elsif ($op eq '/is4') {
|
||||
if (!defined($oppos{'s'})) {
|
||||
if (!defined($oppos->{'s'})) {
|
||||
die "$fname:$line: $opcode: $op without 's' operand\n";
|
||||
}
|
||||
if (defined($oppos{'i'})) {
|
||||
push(@codes, 0172, ($oppos{'s'} << 3)+$oppos{'i'});
|
||||
if (defined($oppos->{'i'})) {
|
||||
push(@codes, 0172, ($oppos->{'s'} << 3)+$oppos->{'i'});
|
||||
} else {
|
||||
push(@codes, 05) if ($oppos{'s'} & 4);
|
||||
push(@codes, 0174+($oppos{'s'} & 3));
|
||||
push(@codes, 05) if ($oppos->{'s'} & 4);
|
||||
push(@codes, 0174+($oppos->{'s'} & 3));
|
||||
}
|
||||
$prefix_ok = 0;
|
||||
} elsif ($op =~ /^\/is4\=([0-9]+)$/) {
|
||||
my $imm = $1;
|
||||
if (!defined($oppos{'s'})) {
|
||||
if (!defined($oppos->{'s'})) {
|
||||
die "$fname:$line: $opcode: $op without 's' operand\n";
|
||||
}
|
||||
if ($imm < 0 || $imm > 15) {
|
||||
die "$fname:$line: $opcode: invalid imm4 value for $op: $imm\n";
|
||||
}
|
||||
push(@codes, 0173, ($oppos{'s'} << 4) + $imm);
|
||||
push(@codes, 0173, ($oppos->{'s'} << 4) + $imm);
|
||||
$prefix_ok = 0;
|
||||
} elsif ($op =~ /^([0-9a-f]{2})\+r$/) {
|
||||
if (!defined($oppos{'r'})) {
|
||||
if (!defined($oppos->{'r'})) {
|
||||
die "$fname:$line: $opcode: $op without 'r' operand\n";
|
||||
}
|
||||
push(@codes, 05) if ($oppos{'r'} & 4);
|
||||
push(@codes, 010 + ($oppos{'r'} & 3), hex $1);
|
||||
push(@codes, 05) if ($oppos->{'r'} & 4);
|
||||
push(@codes, 010 + ($oppos->{'r'} & 3), hex $1);
|
||||
$prefix_ok = 0;
|
||||
} elsif ($op =~ /^(jcc|jmp)8$/) {
|
||||
# A relaxable jump instruction
|
||||
|
|
|
|||
19
x86/regs.dat
19
x86/regs.dat
|
|
@ -1,6 +1,6 @@
|
|||
## --------------------------------------------------------------------------
|
||||
##
|
||||
## Copyright 1996-2024 The NASM Authors - All Rights Reserved
|
||||
## Copyright 1996-2025 The NASM Authors - All Rights Reserved
|
||||
## See the file AUTHORS included with the NASM distribution for
|
||||
## the specific copyright holders.
|
||||
##
|
||||
|
|
@ -91,7 +91,7 @@ r8-31d REG32 reg32 8
|
|||
r8-31 REG64 reg64 8
|
||||
|
||||
# Segment registers
|
||||
es REG_ES sreg 0
|
||||
es REG_ES sreg 0 & 7
|
||||
cs REG_CS sreg 1
|
||||
ss REG_SS sreg 2
|
||||
ds REG_DS sreg 3
|
||||
|
|
@ -106,13 +106,13 @@ cr0-31 REG_CREG creg 0
|
|||
dr0-31 REG_DREG dreg 0
|
||||
|
||||
# Test registers
|
||||
tr0-7 REG_TREG treg 0
|
||||
tr0-7 REG_TREG treg 0 & 7
|
||||
|
||||
# Floating-point registers
|
||||
st0-7 FPUREG fpureg 0
|
||||
st0-7 FPUREG fpureg 0 & 7
|
||||
|
||||
# MMX registers
|
||||
mm0-7 MMXREG mmxreg 0
|
||||
mm0-7 MMXREG mmxreg 0 & 7
|
||||
|
||||
# SSE/AVX registers
|
||||
xmm0-31 XMMREG xmmreg 0
|
||||
|
|
@ -120,11 +120,12 @@ ymm0-31 YMMREG ymmreg 0
|
|||
zmm0-31 ZMMREG zmmreg 0
|
||||
|
||||
# AMX tile registers
|
||||
tmm0-7 TMMREG tmmreg 0
|
||||
tmm0-7 TMMREG tmmreg 0 & 7
|
||||
|
||||
# Opmask registers
|
||||
k0 OPMASKREG opmaskreg 0
|
||||
k0 OPMASKREG opmaskreg 0 & 7
|
||||
k1-7 OPMASKREG opmaskreg 1 TFLAG_BRC_OPT
|
||||
|
||||
# Bounds registers
|
||||
bnd0-3 BNDREG bndreg 0
|
||||
# Bounds registers (the mask here really is 7, not 3;
|
||||
# 4-7 were reserved encodings)
|
||||
bnd0-3 BNDREG bndreg 0 & 7
|
||||
|
|
|
|||
60
x86/regs.pl
60
x86/regs.pl
|
|
@ -1,7 +1,7 @@
|
|||
#!/usr/bin/perl
|
||||
## --------------------------------------------------------------------------
|
||||
##
|
||||
## Copyright 1996-2024 The NASM Authors - All Rights Reserved
|
||||
## Copyright 1996-2025 The NASM Authors - All Rights Reserved
|
||||
## See the file AUTHORS included with the NASM distribution for
|
||||
## the specific copyright holders.
|
||||
##
|
||||
|
|
@ -36,6 +36,14 @@
|
|||
# Read regs.dat and output regs.h and regs.c (included in names.c)
|
||||
#
|
||||
|
||||
use integer;
|
||||
|
||||
# For simplicity make all the disassembly tables the same size
|
||||
# This must be power of 2!
|
||||
my $distablesz = 32;
|
||||
|
||||
die if ($distablesz & ($distablesz-1)); # Not a power of 2?
|
||||
|
||||
$nline = 0;
|
||||
|
||||
sub toint($) {
|
||||
|
|
@ -48,13 +56,14 @@ sub process_line($) {
|
|||
my($line) = @_;
|
||||
my @v;
|
||||
|
||||
if ( $line !~ /^\s*(\S+)\s*(\S+)\s*(\S+)\s*([0-9]+)\s*(\S*)/i ) {
|
||||
if ( $line !~ /^\s*(\S+)\s*(\S+)\s*(\S+)\s*([0-9]+)\s*(?:\&\s*(0x[0-9a-f]+|[0-9]+))?/i ) {
|
||||
die "regs.dat:$nline: invalid input\n";
|
||||
}
|
||||
$reg = $1;
|
||||
$aclass = $2;
|
||||
$dclasses = $3;
|
||||
$x86regno = toint($4);
|
||||
$regmask = toint($5);
|
||||
|
||||
if ($reg =~ /^(.*[^0-9])([0-9]+)\-([0-9]+)(|[^0-9].*)$/) {
|
||||
$nregs = $3-$2+1;
|
||||
|
|
@ -68,15 +77,27 @@ sub process_line($) {
|
|||
undef $reg_suffix;
|
||||
}
|
||||
|
||||
foreach $dclass (split(/,/, $dclasses)) {
|
||||
if ( !defined($disclass{$dclass}) ) {
|
||||
$disclass{$dclass} = [];
|
||||
}
|
||||
if ($regmask) {
|
||||
if ($regmasks{$dclass} && $regmasks{$dclass} != $regmask) {
|
||||
die "regs.dat:$nline: inconsistent regmasks for disassembly class $dclass\n";
|
||||
}
|
||||
$regmasks{$dclass} = $regmask;
|
||||
}
|
||||
}
|
||||
|
||||
while ($nregs--) {
|
||||
$regs{$reg} = $aclass;
|
||||
$regvals{$reg} = $x86regno;
|
||||
|
||||
foreach $dclass (split(/,/, $dclasses)) {
|
||||
if ( !defined($disclass{$dclass}) ) {
|
||||
$disclass{$dclass} = [];
|
||||
}
|
||||
if ($x86regno >= $distablesz) {
|
||||
die "regs.dat:$nline: register number $x86regno too large, increase distablesz in regs.pl\n";
|
||||
}
|
||||
|
||||
foreach $dclass (split(/,/, $dclasses)) {
|
||||
$disclass{$dclass}->[$x86regno] = $reg;
|
||||
}
|
||||
|
||||
|
|
@ -97,6 +118,7 @@ sub process_line($) {
|
|||
%regs = ();
|
||||
%regvals = ();
|
||||
%disclass = ();
|
||||
%regmasks = ();
|
||||
open(REGS, '<', $file) or die "$0: Cannot open $file\n";
|
||||
while ( defined($line = <REGS>) ) {
|
||||
$nline++;
|
||||
|
|
@ -176,18 +198,17 @@ if ( $fmt eq 'h' ) {
|
|||
print "/* automatically generated from $file - do not edit */\n\n";
|
||||
print "#include \"regdis.h\"\n\n";
|
||||
foreach $class ( sort(keys(%disclass)) ) {
|
||||
printf "const enum reg_enum nasm_rd_%-8s[%2d] = {",
|
||||
$class, scalar @{$disclass{$class}};
|
||||
@foo = @{$disclass{$class}};
|
||||
@bar = ();
|
||||
for ( $i = 0 ; $i < scalar(@foo) ; $i++ ) {
|
||||
if (defined($foo[$i])) {
|
||||
push(@bar, "R_\U$foo[$i]\E");
|
||||
} else {
|
||||
die "$0: No register name for class $class, value $i\n";
|
||||
}
|
||||
die if (scalar @{$disclass{$class}} > $distablesz);
|
||||
$regmask = $regmasks{$class} || ($distablesz - 1);
|
||||
printf "const enum reg_enum nasm_rd_%s[DISREGTBLSZ] = {",
|
||||
$class;
|
||||
for ($i = 0; $i < $distablesz; $i++) {
|
||||
my $r = $disclass{$class}->[$i & $regmask];
|
||||
print "\n " if (!($i & 7));
|
||||
print ' ', defined($r) ? "R_\U$r" : '0';
|
||||
print ',' unless ($i == $distablesz - 1);
|
||||
}
|
||||
print join(',', @bar), "};\n";
|
||||
print "\n};\n";
|
||||
}
|
||||
} elsif ( $fmt eq 'dh' ) {
|
||||
# Output regdis.h
|
||||
|
|
@ -195,9 +216,10 @@ if ( $fmt eq 'h' ) {
|
|||
print "#ifndef NASM_REGDIS_H\n";
|
||||
print "#define NASM_REGDIS_H\n\n";
|
||||
print "#include \"regs.h\"\n\n";
|
||||
printf "#define DISREGTBLSZ %d\n\n", $distablesz;
|
||||
foreach $class ( sort(keys(%disclass)) ) {
|
||||
printf "extern const enum reg_enum nasm_rd_%-8s[%2d];\n",
|
||||
$class, scalar @{$disclass{$class}};
|
||||
printf "extern const enum reg_enum nasm_rd_%s[DISREGTBLSZ];\n",
|
||||
$class;
|
||||
}
|
||||
print "\n#endif /* NASM_REGDIS_H */\n";
|
||||
} else {
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue