Skip to content

Commit c4d820b

Browse files
committed
Fix displacement size compression not affecting ModRM (fixes #33)
1 parent 4ca9caf commit c4d820b

File tree

2 files changed

+32
-23
lines changed

2 files changed

+32
-23
lines changed

core/instructions.js

Lines changed: 28 additions & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -423,7 +423,7 @@ export class Instruction extends Statement
423423
else if(op.rm !== null)
424424
{
425425
let extraRex;
426-
[extraRex, modRM, sib] = this.makeModRM(op.rm, op.reg);
426+
[extraRex, modRM, sib] = this.makeModRM(op.rm, op.reg, op.dispMul !== null ? 32 : null);
427427
if(extraRex !== 0)
428428
rexVal |= extraRex, prefsToGen.REX = true;
429429
}
@@ -437,6 +437,8 @@ export class Instruction extends Statement
437437
prefsToGen.DATASIZE = true;
438438

439439
// Time to generate!
440+
let modRmIndex = 0;
441+
440442
if(prefsToGen.SEG0) this.genByte(0x26);
441443
if(prefsToGen.SEG1) this.genByte(0x2E);
442444
if(prefsToGen.SEG2) this.genByte(0x36);
@@ -470,10 +472,12 @@ export class Instruction extends Statement
470472
this.genByte(opcode >> 8);
471473
}
472474
this.genByte(opcode);
473-
if(modRM !== null)
475+
if(modRM !== null) {
476+
modRmIndex = this.length;
474477
this.genByte(modRM);
475-
if(sib !== null)
476-
this.genByte(sib);
478+
if(sib !== null)
479+
this.genByte(sib);
480+
}
477481

478482
// Generating the displacement
479483
if(op.rm?.value?.addend != null)
@@ -493,12 +497,16 @@ export class Instruction extends Statement
493497
}));
494498
this.ipRelative = true;
495499
}
496-
this.genValue(value, {
500+
const finalSize = this.genValue(value, {
497501
size: op.rm.dispSize || 32,
498502
signed: true,
499503
sizeRelative,
500504
dispMul: op.dispMul
501505
});
506+
if(op.rm.dispSize != finalSize) {
507+
op.rm.dispSize = finalSize;
508+
this.bytes[modRmIndex] = this.makeModRM(op.rm, op.reg, finalSize)[1];
509+
}
502510
}
503511
if(op.relImm !== null)
504512
this.genValue(op.relImm.value, { size: op.relImm.size, sizeRelative: true, functionAddr: true });
@@ -513,24 +521,22 @@ export class Instruction extends Statement
513521

514522
/** Generate the ModRM byte
515523
* @param {Operand} rm
516-
* @param {Operand} r */
517-
makeModRM(rm, r)
518-
{
524+
* @param {Operand} r
525+
* @param {int?} forcedDispSize */
526+
makeModRM(rm, r, forcedDispSize) {
519527
let modrm = 0, rex = 0, sib = null;
520528
// rm's and r's values may be edited, however the objects themselves shouldn't be modified
521529
let rmReg = rm.reg, rmReg2 = rm.reg2, rReg = r.reg;
522530

523531
// Encoding the "reg" field
524-
if(rReg >= 8)
525-
{
532+
if(rReg >= 8) {
526533
rex |= 4; // rex.R extension
527534
rReg &= 7;
528535
}
529536
modrm |= rReg << 3;
530537

531538
// Special case for RIP-relative addressing
532-
if(rm.ripRelative)
533-
{
539+
if(rm.ripRelative) {
534540
rm.value.addend = rm.value.addend || 0n;
535541
// mod = 00, reg = (reg), rm = 101
536542
return [rex, modrm | 5, null];
@@ -539,19 +545,20 @@ export class Instruction extends Statement
539545
// Encoding the "mod" (modifier) field
540546
if(!rm.type.isMemory)
541547
modrm |= 0xC0; // mod=11
542-
else if(rmReg >= 0)
543-
{
544-
if(rm.value.addend != null)
545-
{
546-
this.determineDispSize(rm, 8, 32);
548+
else if(rmReg >= 0) {
549+
if(rm.value.addend != null) {
550+
if(forcedDispSize != null)
551+
rm.dispSize = forcedDispSize;
552+
else
553+
this.determineDispSize(rm, 8, 32);
554+
547555
if(rm.dispSize == 8)
548556
modrm |= 0x40; // mod=01
549557
else
550558
modrm |= 0x80; // mod=10
551559
}
552560
}
553-
else // mod = 00
554-
{
561+
else { // mod = 00
555562
// These are the respective "none" type registers
556563
rmReg = 5;
557564
if(currBitness == 64 && rmReg2 < 0)
@@ -567,12 +574,10 @@ export class Instruction extends Statement
567574
modrm |= rmReg2 < 0 ? rmReg : 4;
568575

569576
// Encoding an SIB byte if necessary
570-
if((modrm & 0xC0) != 0xC0 && (modrm & 7) == 4) // mod!=11, rm=100 signifies an SIB byte follows
571-
{
577+
if((modrm & 0xC0) != 0xC0 && (modrm & 7) == 4) { // mod!=11, rm=100 signifies an SIB byte follows
572578
if(rmReg2 < 0)
573579
rmReg2 = 4; // indicating the "none" index
574-
else if(rmReg2 >= 8)
575-
{
580+
else if(rmReg2 >= 8) {
576581
rex |= 2; // rex.X extension
577582
rmReg2 &= 7;
578583
}

core/statement.js

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -181,6 +181,7 @@ export class Statement
181181
/**
182182
* @param {import("./shuntingYard.js").IdentifierValue} value
183183
* @param {ValueConfig} config
184+
* @returns {number} The number of bits generated
184185
*/
185186
genValue(value, {
186187
size,
@@ -226,11 +227,14 @@ export class Statement
226227
for(const lineEnd of value.lineEnds)
227228
this.lineEnds.push(this.length + Math.min(lineEnd, size / 8));
228229

230+
const finalSize = size;
229231
do
230232
{
231233
this.genByte(num & 0xffn);
232234
num >>= 8n;
233235
} while(size -= 8);
236+
237+
return finalSize;
234238
}
235239

236240
remove()

0 commit comments

Comments
 (0)