Skip to content

Commit 96516c0

Browse files
committed
Fix the "config" argument for Linux/ELF.
This also required E9Patch to support labels as values.
1 parent e826caf commit 96516c0

9 files changed

Lines changed: 158 additions & 68 deletions

File tree

src/e9patch/e9json.cpp

Lines changed: 30 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -672,9 +672,8 @@ static Entry makeDataEntry(Parser &parser)
672672
{
673673
expectToken(parser, TOKEN_STRING);
674674
Entry entry;
675+
memset(&entry, 0x0, sizeof(entry));
675676
entry.kind = ENTRY_LABEL;
676-
entry.length = 0;
677-
entry.bytes = nullptr;
678677

679678
switch (parser.s[0])
680679
{
@@ -737,28 +736,37 @@ static Entry makeDataEntry(Parser &parser)
737736
case ENTRY_INT64:
738737
{
739738
char token = expectToken2(parser, TOKEN_NUMBER, TOKEN_STRING);
740-
intptr_t x;
741-
if (token == TOKEN_NUMBER)
742-
x = (intptr_t)parser.i;
739+
if (token == TOKEN_STRING && parser.s[0] == '.' &&
740+
parser.s[1] == 'L')
741+
{
742+
entry.use_label = true;
743+
entry.label = dupString(parser.s);
744+
}
743745
else
744-
x = stringToNumber(parser);
745-
switch (entry.kind)
746746
{
747-
case ENTRY_INT8:
748-
entry.uint8 = (uint8_t)convertInteger(parser, x,
749-
INT8_MIN, UINT8_MAX, 8);
750-
break;
751-
case ENTRY_INT16:
752-
entry.uint16 = (uint16_t)convertInteger(parser, x,
753-
INT16_MIN, UINT16_MAX, 16);
754-
break;
755-
case ENTRY_INT32:
756-
entry.uint32 = (uint32_t)convertInteger(parser, x,
757-
INT32_MIN, UINT32_MAX, 32);
758-
break;
759-
default:
760-
entry.uint64 = (uint64_t)x;
761-
break;
747+
intptr_t x;
748+
if (token == TOKEN_NUMBER)
749+
x = (intptr_t)parser.i;
750+
else
751+
x = stringToNumber(parser);
752+
switch (entry.kind)
753+
{
754+
case ENTRY_INT8:
755+
entry.uint8 = (uint8_t)convertInteger(parser, x,
756+
INT8_MIN, UINT8_MAX, 8);
757+
break;
758+
case ENTRY_INT16:
759+
entry.uint16 = (uint16_t)convertInteger(parser, x,
760+
INT16_MIN, UINT16_MAX, 16);
761+
break;
762+
case ENTRY_INT32:
763+
entry.uint32 = (uint32_t)convertInteger(parser, x,
764+
INT32_MIN, UINT32_MAX, 32);
765+
break;
766+
default:
767+
entry.uint64 = (uint64_t)x;
768+
break;
769+
}
762770
}
763771
break;
764772
}

src/e9patch/e9trampoline.cpp

Lines changed: 31 additions & 27 deletions
Original file line numberDiff line numberDiff line change
@@ -663,18 +663,36 @@ static void buildBytes(const Binary *B, const Trampoline *T,
663663
for (unsigned i = 0; i < entry.length; i++)
664664
buf.push(0x0);
665665
continue;
666-
case ENTRY_INT8:
667-
buf.push(entry.uint8);
668-
break;
669-
case ENTRY_INT16:
670-
buf.push((uint8_t *)&entry.uint16, sizeof(entry.uint16));
671-
break;
672-
case ENTRY_INT32:
673-
buf.push((uint8_t *)&entry.uint32, sizeof(entry.uint32));
674-
break;
666+
case ENTRY_INT8: case ENTRY_INT16: case ENTRY_INT32:
675667
case ENTRY_INT64:
676-
buf.push((uint8_t *)&entry.uint64, sizeof(entry.uint64));
677-
break;
668+
{
669+
int64_t val = 0;
670+
if (entry.use_label)
671+
{
672+
val = lookupLabel(B, entry.label, I, entry32, labels);
673+
val += entry32 + I->addr;
674+
}
675+
else
676+
val = (int64_t)entry.uint64;
677+
switch (entry.kind)
678+
{
679+
case ENTRY_INT8:
680+
buf.push((uint8_t)val);
681+
break;
682+
case ENTRY_INT16:
683+
buf.push((uint8_t *)&val, sizeof(uint16_t));
684+
break;
685+
case ENTRY_INT32:
686+
buf.push((uint8_t *)&val, sizeof(uint32_t));
687+
break;
688+
case ENTRY_INT64:
689+
buf.push((uint8_t *)&val, sizeof(uint64_t));
690+
break;
691+
default:
692+
break;
693+
}
694+
continue;
695+
}
678696

679697
case ENTRY_LABEL:
680698
continue;
@@ -847,6 +865,8 @@ bool TrampolineCmp::operator()(const Trampoline *a, const Trampoline *b) const
847865
return (cmp < 0);
848866
break;
849867
case ENTRY_REL8: case ENTRY_REL32:
868+
case ENTRY_INT8: case ENTRY_INT16: case ENTRY_INT32:
869+
case ENTRY_INT64:
850870
if (entry_a->use_label != entry_b->use_label)
851871
return (entry_a->use_label < entry_b->use_label);
852872
if (entry_a->use_label)
@@ -861,22 +881,6 @@ bool TrampolineCmp::operator()(const Trampoline *a, const Trampoline *b) const
861881
return (entry_a->uint64 < entry_b->uint64);
862882
}
863883
break;
864-
case ENTRY_INT8:
865-
if (entry_a->uint8 != entry_b->uint8)
866-
return (entry_a->uint8 < entry_b->uint8);
867-
break;
868-
case ENTRY_INT16:
869-
if (entry_a->uint16 != entry_b->uint16)
870-
return (entry_a->uint16 < entry_b->uint16);
871-
break;
872-
case ENTRY_INT32:
873-
if (entry_a->uint32 != entry_b->uint32)
874-
return (entry_a->uint32 < entry_b->uint32);
875-
break;
876-
case ENTRY_INT64:
877-
if (entry_a->uint64 != entry_b->uint64)
878-
return (entry_a->uint64 < entry_b->uint64);
879-
break;
880884
case ENTRY_DEBUG: case ENTRY_INSTRUCTION:
881885
case ENTRY_INSTRUCTION_BYTES: case ENTRY_CONTINUE:
882886
case ENTRY_TAKEN:

src/e9tool/e9frontend.cpp

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3525,6 +3525,20 @@ static void sendMovFromI64ToR64(FILE *out, intptr_t value, int regno)
35253525
fputs("},", out);
35263526
}
35273527

3528+
/*
3529+
* Send a `movabs $i64,%r64' instruction.
3530+
*/
3531+
static void sendMovFromI64ToR64(FILE *out, const char *value, int regno)
3532+
{
3533+
const uint8_t REX[] =
3534+
{0x48, 0x48, 0x48, 0x48, 0x49, 0x49, 0x00,
3535+
0x48, 0x49, 0x49, 0x48, 0x48, 0x49, 0x49, 0x49, 0x49, 0x48};
3536+
const uint8_t OPCODE[] =
3537+
{0xbf, 0xbe, 0xba, 0xb9, 0xb8, 0xb9, 0x00,
3538+
0xb8, 0xba, 0xbb, 0xbb, 0xbd, 0xbc, 0xbd, 0xbe, 0xbf, 0xbc};
3539+
fprintf(out, "%u,%u,%s,", REX[regno], OPCODE[regno], value);
3540+
}
3541+
35283542
/*
35293543
* Send a `lea offset(%rip),%r64' instruction.
35303544
*/

src/e9tool/e9metadata.cpp

Lines changed: 47 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -744,14 +744,11 @@ static void sendOperandDataMetadata(FILE *out, const InstrInfo *I,
744744
}
745745

746746
/*
747-
* Emits instructions to translate an address into a static address, if
748-
* necessary. This essentially just subtracts the ELF base address.
747+
* Emits instructions to translate to/from static and dynamic addresses.
749748
*/
750-
static void sendTranslateToStaticAddress(FILE *out, const InstrInfo *I,
751-
CallInfo &info, bool _static, int regno)
749+
static void sendTranslateAddress(FILE *out, const InstrInfo *I, CallInfo &info,
750+
bool neg, int regno)
752751
{
753-
if (!_static || !info.pic)
754-
return;
755752
Register exclude[] = {getReg(regno), REGISTER_INVALID};
756753
Register rscratch = info.getScratch(exclude);
757754
bool save_rax = false;
@@ -764,27 +761,45 @@ static void sendTranslateToStaticAddress(FILE *out, const InstrInfo *I,
764761
int regno_1 = getRegIdx(rscratch);
765762
sendLeaFromPCRelToR64(out, "{\"rel32\":0}", regno_1);
766763

767-
// The not+lea implement %arg -= %base without affecting %rflags:
768-
769-
// not %reg
770-
const uint8_t REX[] =
771-
{0x48, 0x48, 0x48, 0x48, 0x49, 0x49, 0x00,
772-
0x48, 0x49, 0x49, 0x48, 0x48, 0x49, 0x49, 0x49, 0x49, 0x48};
773-
const uint8_t MODRM[] =
774-
{0xd7, 0xd6, 0xd2, 0xd1, 0xd0, 0xd1, 0x00,
775-
0xd0, 0xd2, 0xd3, 0xd3, 0xd5, 0xd4, 0xd5, 0xd6, 0xd7, 0xd4};
776-
fprintf(out, "%u,%u,%u,", REX[regno_1], 0xf7, MODRM[regno_1]);
764+
int32_t disp = 0x0;
765+
if (neg)
766+
{
767+
// The not+lea implement %arg -= %base without affecting %rflags:
768+
// not %reg
769+
const uint8_t REX[] =
770+
{0x48, 0x48, 0x48, 0x48, 0x49, 0x49, 0x00,
771+
0x48, 0x49, 0x49, 0x48, 0x48, 0x49, 0x49, 0x49, 0x49, 0x48};
772+
const uint8_t MODRM[] =
773+
{0xd7, 0xd6, 0xd2, 0xd1, 0xd0, 0xd1, 0x00,
774+
0xd0, 0xd2, 0xd3, 0xd3, 0xd5, 0xd4, 0xd5, 0xd6, 0xd7, 0xd4};
775+
fprintf(out, "%u,%u,%u,", REX[regno_1], 0xf7, MODRM[regno_1]);
776+
disp = 0x1;
777+
}
777778

778779
// lea 0x1(%arg,%reg,1),%arg
779780
sendLoadFromMemOpToR64(out, I, info, /*size=*/8, /*seg=*/REGISTER_NONE,
780-
/*disp=*/0x1, /*base=*/getReg(regno), /*index=*/rscratch,
781+
disp, /*base=*/getReg(regno), /*index=*/rscratch,
781782
/*scale=*/1, /*lea=*/true, regno, /*asis=*/true);
782783

783784
if (save_rax)
784785
fprintf(out, "%u,", 0x58); // pop %rax
785786
else
786787
info.clobber(rscratch);
787788
}
789+
static void sendTranslateToStaticAddress(FILE *out, const InstrInfo *I,
790+
CallInfo &info, bool _static, int regno)
791+
{
792+
if (!_static || !info.pic)
793+
return;
794+
sendTranslateAddress(out, I, info, /*neg=*/true, regno);
795+
}
796+
static void sendTranslateToDynamicAddress(FILE *out, const InstrInfo *I,
797+
CallInfo &info, bool _static, int regno)
798+
{
799+
if (_static || !info.pic)
800+
return;
801+
sendTranslateAddress(out, I, info, /*neg=*/false, regno);
802+
}
788803

789804
/*
790805
* Emits instructions to load the jump/call/return target into the
@@ -1138,8 +1153,21 @@ static Type sendLoadArgumentMetadata(FILE *out, CallInfo &info,
11381153
t = TYPE_CONST_VOID_PTR;
11391154
break;
11401155
case ARGUMENT_CONFIG:
1141-
sendLoadPointerMetadata(out, info, _static, 0x0,
1142-
"{\"rel32\":\".Lconfig\"}", regno);
1156+
// ELF = "config anywhere", PE = "config close".
1157+
switch (elf->type)
1158+
{
1159+
case BINARY_TYPE_ELF_EXE: case BINARY_TYPE_ELF_DSO:
1160+
case BINARY_TYPE_ELF_PIE:
1161+
sendMovFromI64ToR64(out, "{\"int64\":\".Lconfig\"}",
1162+
regno);
1163+
sendTranslateToDynamicAddress(out, I, info,
1164+
/*static=*/false, regno);
1165+
break;
1166+
case BINARY_TYPE_PE_EXE: case BINARY_TYPE_PE_DLL:
1167+
sendLeaFromPCRelToR64(out, "{\"rel32\":\".Lconfig\"}",
1168+
regno);
1169+
break;
1170+
}
11431171
t = TYPE_CONST_VOID_PTR;
11441172
break;
11451173
case ARGUMENT_ASM:

