Skip to content

Commit b637226

Browse files
committed
feat(x86): completed encoder
1 parent bcd154b commit b637226

4 files changed

Lines changed: 106 additions & 46 deletions

File tree

x86/encoder/encoder.c

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -11,7 +11,7 @@ bool x86_encode(RDContext* ctx, RDAddress address, const char* s,
1111
X86GrammarData g = {
1212
.ctx = ctx,
1313
.req = {.machine_mode = self->userdata->mode},
14-
.err_buf = buf,
14+
.buf = buf,
1515
};
1616

1717
if(!x86_encoder_parse(self->lex, s, &g)) return false;
@@ -21,7 +21,7 @@ bool x86_encode(RDContext* ctx, RDAddress address, const char* s,
2121

2222
if(!ZYAN_SUCCESS(ZydisEncoderEncodeInstructionAbsolute(
2323
&g.req, buffer, &length, (ZyanU64)address))) {
24-
RD_LOG_FAIL("%s", rd_format_to(buf, "failed to encode '%s'", s));
24+
RD_LOG_FAIL_TO(buf, "failed to encode '%s'", s);
2525
return false;
2626
}
2727

x86/encoder/grammar.c

Lines changed: 102 additions & 43 deletions
Original file line numberDiff line numberDiff line change
@@ -105,53 +105,119 @@ static bool _displ_operand_rule(RDLexer* lex, void* userdata) {
105105
return false;
106106
}
107107

108-
if(!rd_lexer_next_expect(lex, RD_TOK_OPEN_SQUARE, &tok)) return false;
108+
if(!rd_lexer_try_consume(lex, RD_TOK_OPEN_SQUARE, &tok)) return false;
109109

110110
ZydisRegister base = ZYDIS_REGISTER_NONE, index = ZYDIS_REGISTER_NONE;
111111
u8 scale = 1;
112112
i64 disp = 0;
113-
bool have_disp = false;
113+
bool have_disp = false, first = true;
114114

115-
// optional base register: "[0x1000]" (absolute) is valid with none at all
116-
if(rd_lexer_peek_expect(lex, RD_TOK_IDENTIFIER, &tok)) {
117-
ZydisRegister reg = _x86_register_from_token(&tok);
115+
while(!rd_lexer_try_consume(lex, RD_TOK_CLOSE_SQUARE, &tok)) {
116+
bool minus = false;
118117

119-
if(reg != ZYDIS_REGISTER_NONE) {
120-
rd_lexer_consume(lex);
121-
base = reg;
122-
}
123-
}
118+
if(!first) {
119+
if(!rd_lexer_next(lex, &tok)) {
120+
RD_LOG_FAIL_TO(data->buf, "unterminated memory operand");
121+
return false;
122+
}
123+
124+
bool plus = tok.type == RD_TOK_PLUS;
125+
minus = tok.type == RD_TOK_MINUS;
124126

125-
for(;;) {
126-
if(!rd_lexer_next(lex, &tok)) return false;
127-
if(tok.type == RD_TOK_CLOSE_SQUARE) break;
127+
if(!plus && !minus) {
128+
RD_LOG_FAIL_TO(data->buf, "expected '+' or '-'");
129+
return false;
130+
}
131+
}
128132

129-
bool plus = tok.type == RD_TOK_PLUS, minus = tok.type == RD_TOK_MINUS;
130-
if(!plus && !minus) return false;
131-
if(!rd_lexer_next(lex, &tok)) return false;
133+
if(!rd_lexer_next(lex, &tok)) {
134+
RD_LOG_FAIL_TO(data->buf, "unterminated memory operand");
135+
return false;
136+
}
132137

133-
if(tok.type == RD_TOK_IDENTIFIER) { // index register, optional "*scale"
138+
if(tok.type == RD_TOK_IDENTIFIER) {
134139
ZydisRegister reg = _x86_register_from_token(&tok);
135-
if(reg == ZYDIS_REGISTER_NONE) return false;
136-
index = reg;
137140

138-
if(rd_lexer_peek_expect(lex, RD_TOK_ASTERISK, &tok)) {
139-
rd_lexer_consume(lex);
141+
if(reg != ZYDIS_REGISTER_NONE) {
142+
u8 curr_scale = 1;
143+
bool scaled = rd_lexer_try_consume(lex, RD_TOK_ASTERISK, &tok);
140144

141-
if(!rd_lexer_next_expect(lex, RD_TOK_NUMBER, &tok))
145+
if(scaled && !rd_lexer_next_expect(lex, RD_TOK_NUMBER, &tok)) {
146+
RD_LOG_FAIL_TO(data->buf, "expected scale value after '*'");
147+
return false;
148+
}
149+
150+
if(scaled) curr_scale = (u8)tok.u_value;
151+
152+
if(scaled || base != ZYDIS_REGISTER_NONE) {
153+
if(index != ZYDIS_REGISTER_NONE) {
154+
RD_LOG_FAIL_TO(data->buf,
155+
"only one index register is allowed");
156+
return false;
157+
}
158+
159+
if(reg == ZYDIS_REGISTER_ESP || reg == ZYDIS_REGISTER_RSP) {
160+
RD_LOG_FAIL_TO(
161+
data->buf,
162+
"ESP/RSP cannot be used as an index register");
163+
return false;
164+
}
165+
166+
index = reg;
167+
scale = curr_scale;
168+
}
169+
else
170+
base = reg;
171+
}
172+
else { // not a register, try as a symbol
173+
const char* name = rd_lexer_token_value(lex, &tok);
174+
175+
RDAddress addr;
176+
if(!rd_get_address(data->ctx, name, &addr)) {
177+
RD_LOG_FAIL_TO(
178+
data->buf,
179+
"unknown register or symbol '%s' in memory operand",
180+
name);
142181
return false;
182+
}
183+
184+
disp += minus ? -(i64)addr
185+
: (i64)addr; // folds into the displacement
143186

144-
scale = (u8)tok.u_value;
187+
have_disp = true;
145188
}
146189
}
147190
else if(tok.type == RD_TOK_NUMBER) {
191+
if(have_disp) {
192+
RD_LOG_FAIL_TO(data->buf, "only one displacement is allowed");
193+
return false;
194+
}
195+
148196
disp = minus ? -(i64)tok.u_value : (i64)tok.u_value;
149197
have_disp = true;
150198
}
151-
else
199+
else {
200+
RD_LOG_FAIL_TO(data->buf, "unexpected token in memory operand");
152201
return false;
202+
}
203+
204+
first = false;
205+
}
206+
207+
if(base == ZYDIS_REGISTER_NONE && index == ZYDIS_REGISTER_NONE &&
208+
!have_disp) {
209+
RD_LOG_FAIL_TO(data->buf, "empty memory operand");
210+
return false;
153211
}
154212

213+
ZydisEncoderOperand* zop = &data->req.operands[data->req.operand_count++];
214+
zop->type = ZYDIS_OPERAND_TYPE_MEMORY;
215+
zop->mem.base = base;
216+
zop->mem.index = index;
217+
zop->mem.scale = index != ZYDIS_REGISTER_NONE ? scale : 0;
218+
zop->mem.displacement = disp;
219+
zop->mem.size = (ZyanU16)size;
220+
155221
return true;
156222
}
157223

@@ -160,16 +226,14 @@ bool x86_encoder_parse(RDLexer* lex, const char* s, X86GrammarData* data) {
160226

161227
RDToken tok;
162228
if(!rd_lexer_next_expect(lex, RD_TOK_IDENTIFIER, &tok)) {
163-
RD_LOG_FAIL(
164-
"%s", rd_format_to(data->err_buf, "expected mnemonic in '%s'", s));
229+
RD_LOG_FAIL_TO(data->buf, "expected mnemonic in '%s'", s);
165230
return false;
166231
}
167232

168233
ZydisMnemonic mnem = _x86_mnemonic_from_token(&tok);
169234
if(mnem == ZYDIS_MNEMONIC_INVALID) {
170-
RD_LOG_FAIL("%s", rd_format_to(data->err_buf,
171-
"unknown mnemonic '%.*s' in '%s'",
172-
(int)tok.length, tok.value, s));
235+
RD_LOG_FAIL_TO(data->buf, "unknown mnemonic '%.*s' in '%s'",
236+
(int)tok.length, tok.value, s);
173237
return false;
174238
}
175239

@@ -185,32 +249,28 @@ bool x86_encoder_parse(RDLexer* lex, const char* s, X86GrammarData* data) {
185249
RDToken peek;
186250
if(rd_lexer_peek(lex, &peek)) {
187251
if(!rd_lexer_try_any(lex, OPERAND_ENTRIES, data)) {
188-
RD_LOG_FAIL("%s", rd_format_to(data->err_buf,
189-
"expected operand in '%s'", s));
252+
RD_LOG_FAIL_TO(data->buf, "expected operand in '%s'", s);
190253
return false;
191254
}
192255

193256
while(rd_lexer_peek_expect(lex, RD_TOK_COMMA, &tok)) {
194257
rd_lexer_consume(lex);
195258

196259
if(data->req.operand_count >= ZYDIS_ENCODER_MAX_OPERANDS) {
197-
RD_LOG_FAIL("%s", rd_format_to(data->err_buf,
198-
"too many operands in '%s'", s));
260+
RD_LOG_FAIL_TO(data->buf, "too many operands in '%s'", s);
199261
return false;
200262
}
201263

202264
if(!rd_lexer_try_any(lex, OPERAND_ENTRIES, data)) {
203-
RD_LOG_FAIL("%s", rd_format_to(
204-
data->err_buf,
205-
"expected operand after ',' in '%s'", s));
265+
RD_LOG_FAIL_TO(data->buf, "expected operand after ',' in '%s'",
266+
s);
206267
return false;
207268
}
208269
}
209270
}
210271

211272
if(!rd_lexer_at_end(lex)) {
212-
RD_LOG_FAIL("%s", rd_format_to(data->err_buf,
213-
"unexpected trailing input in '%s'", s));
273+
RD_LOG_FAIL_TO(data->buf, "unexpected trailing input in '%s'", s);
214274
return false;
215275
}
216276

@@ -230,11 +290,10 @@ bool x86_encoder_parse(RDLexer* lex, const char* s, X86GrammarData* data) {
230290
if(op->type != ZYDIS_OPERAND_TYPE_MEMORY || op->mem.size != 0) continue;
231291

232292
if(!reg_size) {
233-
RD_LOG_FAIL("%s",
234-
rd_format_to(data->err_buf,
235-
"ambiguous memory operand size in '%s'"
236-
"specify byte/word/dword/qword ptr",
237-
s));
293+
RD_LOG_FAIL_TO(data->buf,
294+
"ambiguous memory operand size in '%s' "
295+
"specify byte/word/dword/qword ptr",
296+
s);
238297
return false;
239298
}
240299

x86/encoder/grammar.h

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,7 @@
66
typedef struct X86GrammarData {
77
RDContext* ctx;
88
ZydisEncoderRequest req;
9-
RDScratchBuffer* err_buf;
9+
RDScratchBuffer* buf;
1010
} X86GrammarData;
1111

1212
bool x86_encoder_parse(RDLexer* lex, const char* s, X86GrammarData* data);

x86/plugin.c

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -349,6 +349,7 @@ static RDProcessor* x86_create(const RDProcessorPlugin* plugin) {
349349
X86Processor* self = rd_alloc0(1, sizeof(X86Processor));
350350
self->userdata = ud;
351351
self->lex = rd_lexer_create(NULL);
352+
rd_lexer_set_default_base(self->lex, 16);
352353

353354
ZydisDecoderInit(&self->decoder, ud->mode, ud->width);
354355
return (RDProcessor*)self;

0 commit comments

Comments
 (0)