@@ -2965,7 +2965,7 @@ static ZyanStatus ZydisFindMatchingDefinition(const ZydisEncoderRequest *request
2965
2965
}
2966
2966
}
2967
2967
else if ((request -> machine_mode != ZYDIS_MACHINE_MODE_LONG_64 ) &&
2968
- (definition -> encoding == ZYDIS_INSTRUCTION_ENCODING_MVEX ))
2968
+ (definition -> encoding == ZYDIS_INSTRUCTION_ENCODING_MVEX ))
2969
2969
{
2970
2970
continue ;
2971
2971
}
@@ -4275,6 +4275,33 @@ static ZyanStatus ZydisEncoderCheckRequestSanity(const ZydisEncoderRequest *requ
4275
4275
return ZYAN_STATUS_SUCCESS ;
4276
4276
}
4277
4277
4278
+ /**
4279
+ * Encodes instruction with semantics specified in encoder request structure.
4280
+ *
4281
+ * @param request A pointer to the `ZydisEncoderRequest` struct. Must be validated before
4282
+ * calling this function.
4283
+ * @param buffer A pointer to the output buffer receiving encoded instruction.
4284
+ * @param length A pointer to the variable containing length of the output buffer. Upon
4285
+ * successful return this variable receives length of the encoded instruction.
4286
+ * @param instruction Internal state of the encoder.
4287
+ *
4288
+ * @return A zyan status code.
4289
+ */
4290
+ static ZyanStatus ZydisEncoderEncodeInstructionInternal (const ZydisEncoderRequest * request ,
4291
+ void * buffer , ZyanUSize * length , ZydisEncoderInstruction * instruction )
4292
+ {
4293
+ ZydisEncoderInstructionMatch match ;
4294
+ ZYAN_CHECK (ZydisFindMatchingDefinition (request , & match ));
4295
+ ZydisEncoderBuffer output ;
4296
+ output .buffer = (ZyanU8 * )buffer ;
4297
+ output .size = * length ;
4298
+ output .offset = 0 ;
4299
+ ZYAN_CHECK (ZydisBuildInstruction (& match , instruction ));
4300
+ ZYAN_CHECK (ZydisEmitInstruction (instruction , & output ));
4301
+ * length = output .offset ;
4302
+ return ZYAN_STATUS_SUCCESS ;
4303
+ }
4304
+
4278
4305
/* ============================================================================================== */
4279
4306
/* Exported functions */
4280
4307
/* ============================================================================================== */
@@ -4288,17 +4315,212 @@ ZYDIS_EXPORT ZyanStatus ZydisEncoderEncodeInstruction(const ZydisEncoderRequest
4288
4315
}
4289
4316
ZYAN_CHECK (ZydisEncoderCheckRequestSanity (request ));
4290
4317
4291
- ZydisEncoderInstructionMatch match ;
4292
- ZYAN_CHECK (ZydisFindMatchingDefinition (request , & match ));
4293
- ZydisEncoderBuffer output ;
4294
- output .buffer = (ZyanU8 * )buffer ;
4295
- output .size = * length ;
4296
- output .offset = 0 ;
4297
4318
ZydisEncoderInstruction instruction ;
4298
- ZYAN_CHECK (ZydisBuildInstruction (& match , & instruction ));
4299
- ZYAN_CHECK (ZydisEmitInstruction (& instruction , & output ));
4319
+ return ZydisEncoderEncodeInstructionInternal (request , buffer , length , & instruction );
4320
+ }
4321
+
4322
+ ZYDIS_EXPORT ZyanStatus ZydisEncoderEncodeInstructionAbsolute (ZydisEncoderRequest * request ,
4323
+ void * buffer , ZyanUSize * length , ZyanU64 runtime_address )
4324
+ {
4325
+ if (!request || !buffer || !length )
4326
+ {
4327
+ return ZYAN_STATUS_INVALID_ARGUMENT ;
4328
+ }
4329
+ ZYAN_CHECK (ZydisEncoderCheckRequestSanity (request ));
4330
+
4331
+ const ZydisEncoderRelInfo * rel_info = ZydisGetRelInfo (request -> mnemonic );
4332
+ ZydisEncoderOperand * op_rip_rel = ZYAN_NULL ;
4333
+ ZyanBool adjusted_rel = ZYAN_FALSE ;
4334
+ ZyanU64 absolute_address = 0 ;
4335
+ ZyanU8 mode_index = ZydisGetMachineModeWidth (request -> machine_mode ) >> 5 ;
4336
+ for (ZyanU8 i = 0 ; i < request -> operand_count ; ++ i )
4337
+ {
4338
+ ZydisEncoderOperand * op = & request -> operands [i ];
4339
+ if ((op -> type == ZYDIS_OPERAND_TYPE_IMMEDIATE ) && rel_info )
4340
+ {
4341
+ if (adjusted_rel )
4342
+ {
4343
+ return ZYAN_STATUS_INVALID_ARGUMENT ;
4344
+ }
4345
+
4346
+ switch (rel_info -> accepts_scaling_hints )
4347
+ {
4348
+ case ZYDIS_SIZE_HINT_NONE :
4349
+ case ZYDIS_SIZE_HINT_OSZ :
4350
+ {
4351
+ static const ZyanI8 asz_priority [3 ][3 ] =
4352
+ {
4353
+ { 0 , 1 , 2 },
4354
+ { 0 , 2 , 1 },
4355
+ { 0 , 2 , -1 },
4356
+ };
4357
+ static const ZyanI8 osz_priority [3 ][3 ] =
4358
+ {
4359
+ { 0 , 1 , 2 },
4360
+ { 0 , 2 , 1 },
4361
+ { 0 , 2 , 1 },
4362
+ };
4363
+ ZyanI8 forced_priority_row [3 ] = { -1 , -1 , -1 };
4364
+ ZyanI8 * priority_row = ZYAN_NULL ;
4365
+ ZyanU8 extra_length = 0 ;
4366
+ ZyanU8 start_offset = 0 ;
4367
+ if (rel_info -> accepts_scaling_hints == ZYDIS_SIZE_HINT_NONE )
4368
+ {
4369
+ if ((request -> branch_type == ZYDIS_BRANCH_TYPE_FAR ) ||
4370
+ (request -> branch_width == ZYDIS_BRANCH_WIDTH_64 ))
4371
+ {
4372
+ return ZYAN_STATUS_INVALID_ARGUMENT ;
4373
+ }
4374
+ if ((rel_info -> accepts_branch_hints ) &&
4375
+ (request -> prefixes & (ZYDIS_ATTRIB_HAS_BRANCH_NOT_TAKEN |
4376
+ ZYDIS_ATTRIB_HAS_BRANCH_TAKEN )))
4377
+ {
4378
+ extra_length = 1 ;
4379
+ }
4380
+ if (request -> branch_width == ZYDIS_BRANCH_WIDTH_NONE )
4381
+ {
4382
+ if (request -> branch_type == ZYDIS_BRANCH_TYPE_NEAR )
4383
+ {
4384
+ start_offset = 1 ;
4385
+ }
4386
+ priority_row = (ZyanI8 * )& asz_priority [mode_index ];
4387
+ }
4388
+ else
4389
+ {
4390
+ forced_priority_row [0 ] = request -> branch_width - 1 ;
4391
+ priority_row = (ZyanI8 * )& forced_priority_row ;
4392
+ }
4393
+ }
4394
+ else
4395
+ {
4396
+ if (request -> operand_size_hint == ZYDIS_OPERAND_SIZE_HINT_NONE )
4397
+ {
4398
+ priority_row = (ZyanI8 * )& osz_priority [mode_index ];
4399
+ }
4400
+ else
4401
+ {
4402
+ if (request -> operand_size_hint == ZYDIS_OPERAND_SIZE_HINT_64 )
4403
+ {
4404
+ extra_length = 1 ;
4405
+ forced_priority_row [0 ] = 2 ;
4406
+ }
4407
+ else
4408
+ {
4409
+ forced_priority_row [0 ] = request -> operand_size_hint - 1 ;
4410
+ }
4411
+ priority_row = (ZyanI8 * )& forced_priority_row ;
4412
+ }
4413
+ }
4414
+ ZYAN_ASSERT (ZYAN_ARRAY_LENGTH (asz_priority [0 ]) ==
4415
+ ZYAN_ARRAY_LENGTH (osz_priority [0 ]));
4416
+ for (ZyanU8 j = start_offset ; j < ZYAN_ARRAY_LENGTH (asz_priority [0 ]); ++ j )
4417
+ {
4418
+ ZyanI8 size_index = priority_row [j ];
4419
+ if (size_index < 0 )
4420
+ {
4421
+ break ;
4422
+ }
4423
+ ZyanU8 base_size = rel_info -> size [mode_index ][size_index ];
4424
+ if (base_size == 0 )
4425
+ {
4426
+ continue ;
4427
+ }
4428
+ ZyanU8 predicted_size = base_size + extra_length ;
4429
+ if (runtime_address > ZYAN_UINT64_MAX - predicted_size + 1 )
4430
+ {
4431
+ continue ;
4432
+ }
4433
+ ZyanI64 rel = (ZyanI64 )(op -> imm .u - (runtime_address + predicted_size ));
4434
+ ZyanU8 rel_size = ZydisGetSignedImmSize (rel );
4435
+ if (rel_size > (8 << size_index ))
4436
+ {
4437
+ continue ;
4438
+ }
4439
+ op -> imm .s = rel ;
4440
+ adjusted_rel = ZYAN_TRUE ;
4441
+ break ;
4442
+ }
4443
+ break ;
4444
+ }
4445
+ case ZYDIS_SIZE_HINT_ASZ :
4446
+ {
4447
+ static const ZyanI8 asz_prefix_lookup [3 ][ZYDIS_ADDRESS_SIZE_HINT_MAX_VALUE + 1 ] =
4448
+ {
4449
+ { 0 , 0 , 1 , -1 },
4450
+ { 0 , 1 , 0 , -1 },
4451
+ { 0 , -1 , 1 , 0 },
4452
+ };
4453
+ ZyanI8 extra_length = asz_prefix_lookup [mode_index ][request -> address_size_hint ];
4454
+ if (extra_length < 0 )
4455
+ {
4456
+ return ZYAN_STATUS_INVALID_ARGUMENT ;
4457
+ }
4458
+ ZyanU8 asz_index = (request -> address_size_hint == ZYDIS_ADDRESS_SIZE_HINT_NONE )
4459
+ ? mode_index
4460
+ : ZydisGetAszFromHint (request -> address_size_hint ) >> 5 ;
4461
+ ZYAN_ASSERT ((rel_info -> size [asz_index ][0 ] != 0 ) &&
4462
+ (rel_info -> size [asz_index ][1 ] == 0 ) &&
4463
+ (rel_info -> size [asz_index ][2 ] == 0 ) &&
4464
+ !rel_info -> accepts_branch_hints );
4465
+ ZyanU8 predicted_size = rel_info -> size [asz_index ][0 ] + extra_length ;
4466
+ if (runtime_address > ZYAN_UINT64_MAX - predicted_size + 1 )
4467
+ {
4468
+ return ZYAN_STATUS_INVALID_ARGUMENT ;
4469
+ }
4470
+ ZyanI64 rel = (ZyanI64 )(op -> imm .u - (runtime_address + predicted_size ));
4471
+ ZyanU8 rel_size = ZydisGetSignedImmSize (rel );
4472
+ if (rel_size > 8 )
4473
+ {
4474
+ return ZYAN_STATUS_INVALID_ARGUMENT ;
4475
+ }
4476
+ op -> imm .s = rel ;
4477
+ adjusted_rel = ZYAN_TRUE ;
4478
+ break ;
4479
+ }
4480
+ default :
4481
+ ZYAN_UNREACHABLE ;
4482
+ }
4483
+ if (!adjusted_rel )
4484
+ {
4485
+ return ZYAN_STATUS_INVALID_ARGUMENT ;
4486
+ }
4487
+ }
4488
+ else if ((op -> type == ZYDIS_OPERAND_TYPE_MEMORY ) &&
4489
+ ((op -> mem .base == ZYDIS_REGISTER_EIP ) ||
4490
+ (op -> mem .base == ZYDIS_REGISTER_RIP )))
4491
+ {
4492
+ if (op_rip_rel )
4493
+ {
4494
+ return ZYAN_STATUS_INVALID_ARGUMENT ;
4495
+ }
4496
+
4497
+ absolute_address = op -> mem .displacement ;
4498
+ op -> mem .displacement = 0 ;
4499
+ op_rip_rel = op ;
4500
+ }
4501
+ }
4502
+
4503
+ ZydisEncoderInstruction instruction ;
4504
+ ZYAN_CHECK (ZydisEncoderEncodeInstructionInternal (request , buffer , length , & instruction ));
4505
+ if (op_rip_rel )
4506
+ {
4507
+ ZyanUSize instruction_size = * length ;
4508
+ if (runtime_address > ZYAN_UINT64_MAX - instruction_size + 1 )
4509
+ {
4510
+ return ZYAN_STATUS_INVALID_ARGUMENT ;
4511
+ }
4512
+ ZyanI64 rip_rel = (ZyanI64 )(absolute_address - (runtime_address + instruction_size ));
4513
+ if (ZydisGetSignedImmSize (rip_rel ) > 32 )
4514
+ {
4515
+ return ZYAN_STATUS_INVALID_ARGUMENT ;
4516
+ }
4517
+ ZYAN_ASSERT (instruction .disp_size != 0 );
4518
+ ZyanU8 disp_offset = (instruction .disp_size >> 3 ) + (instruction .imm_size >> 3 );
4519
+ ZYAN_ASSERT (instruction_size > disp_offset );
4520
+ ZYAN_MEMCPY ((ZyanU8 * )buffer + instruction_size - disp_offset , & rip_rel , sizeof (ZyanI32 ));
4521
+ op_rip_rel -> mem .displacement = rip_rel ;
4522
+ }
4300
4523
4301
- * length = output .offset ;
4302
4524
return ZYAN_STATUS_SUCCESS ;
4303
4525
}
4304
4526
0 commit comments