Skip to content

Commit

Permalink
Merge pull request #5739 from WalterWaldron/fix13147
Browse files Browse the repository at this point in the history
Fix issue 15999 - Inline assembly incorrect sign extension instead of…
  • Loading branch information
WalterBright committed Jul 6, 2016
2 parents 4896230 + cb1911c commit 702c543
Show file tree
Hide file tree
Showing 4 changed files with 99 additions and 18 deletions.
58 changes: 40 additions & 18 deletions src/iasm.c
Expand Up @@ -494,7 +494,6 @@ static PTRNTAB asm_classify(OP *pop, OPND *popnd1, OPND *popnd2,
opflag_t opflags2 = 0;
opflag_t opflags3 = 0;
opflag_t opflags4 = 0;
bool bFake = false;
bool bInvalid64bit = false;

bool bMatch1, bMatch2, bMatch3, bMatch4, bRetry = false;
Expand Down Expand Up @@ -710,25 +709,48 @@ static PTRNTAB asm_classify(OP *pop, OPND *popnd1, OPND *popnd2,
{
//printf("match\n");

/* If they both match and the first op in the table is not AL
* or size of 8 and the second is immediate 8,
* then check to see if the constant
* is a signed 8 bit constant. If so, then do not match, otherwise match
/* Don't match if implicit sign-extension will
* change the value of the immediate operand
*/
if (!bRetry &&
!((ASM_GET_uSizemask(table2->usOp1) & _8) ||
(ASM_GET_uRegmask(table2->usOp1) & _al)) &&
(ASM_GET_aopty(table2->usOp2) == _imm) &&
(ASM_GET_uSizemask(table2->usOp2) & _8))
if (!bRetry && ASM_GET_aopty(table2->usOp2) == _imm)
{

if (popnd2->disp <= SCHAR_MAX)
break;
else
bFake = true;
int op1size = ASM_GET_uSizemask(table2->usOp1);
if (!op1size) // implicit register operand
{
switch (ASM_GET_uRegmask(table2->usOp1))
{
case ASM_GET_uRegmask(_al):
case ASM_GET_uRegmask(_cl): op1size = _8; break;
case ASM_GET_uRegmask(_ax):
case ASM_GET_uRegmask(_dx): op1size = _16; break;
case ASM_GET_uRegmask(_eax): op1size = _32; break;
case ASM_GET_uRegmask(_rax): op1size = _64; break;
default:
assert(0);
}
}
if (op1size > ASM_GET_uSizemask(table2->usOp2))
{
switch(ASM_GET_uSizemask(table2->usOp2))
{
case _8:
if (popnd2->disp > SCHAR_MAX)
continue;
break;
case _16:
if (popnd2->disp > SHRT_MAX)
continue;
break;
case _32:
if (popnd2->disp > INT_MAX)
continue;
break;
default:
assert(0);
}
}
}
else
break;
break;
}
if (asmstate.ucItype == ITopt ||
asmstate.ucItype == ITfloat)
Expand Down Expand Up @@ -970,7 +992,7 @@ static PTRNTAB asm_classify(OP *pop, OPND *popnd1, OPND *popnd2,
}
}
RETURN_IT:
if (bRetry && !bFake)
if (bRetry)
{
asmerr("bad type/size of operands '%s'", asm_opstr(pop));
}
Expand Down
12 changes: 12 additions & 0 deletions test/fail_compilation/fail15999.d
@@ -0,0 +1,12 @@
// REQUIRED_ARGS: -m64
/*
TEST_OUTPUT:
---
fail_compilation/fail15999.d(11): Error: bad type/size of operands 'and'
---
*/

void foo(ulong bar)
{
asm { and RAX, 0x00000000FFFFFFFF; ret; }
}
12 changes: 12 additions & 0 deletions test/fail_compilation/fail15999b.d
@@ -0,0 +1,12 @@
// REQUIRED_ARGS: -m64
/*
TEST_OUTPUT:
---
fail_compilation/fail15999b.d(11): Error: bad type/size of operands 'and'
---
*/

void foo(ulong bar)
{
asm { and RAX, 0xFFFFFFFF00000000; ret; }
}
35 changes: 35 additions & 0 deletions test/runnable/iasm64.d
Expand Up @@ -6663,6 +6663,40 @@ L1: pop RAX;

/****************************************************/

void test15999()
{
int x;
ubyte* p;
static ubyte data[] =
[
0x48, 0x83, 0xE0, 0xFF,
0x83, 0xE0, 0xFF,
0x48, 0x25, 0x00, 0x00, 0x00, 0x80,
0xC3
];

asm
{
call L1 ;

and RAX, -1;
and EAX, -1;
and RAX, 0xFFFF_FFFF_8000_0000;
ret;

L1: pop RAX;
mov p[RBP],RAX;
}

foreach (ref i, b; data)
{
//printf("data[%d] = 0x%02x, should be 0x%02x\n", i, p[i], b);
assert(p[i] == b);
}
}

/****************************************************/

int main()
{
printf("Testing iasm64.d\n");
Expand Down Expand Up @@ -6734,6 +6768,7 @@ int main()
test9965();
test12849();
test12968();
test15999();
testconst();

printf("Success\n");
Expand Down

0 comments on commit 702c543

Please sign in to comment.