Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
stenzek
GitHub Repository: stenzek/duckstation
Path: blob/master/dep/zydis/src/FormatterIntel.c
4211 views
1
/***************************************************************************************************
2
3
Zyan Disassembler Library (Zydis)
4
5
Original Author : Florian Bernd, Joel Hoener
6
7
* Permission is hereby granted, free of charge, to any person obtaining a copy
8
* of this software and associated documentation files (the "Software"), to deal
9
* in the Software without restriction, including without limitation the rights
10
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
11
* copies of the Software, and to permit persons to whom the Software is
12
* furnished to do so, subject to the following conditions:
13
*
14
* The above copyright notice and this permission notice shall be included in all
15
* copies or substantial portions of the Software.
16
*
17
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
18
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
19
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
20
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
21
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
22
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
23
* SOFTWARE.
24
25
***************************************************************************************************/
26
27
#include <Zydis/Internal/FormatterIntel.h>
28
#include <Zydis/Utils.h>
29
#include <Zycore/Format.h>
30
31
/* ============================================================================================== */
32
/* Constants */
33
/* ============================================================================================== */
34
35
#include <Generated/FormatterStrings.inc>
36
37
/* ============================================================================================== */
38
/* Formatter functions */
39
/* ============================================================================================== */
40
41
/* ---------------------------------------------------------------------------------------------- */
42
/* Intel */
43
/* ---------------------------------------------------------------------------------------------- */
44
45
ZyanStatus ZydisFormatterIntelFormatInstruction(const ZydisFormatter* formatter,
46
ZydisFormatterBuffer* buffer, ZydisFormatterContext* context)
47
{
48
ZYAN_ASSERT(formatter);
49
ZYAN_ASSERT(buffer);
50
ZYAN_ASSERT(context);
51
ZYAN_ASSERT(context->instruction);
52
ZYAN_ASSERT(context->operands);
53
54
ZYAN_CHECK(formatter->func_print_prefixes(formatter, buffer, context));
55
ZYAN_CHECK(formatter->func_print_mnemonic(formatter, buffer, context));
56
57
ZyanUPointer state_mnemonic;
58
ZYDIS_BUFFER_REMEMBER(buffer, state_mnemonic);
59
for (ZyanU8 i = 0; i < context->instruction->operand_count_visible; ++i)
60
{
61
const ZydisDecodedOperand* const operand = &context->operands[i];
62
63
// Print embedded-mask registers as decorator instead of a regular operand
64
if ((i == 1) && (operand->type == ZYDIS_OPERAND_TYPE_REGISTER) &&
65
(operand->encoding == ZYDIS_OPERAND_ENCODING_MASK))
66
{
67
continue;
68
}
69
70
ZyanUPointer buffer_state;
71
ZYDIS_BUFFER_REMEMBER(buffer, buffer_state);
72
73
if (buffer_state != state_mnemonic)
74
{
75
ZYDIS_BUFFER_APPEND(buffer, DELIM_OPERAND);
76
} else
77
{
78
ZYDIS_BUFFER_APPEND(buffer, DELIM_MNEMONIC);
79
}
80
81
// Set current operand
82
context->operand = operand;
83
84
ZyanStatus status;
85
if (formatter->func_pre_operand)
86
{
87
status = formatter->func_pre_operand(formatter, buffer, context);
88
if (status == ZYDIS_STATUS_SKIP_TOKEN)
89
{
90
ZYAN_CHECK(ZydisFormatterBufferRestore(buffer, buffer_state));
91
continue;
92
}
93
if (!ZYAN_SUCCESS(status))
94
{
95
return status;
96
}
97
}
98
99
switch (operand->type)
100
{
101
case ZYDIS_OPERAND_TYPE_REGISTER:
102
status = formatter->func_format_operand_reg(formatter, buffer, context);
103
break;
104
case ZYDIS_OPERAND_TYPE_MEMORY:
105
status = formatter->func_format_operand_mem(formatter, buffer, context);
106
break;
107
case ZYDIS_OPERAND_TYPE_POINTER:
108
status = formatter->func_format_operand_ptr(formatter, buffer, context);
109
break;
110
case ZYDIS_OPERAND_TYPE_IMMEDIATE:
111
status = formatter->func_format_operand_imm(formatter, buffer, context);
112
break;
113
default:
114
return ZYAN_STATUS_INVALID_ARGUMENT;
115
}
116
if (status == ZYDIS_STATUS_SKIP_TOKEN)
117
{
118
ZYAN_CHECK(ZydisFormatterBufferRestore(buffer, buffer_state));
119
continue;
120
}
121
if (!ZYAN_SUCCESS(status))
122
{
123
return status;
124
}
125
126
if (formatter->func_post_operand)
127
{
128
status = formatter->func_post_operand(formatter, buffer, context);
129
if (status == ZYDIS_STATUS_SKIP_TOKEN)
130
{
131
ZYAN_CHECK(ZydisFormatterBufferRestore(buffer, buffer_state));
132
continue;
133
}
134
if (ZYAN_SUCCESS(status))
135
{
136
return status;
137
}
138
}
139
140
#if !defined(ZYDIS_DISABLE_AVX512) || !defined(ZYDIS_DISABLE_KNC)
141
if ((context->instruction->encoding == ZYDIS_INSTRUCTION_ENCODING_EVEX) ||
142
(context->instruction->encoding == ZYDIS_INSTRUCTION_ENCODING_MVEX))
143
{
144
if ((i == 0) &&
145
(context->instruction->operand_count_visible > 1) &&
146
(context->operands[i + 1].encoding == ZYDIS_OPERAND_ENCODING_MASK))
147
{
148
ZYAN_CHECK(formatter->func_print_decorator(formatter, buffer, context,
149
ZYDIS_DECORATOR_MASK));
150
}
151
if (operand->type == ZYDIS_OPERAND_TYPE_MEMORY)
152
{
153
ZYAN_CHECK(formatter->func_print_decorator(formatter, buffer, context,
154
ZYDIS_DECORATOR_BC));
155
if (context->instruction->encoding == ZYDIS_INSTRUCTION_ENCODING_MVEX)
156
{
157
ZYAN_CHECK(formatter->func_print_decorator(formatter, buffer, context,
158
ZYDIS_DECORATOR_CONVERSION));
159
ZYAN_CHECK(formatter->func_print_decorator(formatter, buffer, context,
160
ZYDIS_DECORATOR_EH));
161
}
162
} else
163
{
164
ZyanBool decorate_operand;
165
if (i == (context->instruction->operand_count_visible - 1))
166
{
167
decorate_operand = operand->type != ZYDIS_OPERAND_TYPE_IMMEDIATE;
168
}
169
else
170
{
171
decorate_operand =
172
(context->instruction->operand_count_visible > (i + 1)) &&
173
((context->operands[i + 1].type == ZYDIS_OPERAND_TYPE_IMMEDIATE) ||
174
(context->operands[i + 1].visibility == ZYDIS_OPERAND_VISIBILITY_HIDDEN));
175
}
176
if (decorate_operand)
177
{
178
if (context->instruction->encoding == ZYDIS_INSTRUCTION_ENCODING_MVEX)
179
{
180
ZYAN_CHECK(formatter->func_print_decorator(formatter, buffer, context,
181
ZYDIS_DECORATOR_SWIZZLE));
182
}
183
ZYAN_CHECK(formatter->func_print_decorator(formatter, buffer, context,
184
ZYDIS_DECORATOR_RC));
185
ZYAN_CHECK(formatter->func_print_decorator(formatter, buffer, context,
186
ZYDIS_DECORATOR_SAE));
187
}
188
}
189
}
190
#endif
191
}
192
193
return ZYAN_STATUS_SUCCESS;
194
}
195
196
ZyanStatus ZydisFormatterIntelFormatOperandMEM(const ZydisFormatter* formatter,
197
ZydisFormatterBuffer* buffer, ZydisFormatterContext* context)
198
{
199
ZYAN_ASSERT(formatter);
200
ZYAN_ASSERT(buffer);
201
ZYAN_ASSERT(context);
202
203
if ((context->operand->mem.type == ZYDIS_MEMOP_TYPE_MEM) ||
204
(context->operand->mem.type == ZYDIS_MEMOP_TYPE_VSIB))
205
{
206
ZYAN_CHECK(formatter->func_print_typecast(formatter, buffer, context));
207
}
208
ZYAN_CHECK(formatter->func_print_segment(formatter, buffer, context));
209
210
ZYDIS_BUFFER_APPEND(buffer, MEMORY_BEGIN_INTEL);
211
212
const ZyanBool absolute = !formatter->force_relative_riprel &&
213
(context->runtime_address != ZYDIS_RUNTIME_ADDRESS_NONE);
214
if (absolute && context->operand->mem.disp.has_displacement &&
215
(context->operand->mem.index == ZYDIS_REGISTER_NONE) &&
216
((context->operand->mem.base == ZYDIS_REGISTER_NONE) ||
217
(context->operand->mem.base == ZYDIS_REGISTER_EIP ) ||
218
(context->operand->mem.base == ZYDIS_REGISTER_RIP )))
219
{
220
// EIP/RIP-relative or absolute-displacement address operand
221
ZYAN_CHECK(formatter->func_print_address_abs(formatter, buffer, context));
222
} else
223
{
224
const ZyanBool should_print_reg = context->operand->mem.base != ZYDIS_REGISTER_NONE;
225
const ZyanBool should_print_idx = context->operand->mem.index != ZYDIS_REGISTER_NONE;
226
const ZyanBool neither_reg_nor_idx = !should_print_reg && !should_print_idx;
227
228
// Regular memory operand
229
if (should_print_reg)
230
{
231
ZYAN_CHECK(formatter->func_print_register(formatter, buffer, context,
232
context->operand->mem.base));
233
}
234
if (should_print_idx)
235
{
236
if (context->operand->mem.base != ZYDIS_REGISTER_NONE)
237
{
238
ZYDIS_BUFFER_APPEND(buffer, ADD);
239
}
240
ZYAN_CHECK(formatter->func_print_register(formatter, buffer, context,
241
context->operand->mem.index));
242
if (context->operand->mem.scale &&
243
(context->operand->mem.type != ZYDIS_MEMOP_TYPE_MIB) &&
244
((context->operand->mem.scale > 1) || formatter->force_memory_scale))
245
{
246
ZYDIS_BUFFER_APPEND(buffer, MUL);
247
ZYDIS_BUFFER_APPEND_TOKEN(buffer, ZYDIS_TOKEN_IMMEDIATE);
248
ZYAN_CHECK(ZydisStringAppendDecU(&buffer->string, context->operand->mem.scale, 0,
249
ZYAN_NULL, ZYAN_NULL));
250
}
251
}
252
if (neither_reg_nor_idx)
253
{
254
ZYAN_CHECK(formatter->func_print_address_abs(formatter, buffer, context));
255
} else if (context->operand->mem.disp.has_displacement && context->operand->mem.disp.value)
256
{
257
ZYAN_CHECK(formatter->func_print_disp(formatter, buffer, context));
258
}
259
}
260
261
ZYDIS_BUFFER_APPEND(buffer, MEMORY_END_INTEL);
262
return ZYAN_STATUS_SUCCESS;
263
}
264
265
ZyanStatus ZydisFormatterIntelPrintMnemonic(const ZydisFormatter* formatter,
266
ZydisFormatterBuffer* buffer, ZydisFormatterContext* context)
267
{
268
ZYAN_ASSERT(formatter);
269
ZYAN_ASSERT(buffer);
270
ZYAN_ASSERT(context);
271
272
const ZydisShortString* mnemonic = ZydisMnemonicGetStringWrapped(
273
context->instruction->mnemonic);
274
if (!mnemonic)
275
{
276
ZYDIS_BUFFER_APPEND_CASE(buffer, INVALID_MNEMONIC, formatter->case_mnemonic);
277
return ZYAN_STATUS_SUCCESS;
278
}
279
280
ZYDIS_BUFFER_APPEND_TOKEN(buffer, ZYDIS_TOKEN_MNEMONIC);
281
ZYAN_CHECK(ZydisStringAppendShortCase(&buffer->string, mnemonic, formatter->case_mnemonic));
282
if (context->instruction->meta.branch_type == ZYDIS_BRANCH_TYPE_FAR)
283
{
284
return ZydisStringAppendShortCase(&buffer->string, &STR_FAR, formatter->case_mnemonic);
285
}
286
if (formatter->print_branch_size)
287
{
288
switch (context->instruction->meta.branch_type)
289
{
290
case ZYDIS_BRANCH_TYPE_NONE:
291
break;
292
case ZYDIS_BRANCH_TYPE_SHORT:
293
return ZydisStringAppendShortCase(&buffer->string, &STR_SHORT,
294
formatter->case_mnemonic);
295
case ZYDIS_BRANCH_TYPE_NEAR:
296
return ZydisStringAppendShortCase(&buffer->string, &STR_NEAR,
297
formatter->case_mnemonic);
298
default:
299
return ZYAN_STATUS_INVALID_ARGUMENT;
300
}
301
}
302
303
return ZYAN_STATUS_SUCCESS;
304
}
305
306
ZyanStatus ZydisFormatterIntelPrintRegister(const ZydisFormatter* formatter,
307
ZydisFormatterBuffer* buffer, ZydisFormatterContext* context, ZydisRegister reg)
308
{
309
ZYAN_UNUSED(context);
310
311
ZYAN_ASSERT(formatter);
312
ZYAN_ASSERT(buffer);
313
ZYAN_ASSERT(context);
314
315
const ZydisShortString* str = ZydisRegisterGetStringWrapped(reg);
316
if (!str)
317
{
318
ZYDIS_BUFFER_APPEND_CASE(buffer, INVALID_REG, formatter->case_registers);
319
return ZYAN_STATUS_SUCCESS;
320
}
321
322
ZYDIS_BUFFER_APPEND_TOKEN(buffer, ZYDIS_TOKEN_REGISTER);
323
return ZydisStringAppendShortCase(&buffer->string, str, formatter->case_registers);
324
}
325
326
ZyanStatus ZydisFormatterIntelPrintDISP(const ZydisFormatter* formatter,
327
ZydisFormatterBuffer* buffer, ZydisFormatterContext* context)
328
{
329
ZYAN_ASSERT(formatter);
330
ZYAN_ASSERT(buffer);
331
ZYAN_ASSERT(context);
332
333
switch (formatter->disp_signedness)
334
{
335
case ZYDIS_SIGNEDNESS_AUTO:
336
case ZYDIS_SIGNEDNESS_SIGNED:
337
if (context->operand->mem.disp.value < 0)
338
{
339
if ((context->operand->mem.base != ZYDIS_REGISTER_NONE) ||
340
(context->operand->mem.index != ZYDIS_REGISTER_NONE))
341
{
342
ZYDIS_BUFFER_APPEND(buffer, SUB);
343
}
344
ZYDIS_BUFFER_APPEND_TOKEN(buffer, ZYDIS_TOKEN_DISPLACEMENT);
345
ZYDIS_STRING_APPEND_NUM_U(formatter, formatter->disp_base, &buffer->string,
346
ZyanAbsI64(context->operand->mem.disp.value), formatter->disp_padding,
347
formatter->hex_force_leading_number);
348
break;
349
}
350
ZYAN_FALLTHROUGH;
351
case ZYDIS_SIGNEDNESS_UNSIGNED:
352
if ((context->operand->mem.base != ZYDIS_REGISTER_NONE) ||
353
(context->operand->mem.index != ZYDIS_REGISTER_NONE))
354
{
355
ZYDIS_BUFFER_APPEND(buffer, ADD);
356
}
357
ZYDIS_BUFFER_APPEND_TOKEN(buffer, ZYDIS_TOKEN_DISPLACEMENT);
358
ZYDIS_STRING_APPEND_NUM_U(formatter, formatter->disp_base, &buffer->string,
359
context->operand->mem.disp.value, formatter->disp_padding,
360
formatter->hex_force_leading_number);
361
break;
362
default:
363
return ZYAN_STATUS_INVALID_ARGUMENT;
364
}
365
366
return ZYAN_STATUS_SUCCESS;
367
}
368
369
ZyanStatus ZydisFormatterIntelPrintTypecast(const ZydisFormatter* formatter,
370
ZydisFormatterBuffer* buffer, ZydisFormatterContext* context)
371
{
372
ZYAN_ASSERT(formatter);
373
ZYAN_ASSERT(buffer);
374
ZYAN_ASSERT(context);
375
376
switch (ZydisFormatterHelperGetExplicitSize(formatter, context, context->operand))
377
{
378
case 8: ZYDIS_BUFFER_APPEND(buffer, SIZE_8_INTEL ); break;
379
case 16: ZYDIS_BUFFER_APPEND(buffer, SIZE_16_INTEL ); break;
380
case 32: ZYDIS_BUFFER_APPEND(buffer, SIZE_32_INTEL ); break;
381
case 48: ZYDIS_BUFFER_APPEND(buffer, SIZE_48 ); break;
382
case 64: ZYDIS_BUFFER_APPEND(buffer, SIZE_64_INTEL ); break;
383
case 80: ZYDIS_BUFFER_APPEND(buffer, SIZE_80 ); break;
384
case 128: ZYDIS_BUFFER_APPEND(buffer, SIZE_128_INTEL); break;
385
case 256: ZYDIS_BUFFER_APPEND(buffer, SIZE_256_INTEL); break;
386
case 512: ZYDIS_BUFFER_APPEND(buffer, SIZE_512_INTEL); break;
387
default:
388
break;
389
}
390
391
return ZYAN_STATUS_SUCCESS;
392
}
393
394
/* ---------------------------------------------------------------------------------------------- */
395
/* MASM */
396
/* ---------------------------------------------------------------------------------------------- */
397
398
ZyanStatus ZydisFormatterIntelFormatInstructionMASM(const ZydisFormatter* formatter,
399
ZydisFormatterBuffer* buffer, ZydisFormatterContext* context)
400
{
401
ZYAN_ASSERT(formatter);
402
ZYAN_ASSERT(buffer);
403
ZYAN_ASSERT(context);
404
405
// Force the formatter to always call our MASM `ZYDIS_FORMATTER_PRINT_ADDRESS_ABS` function.
406
// This implicitly omits printing of the `RIP`/`EIP` registers for `RIP`/`EIP`-relative
407
// memory operands
408
context->runtime_address = 0;
409
410
return ZydisFormatterIntelFormatInstruction(formatter, buffer, context);
411
}
412
413
ZyanStatus ZydisFormatterIntelPrintAddressMASM(const ZydisFormatter* formatter,
414
ZydisFormatterBuffer* buffer, ZydisFormatterContext* context)
415
{
416
ZYAN_ASSERT(formatter);
417
ZYAN_ASSERT(buffer);
418
ZYAN_ASSERT(context);
419
420
ZyanU64 address;
421
ZYAN_CHECK(ZydisCalcAbsoluteAddress(context->instruction, context->operand, 0, &address));
422
423
ZyanU8 padding = (formatter->addr_padding_relative ==
424
ZYDIS_PADDING_AUTO) ? 0 : (ZyanU8)formatter->addr_padding_relative;
425
if ((formatter->addr_padding_relative == ZYDIS_PADDING_AUTO) &&
426
(formatter->addr_base == ZYDIS_NUMERIC_BASE_HEX))
427
{
428
switch (context->instruction->stack_width)
429
{
430
case 16:
431
padding = 4;
432
address = (ZyanU16)address;
433
break;
434
case 32:
435
padding = 8;
436
address = (ZyanU32)address;
437
break;
438
case 64:
439
padding = 16;
440
break;
441
default:
442
return ZYAN_STATUS_INVALID_ARGUMENT;
443
}
444
}
445
446
ZYDIS_BUFFER_APPEND(buffer, ADDR_RELATIVE);
447
ZYDIS_STRING_APPEND_NUM_S(formatter, formatter->addr_base, &buffer->string, address, padding,
448
formatter->hex_force_leading_number, ZYAN_TRUE);
449
450
return ZYAN_STATUS_SUCCESS;
451
}
452
453
/* ---------------------------------------------------------------------------------------------- */
454
455
/* ============================================================================================== */
456
457