Skip to content

Commit 718dac4

Browse files
committed
"rflags" now refers to the native %rflags register
Previously, the "rflags" argument would use a different layout than the native %rflags register. This commit makes the following changes: - The "rflags" argument now uses the native %rflags layout, and includes all flags. - A new "flags" argument implements the old "rflags" layout and behaviour. Most applications should switch to using "flags" for performance reasons, since accessing the %rflags register directly is a slow operation.
1 parent e888f38 commit 718dac4

30 files changed

+211
-107
lines changed

doc/e9tool-user-guide.md

Lines changed: 15 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -1048,8 +1048,10 @@ The following arguments are supported:
10481048
<td>The corresponding 32bit register</td></tr>
10491049
<tr><td><b><tt>rax</tt></b>,...,<b><tt>r15</tt></b></td><td><tt>int64_t</tt></td>
10501050
<td>The corresponding 64bit register</td></tr>
1051-
<tr><td><b><tt>rflags</tt></b></td><td><tt>int16_t</tt></td>
1052-
<td>The <tt>%rflags</tt> register with format
1051+
<tr><td><b><tt>rflags</tt></b></td><td><tt>int64_t</tt></td>
1052+
<td>The <tt>%rflags</tt> register</td></tr>
1053+
<tr><td><b><tt>flags</tt></b></td><td><tt>int16_t</tt></td>
1054+
<td>The <tt>%rflags</tt> status flags with format
10531055
<tt>SF:ZF:0:AF:0:PF:1:CF:0:0:0:0:0:0:0:OF</tt></td></tr>
10541056
<tr><td><b><tt>rip</tt></b></td><td><tt>const void &#42;</tt></td>
10551057
<td>The <tt>%rip</tt> register</td></tr>
@@ -1061,8 +1063,10 @@ The following arguments are supported:
10611063
<td>The corresponding 32bit register (passed-by-pointer)</td></tr>
10621064
<tr><td><b><tt>&amp;rax</tt></b>,...,<b><tt>&amp;r15</tt></b></td><td><tt>int64_t &#42;</tt></td>
10631065
<td>The corresponding 64bit register (passed-by-pointer)</td></tr>
1064-
<tr><td><b><tt>&amp;rflags</tt></b></td><td><tt>int16_t &#42;</tt></td>
1066+
<tr><td><b><tt>&amp;rflags</tt></b></td><td><tt>int64_t &#42;</tt></td>
10651067
<td>The <tt>%rflags</tt> register (passed-by-pointer)</td></tr>
1068+
<tr><td><b><tt>&amp;flags</tt></b></td><td><tt>int16_t &#42;</tt></td>
1069+
<td>The status flags from <tt>%rflags</tt> (passed-by-pointer)</td></tr>
10661070
<tr><td><b><tt>op[i]</tt></b></td><td><tt>int8/16/32/64_t</tt></td>
10671071
<td>The matching instruction's <i>i</i><sup>th</sup> operand</td></tr>
10681072
<tr><td><b><tt>src[i]</tt></b></td><td><tt>int8/16/32/64_t</tt></td>
@@ -1272,16 +1276,18 @@ The following arguments are supported:
12721276

12731277
Notes:
12741278