test/regtest/config.exp

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,14 @@
1+
000000020e9e9000:8877665544332211:8877665544332211: 48 39 c3 cmp %rax, %rbx
2+
000000020e9e9000:8877665544332211:00ffeeddccbbaa99: 48 8b 0d 9a 01 00 00 movq 0x19a(%rip), %rcx
3+
000000020e9e9000:8877665544332211:8877665544332211: 4c 39 c1 cmp %r8, %rcx
4+
000000020e9e9000:8877665544332211:ffffffffffff8889: 48 c7 c1 89 88 ff ff mov $-0x7777, %rcx
5+
000000020e9e9000:0000000000000032:0000000000000032: 48 21 c3 and %rax, %rbx
6+
000000020e9e9000:0000000000004519:0000000000004519: f3 48 0f 2a c0 cvtsi2ss %rax, %xmm0
7+
000000020e9e9000:0000000000000000:0000000000000000: 48 85 c0 test %rax, %rax
8+
000000020e9e9000:0000000000000000:0000000000000000: 48 85 c0 test %rax, %rax
9+
000000020e9e9000:0000000000000000:0000000000000000: 3e 48 8b 8c f4 00 ff ff movq %ds:-0x100(%rsp,%rsi,8), %rcx
10+
ff
11+
000000020e9e9000:0000000000000000:0000000000000000: 48 39 c1 cmp %rax, %rcx
12+
000000020e9e9000:0000000000000000:1cba0b0b0b0bb8c0: 48 8b 8c f0 00 00 00 0a movq 0xa000000(%rax,%rsi,8), %rcx
13+
000000020e9e9000:0000000000000001:0000000000000001: 48 ff c7 inc %rdi
14+
PASSED