1275-
* The `rflags` argument differs from the native
1276-
`x86_64` layout in terms of the number of flags as well as the flag ordering.
1277-
The modified layout is used for efficiency reasons since preserving the
1278-
native layout is a relatively slow operation.
1279+
* Accessing the `%rflags` register directly is relatively slow operation.
1280+
For performance, consider accessing *status flag* bits indirectly using the
1281+
alternative `flags` argument.
1282+
Note that the `flags` argument uses a special
1283+
<tt>SF:ZF:0:AF:0:PF:1:CF:0:0:0:0:0:0:0:OF</tt> layout (which differs from
1284+
the native `%rflags` layout).
12791285
* For technical reasons, the `%rip` register is considered constant and cannot
12801286
be modified.
12811287
To implement jumps, use [conditional call trampolines](#conditional-calls) instead.
12821288
* The `state` argument is a pointer to a structure containing all
1283-
general-purpose registers, the flag register (`%rflags`), the stack register
1284-
(`%rsp`) and the instruction pointer register (`%rip`).
1289+
general-purpose registers, the status flags (using the `flags` layout), the
1290+
stack register (`%rsp`) and the instruction pointer register (`%rip`).
12851291
See `STATE` defined in `stdlib.c` for the structure layout.
12861292
Except for `%rip`, the values in the structure can be modified, in which
12871293
case the corresponding register will be updated accordingly.

examples/stdlib.c

Lines changed: 19 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -5739,7 +5739,7 @@ struct STATE
57395739
{
57405740
union
57415741
{
5742-
uint16_t rflags;
5742+
uint16_t flags;
57435743
uint64_t __padding;
57445744
};
57455745
union
@@ -5879,17 +5879,27 @@ struct STATE
58795879
};
58805880

58815881
/*
5882-
* Flags.
5882+
* Flags (E9Tool `flags' argument ordering)
58835883
*/
5884-
#define OF 0x0001
5885-
#define CF 0x0100
5886-
#define PF 0x0400
5887-
#define AF 0x1000
5888-
#define ZF 0x4000
5889-
#define SF 0x8000
5884+
#define FLAGS_OF 0x0001
5885+
#define FLAGS_CF 0x0100
5886+
#define FLAGS_PF 0x0400
5887+
#define FLAGS_AF 0x1000
5888+
#define FLAGS_ZF 0x4000
5889+
#define FLAGS_SF 0x8000
58905890

58915891
/*
5892-
* Jump to state (also restores %rip and %rip)
5892+
* Flags (native x86_64 %rflags ordering)
5893+
*/
5894+
#define RFLAGS_CF 0x0001
5895+
#define RFLAGS_PF 0x0004
5896+
#define RFLAGS_AF 0x0010
5897+
#define RFLAGS_ZF 0x0040
5898+
#define RFLAGS_SF 0x0080
5899+
#define RFLAGS_OF 0x0800
5900+
5901+
/*
5902+
* Jump to state (also restores %rip and %rsp)
58935903
*/
58945904
static __attribute__((noreturn)) void jump(const struct STATE *state)
58955905
{

src/e9tool/e9action.cpp

Lines changed: 7 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1011,6 +1011,10 @@ static const Argument parsePatchArg(Parser &parser)
10111011
case TOKEN_FILENAME:
10121012
option_lines = true;
10131013
arg = ARGUMENT_FILENAME; break;
1014+
case TOKEN_FLAGS:
1015+
value = REGISTER_FLAGS;
1016+
arg = ARGUMENT_REGISTER;
1017+
break;
10141018
case TOKEN_ID:
10151019
arg = ARGUMENT_ID; break;
10161020
case TOKEN_IMM:
@@ -2321,7 +2325,7 @@ static MatchVal makeMatchValue(const MatchVar *var, const ELF *elf,
23212325
return result;
23222326
case MATCH_READS:
23232327
if (I->flags.read != 0x0)
2324-
buf[j++] = REGISTER_EFLAGS;
2328+
buf[j++] = REGISTER_RFLAGS;
23252329
for (uint8_t i = 0; I->regs.read[i] != REGISTER_INVALID; i++)
23262330
buf[j++] = MatchVal(I->regs.read[i]);
23272331
for (uint8_t i = 0; I->regs.condread[i] != REGISTER_INVALID; i++)
@@ -2332,7 +2336,7 @@ static MatchVal makeMatchValue(const MatchVar *var, const ELF *elf,
23322336
return result;
23332337
case MATCH_WRITES:
23342338
if (I->flags.write != 0x0)
2335-
buf[j++] = REGISTER_EFLAGS;
2339+
buf[j++] = REGISTER_RFLAGS;
23362340
for (uint8_t i = 0; I->regs.write[i] != REGISTER_INVALID; i++)
23372341
buf[j++] = MatchVal(I->regs.write[i]);
23382342
for (uint8_t i = 0; I->regs.condwrite[i] != REGISTER_INVALID; i++)
@@ -2343,7 +2347,7 @@ static MatchVal makeMatchValue(const MatchVar *var, const ELF *elf,
23432347
return result;
23442348
case MATCH_REGS:
23452349
if ((I->flags.read | I->flags.write) != 0x0)
2346-
buf[j++] = REGISTER_EFLAGS;
2350+
buf[j++] = REGISTER_RFLAGS;
23472351
for (uint8_t i = 0; I->regs.read[i] != REGISTER_INVALID; i++)
23482352
buf[j++] = MatchVal(I->regs.read[i]);
23492353
for (uint8_t i = 0; I->regs.condread[i] != REGISTER_INVALID; i++)

src/e9tool/e9codegen.cpp

Lines changed: 35 additions & 25 deletions
Original file line numberDiff line numberDiff line change
@@ -78,8 +78,8 @@ Register getReg(int regno)
7878
return REGISTER_R8;
7979
case R9_IDX:
8080
return REGISTER_R9;
81-
case RFLAGS_IDX:
82-
return REGISTER_EFLAGS;
81+
case FLAGS_IDX:
82+
return REGISTER_FLAGS;
8383
case RAX_IDX:
8484
return REGISTER_RAX;
8585
case R10_IDX:
@@ -245,12 +245,12 @@ int32_t getRegSize(Register reg)
245245
case REGISTER_R14B: case REGISTER_R15B:
246246
return sizeof(int8_t);
247247

248-
case REGISTER_EFLAGS: case REGISTER_AX: case REGISTER_BP:
249-
case REGISTER_BX: case REGISTER_CX: case REGISTER_DX:
250-
case REGISTER_DI: case REGISTER_IP: case REGISTER_SI:
251-
case REGISTER_SP: case REGISTER_R8W: case REGISTER_R9W:
252-
case REGISTER_R10W: case REGISTER_R11W: case REGISTER_R12W:
253-
case REGISTER_R13W: case REGISTER_R14W: case REGISTER_R15W:
248+
case REGISTER_AX: case REGISTER_BP: case REGISTER_BX:
249+
case REGISTER_CX: case REGISTER_DX: case REGISTER_DI:
250+
case REGISTER_IP: case REGISTER_SI: case REGISTER_SP:
251+
case REGISTER_R8W: case REGISTER_R9W: case REGISTER_R10W:
252+
case REGISTER_R11W: case REGISTER_R12W: case REGISTER_R13W:
253+
case REGISTER_R14W: case REGISTER_R15W: case REGISTER_FLAGS:
254254
return sizeof(int16_t);
255255

256256
case REGISTER_EAX: case REGISTER_EBP: case REGISTER_EBX:
@@ -266,7 +266,7 @@ int32_t getRegSize(Register reg)
266266
case REGISTER_RIP: case REGISTER_RSI: case REGISTER_RSP:
267267
case REGISTER_R8: case REGISTER_R9: case REGISTER_R10:
268268
case REGISTER_R11: case REGISTER_R12: case REGISTER_R13:
269-
case REGISTER_R14: case REGISTER_R15:
269+
case REGISTER_R14: case REGISTER_R15: case REGISTER_RFLAGS:
270270
return sizeof(int64_t);
271271

272272
case REGISTER_XMM0: case REGISTER_XMM1: case REGISTER_XMM2:
@@ -353,12 +353,12 @@ Type getRegType(Register reg)
353353
case REGISTER_R14B: case REGISTER_R15B:
354354
return TYPE_INT8;
355355

356-
case REGISTER_EFLAGS: case REGISTER_AX: case REGISTER_BP:
357-
case REGISTER_BX: case REGISTER_CX: case REGISTER_DX:
358-
case REGISTER_DI: case REGISTER_IP: case REGISTER_SI:
359-
case REGISTER_SP: case REGISTER_R8W: case REGISTER_R9W:
360-
case REGISTER_R10W: case REGISTER_R11W: case REGISTER_R12W:
361-
case REGISTER_R13W: case REGISTER_R14W: case REGISTER_R15W:
356+
case REGISTER_AX: case REGISTER_BP: case REGISTER_BX:
357+
case REGISTER_CX: case REGISTER_DX: case REGISTER_DI:
358+
case REGISTER_IP: case REGISTER_SI: case REGISTER_SP:
359+
case REGISTER_R8W: case REGISTER_R9W: case REGISTER_R10W:
360+
case REGISTER_R11W: case REGISTER_R12W: case REGISTER_R13W:
361+
case REGISTER_R14W: case REGISTER_R15W: case REGISTER_FLAGS:
362362
return TYPE_INT16;
363363

364364
case REGISTER_EAX: case REGISTER_EBP: case REGISTER_EBX:
@@ -375,6 +375,7 @@ Type getRegType(Register reg)
375375
case REGISTER_RSP: case REGISTER_R8: case REGISTER_R9:
376376
case REGISTER_R10: case REGISTER_R11: case REGISTER_R12:
377377
case REGISTER_R13: case REGISTER_R14: case REGISTER_R15:
378+
case REGISTER_RFLAGS:
378379
return TYPE_INT64;
379380

380381
case REGISTER_XMM0: case REGISTER_XMM1: case REGISTER_XMM2:
@@ -486,7 +487,7 @@ const char *e9tool::getRegName(Register reg)
486487
case REGISTER_R13B: return "%r13b";
487488
case REGISTER_R14B: return "%r14b";
488489
case REGISTER_R15B: return "%r15b";
489-
case REGISTER_EFLAGS: return "%rflags";
490+
case REGISTER_RFLAGS: return "%rflags";
490491
case REGISTER_AX: return "%ax";
491492
case REGISTER_BP: return "%bp";
492493
case REGISTER_BX: return "%bx";
@@ -712,7 +713,7 @@ const int *getCallerSaveRegs(bool sysv, bool clean, bool state,
712713
{
713714
RAX_IDX, RCX_IDX, RDX_IDX, RBX_IDX, RBP_IDX, RSI_IDX, RDI_IDX, R8_IDX,
714715
R9_IDX, R10_IDX, R11_IDX, R12_IDX, R13_IDX, R14_IDX, R15_IDX,
715-
RFLAGS_IDX, RSP_IDX, RIP_IDX, -1
716+
FLAGS_IDX, RSP_IDX, RIP_IDX, -1
716717
};
717718
if (state)
718719
return state_save;
@@ -723,12 +724,12 @@ const int *getCallerSaveRegs(bool sysv, bool clean, bool state,
723724
// - %rax must be saved before %rflags.
724725
static const int clean_sysv_save[] =
725726
{
726-
RCX_IDX, RAX_IDX, RFLAGS_IDX, R11_IDX, R10_IDX, R9_IDX, R8_IDX,
727+
RCX_IDX, RAX_IDX, FLAGS_IDX, R11_IDX, R10_IDX, R9_IDX, R8_IDX,
727728
RDX_IDX, RSI_IDX, RDI_IDX, -1
728729
};
729730
static const int clean_win64_save[] =
730731
{
731-
RCX_IDX, RAX_IDX, RFLAGS_IDX, R11_IDX, R10_IDX, R9_IDX, R8_IDX,
732+
RCX_IDX, RAX_IDX, FLAGS_IDX, R11_IDX, R10_IDX, R9_IDX, R8_IDX,
732733
RDX_IDX, -1
733734
};
734735
const int *clean_save = (sysv? clean_sysv_save: clean_win64_save);
@@ -969,9 +970,9 @@ std::pair<bool, bool> sendPush(FILE *out, int32_t offset, bool before,
969970
{
970971
case REGISTER_RIP:
971972
case REGISTER_RSP:
972-
case REGISTER_EFLAGS:
973+
case REGISTER_FLAGS:
973974
scratch = getRegIdx(rscratch);
974-
assert(scratch != RSP_IDX && scratch != RFLAGS_IDX &&
975+
assert(scratch != RSP_IDX && scratch != FLAGS_IDX &&
975976
scratch != RIP_IDX);
976977
if (scratch < 0)
977978
{
@@ -981,7 +982,7 @@ std::pair<bool, bool> sendPush(FILE *out, int32_t offset, bool before,
981982
scratch = RAX_IDX;
982983
rax_stack = true;
983984
}
984-
if (reg == REGISTER_EFLAGS && scratch != RAX_IDX)
985+
if (reg == REGISTER_FLAGS && scratch != RAX_IDX)
985986
{
986987
// %rflags requires %rax as the scratch register:
987988
sendMovFromR64ToR64(out, RAX_IDX, scratch);
@@ -1011,7 +1012,7 @@ std::pair<bool, bool> sendPush(FILE *out, int32_t offset, bool before,
10111012
sendMovFromR64ToStack(out, scratch, offset - RSP_SLOT);
10121013
break;
10131014

1014-
case REGISTER_EFLAGS:
1015+
case REGISTER_FLAGS:
10151016
// seto %al
10161017
// lahf
10171018
assert(scratch == RAX_IDX);
@@ -1020,14 +1021,19 @@ std::pair<bool, bool> sendPush(FILE *out, int32_t offset, bool before,
10201021
sendPush(out, offset + sizeof(int64_t), before, REGISTER_RAX);
10211022
break;
10221023

1024+
case REGISTER_RFLAGS:
1025+
// pushfq
1026+
fprintf(out, "%u,", 0x9c);
1027+
return {true, false};
1028+
10231029
default:
10241030
break;
10251031
}
10261032
switch (reg)
10271033
{
10281034
case REGISTER_RIP:
10291035
case REGISTER_RSP:
1030-
case REGISTER_EFLAGS:
1036+
case REGISTER_FLAGS:
10311037
if (old_scratch >= 0)
10321038
sendMovFromR64ToR64(out, old_scratch, scratch);
10331039
else if (rax_stack)
@@ -1076,7 +1082,7 @@ bool sendPop(FILE *out, bool preserve_rax, Register reg, Register rscratch)
10761082
// Special cases:
10771083
switch (reg)
10781084
{
1079-
case REGISTER_EFLAGS:
1085+
case REGISTER_FLAGS:
10801086
{
10811087
int scratch = -1;
10821088
if (preserve_rax)
@@ -1109,6 +1115,10 @@ bool sendPop(FILE *out, bool preserve_rax, Register reg, Register rscratch)
11091115
return false;
11101116
}
11111117

1118+
case REGISTER_RFLAGS:
1119+
fprintf(out, "%u,", 0x9d);
1120+
return false;
1121+
11121122
case REGISTER_RIP:
11131123
// %rip is treated as read-only & stored in a special slot.
11141124
// So the pop operation is treated as a NOP.

src/e9tool/e9codegen.h

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -32,7 +32,7 @@
3232
#define RCX_IDX 3
3333
#define R8_IDX 4
3434
#define R9_IDX 5
35-
#define RFLAGS_IDX 6
35+
#define FLAGS_IDX 6
3636
#define RAX_IDX 7
3737
#define R10_IDX 8
3838
#define R11_IDX 9

src/e9tool/e9elf.h

Lines changed: 8 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -144,17 +144,16 @@ namespace e9tool
144144
const CallABI abi;
145145
const CallJump jmp;
146146
const PatchPos pos;
147-
const bool state;
147+
const bool state; // Uses ARGUMENT_STATE?
148+
const bool rflags; // Writes to %rflags?
148149
const ELF * const target;
149150
const char *const entry;
150-
const std::vector<ArgumentKind> args;
151-
152-
Call(CallABI abi, CallJump jmp, PatchPos pos, bool state,
153-
const ELF *target, const char *entry,
154-
const std::vector<ArgumentKind> &args) :
155-
abi(abi), jmp(jmp), pos(pos), state(state), target(target),
156-
entry(entry),
157-
args(args) // copy
151+
const size_t nargs;
152+
153+
Call(CallABI abi, CallJump jmp, PatchPos pos, bool state, bool rflags,
154+
const ELF *target, const char *entry, size_t nargs) :
155+
abi(abi), jmp(jmp), pos(pos), state(state), rflags(rflags),
156+
target(target), entry(entry), nargs(nargs)
158157
{
159158
;
160159
}

0 commit comments

Comments
 (0)