test/regtest/config.in

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
./test -M 'op[0] == rax || op[1] == rcx || op[0] == rdi' -A 'call entry(config,rax,op[0],instr,size,asm)@inst'

test/regtest/config_pie.exp

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,14 @@
1+
cmp %rax, %rbx # diff = 0x20e9e9000
2+
movq 0x19a(%rip), %rcx # diff = 0x20e9e9000
3+
cmp %r8, %rcx # diff = 0x20e9e9000
4+
mov $-0x7777, %rcx # diff = 0x20e9e9000
5+
and %rax, %rbx # diff = 0x20e9e9000
6+
cvtsi2ss %rax, %xmm0 # diff = 0x20e9e9000
7+
test %rax, %rax # diff = 0x20e9e9000
8+
test %rax, %rax # diff = 0x20e9e9000
9+
movq %ds:-0x100(%rsp,%rsi,8), %rcx # diff = 0x20e9e9000
10+
cmp %rax, %rcx # diff = 0x20e9e9000
11+
movq 0xa000000(%rax), %rcx # diff = 0x20e9e9000
12+
movq 0xa000000(%rax,%rsi,8), %rcx # diff = 0x20e9e9000
13+
inc %rdi # diff = 0x20e9e9000
14+
PASSED

test/regtest/config_pie.in

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
./test.pie -M 'op[0] == rax || op[1] == rcx || op[0] == rdi' -A 'call diff(base,config,asm)@patch'

test/regtest/patch.cpp

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -465,3 +465,9 @@ const void *stack_overflow(const void *addr, intptr_t *rsp, const char *_asm)
465465
return addr; // loop
466466
}
467467

468+
void diff(const void *a, const void *b, const char *_asm)
469+
{
470+
intptr_t diff = (intptr_t)b - (intptr_t)a;
471+
fprintf(stderr, "%s # diff = 0x%lx\n", _asm, diff);
472+
}
473+

0 commit comments

Comments
 (0)