Last active
December 24, 2015 11:19
-
-
Save rygorous/6790191 to your computer and use it in GitHub Desktop.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Dump of file test.obj | |
File Type: COFF OBJECT | |
RELOCATIONS #1 | |
Symbol Symbol | |
Offset Type Applied To Index Name | |
-------- ---------------- ----------------- -------- ------ | |
00000006 ADDR32 00000000 9 $jump@f <--- ADDR32 for this is not OK! | |
00000013 ADDR64 00000000 00000000 A $L0@f | |
0000001B ADDR64 00000000 00000000 B $L1@f | |
Summary | |
0 .data | |
60 .debug$S | |
23 .text |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
_TEXT SEGMENT | |
f PROC | |
and eax, 1 | |
jmp qword ptr $jump@f[rax*8] ; abs. data references are tricky in x64 code! | |
$L0@f: | |
xor eax, eax | |
ret | |
$L1@f: | |
mov eax, 1 | |
ret | |
$jump@f: | |
dq $L0@f | |
dq $L1@f | |
f ENDP | |
_TEXT ENDS | |
END |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
; cl /c /nologo /O2 /FAs bug2.c (x64) | |
; Listing generated by Microsoft (R) Optimizing Compiler Version 17.00.60610.1 | |
include listing.inc | |
INCLUDELIB LIBCMT | |
INCLUDELIB OLDNAMES | |
PUBLIC f | |
EXTRN __ImageBase:BYTE | |
; Function compile flags: /Ogtpy | |
; File c:\test\bug2.c | |
; COMDAT f | |
_TEXT SEGMENT | |
x$ = 8 | |
f PROC ; COMDAT | |
; 3 : switch (x & 7) { // code doesn't matter, just something to get a jump table | |
mov eax, ecx | |
and eax, 7 | |
cmp eax, 7 | |
ja SHORT $LN6@f | |
lea r8, OFFSET FLAT:__ImageBase | |
cdqe | |
mov edx, DWORD PTR $LN10@f[r8+rax*4] | |
add rdx, r8 | |
jmp rdx | |
$LN5@f: | |
; 4 : case 0: return x + 1; | |
lea eax, DWORD PTR [rcx+1] | |
; 11 : } | |
ret 0 | |
$LN4@f: | |
; 5 : case 1: return x * 3; | |
lea eax, DWORD PTR [rcx+rcx*2] | |
; 11 : } | |
ret 0 | |
$LN3@f: | |
; 6 : case 2: return x * 5; | |
lea eax, DWORD PTR [rcx+rcx*4] | |
; 11 : } | |
ret 0 | |
$LN2@f: | |
; 7 : case 3: return x - 1; | |
lea eax, DWORD PTR [rcx-1] | |
; 11 : } | |
ret 0 | |
$LN1@f: | |
; 8 : case 4: case 5: case 6: case 7: return x; | |
mov eax, ecx | |
; 11 : } | |
ret 0 | |
$LN6@f: | |
; 9 : } | |
; 10 : return 0; | |
xor eax, eax | |
; 11 : } | |
ret 0 | |
npad 2 | |
$LN10@f: | |
DD $LN5@f | |
DD $LN4@f | |
DD $LN3@f | |
DD $LN2@f | |
DD $LN1@f | |
DD $LN1@f | |
DD $LN1@f | |
DD $LN1@f | |
f ENDP | |
_TEXT ENDS | |
END |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
int f(int x) | |
{ | |
switch (x & 7) { // code doesn't matter, just something to get a jump table | |
case 0: return x + 1; | |
case 1: return x * 3; | |
case 2: return x * 5; | |
case 3: return x - 1; | |
case 4: case 5: case 6: case 7: return x; | |
} | |
return 0; | |
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
C:\test>ml64 /c /nologo bug2.asm | |
Assembling: bug2.asm | |
bug2.asm(23) : error A2006:undefined symbol : FLAT | |
---> So edit by hand to remove "FLAT:", producing bug2b.asm |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Now compare relocations in output OBJ for bug2.c ("cl /c /O2 /nologo bug2.c") vs bug2b.asm ("ml64 /c /nologo bug2b.asm"): | |
C:\test>dumpbin /relocations bug2.obj | |
Microsoft (R) COFF/PE Dumper Version 11.00.60610.1 | |
Copyright (C) Microsoft Corporation. All rights reserved. | |
Dump of file bug2.obj | |
File Type: COFF OBJECT | |
RELOCATIONS #3 | |
Symbol Symbol | |
Offset Type Applied To Index Name | |
-------- ---------------- ----------------- -------- ------ | |
0000000D REL32 00000000 F __ImageBase | |
00000017 ADDR32NB 00000000 9 $LN10 | |
00000038 ADDR32NB 00000000 A $LN5 | |
0000003C ADDR32NB 00000000 B $LN4 | |
00000040 ADDR32NB 00000000 C $LN3 | |
00000044 ADDR32NB 00000000 D $LN2 | |
00000048 ADDR32NB 00000000 E $LN1 | |
0000004C ADDR32NB 00000000 E $LN1 | |
00000050 ADDR32NB 00000000 E $LN1 | |
00000054 ADDR32NB 00000000 E $LN1 | |
Summary | |
64 .debug$S | |
2F .drectve | |
58 .text | |
vs. | |
C:\test>dumpbin /relocations bug2b.obj | |
Microsoft (R) COFF/PE Dumper Version 11.00.60610.1 | |
Copyright (C) Microsoft Corporation. All rights reserved. | |
Dump of file bug2b.obj | |
File Type: COFF OBJECT | |
RELOCATIONS #1 | |
Symbol Symbol | |
Offset Type Applied To Index Name | |
-------- ---------------- ----------------- -------- ------ | |
0000000D REL32 00000000 A __ImageBase | |
00000017 ADDR32 00000000 C $LN10@f | |
00000038 ADDR32 00000000 D $LN5@f | |
0000003C ADDR32 00000000 E $LN4@f | |
00000040 ADDR32 00000000 F $LN3@f | |
00000044 ADDR32 00000000 10 $LN2@f | |
00000048 ADDR32 00000000 11 $LN1@f | |
0000004C ADDR32 00000000 11 $LN1@f | |
00000050 ADDR32 00000000 11 $LN1@f | |
00000054 ADDR32 00000000 11 $LN1@f | |
Summary | |
0 .data | |
60 .debug$S | |
28 .drectve | |
58 .text | |
NOTE how these are all ADDR32 (broken) instead of ADDR32NB (relative to image base). The compiler | |
clearly expects the LEA for ImageBase to be emitted as RIP-relative, then the remaining offsets | |
to be ADDR32NB (see e.g. addition of r8 in the jump table access). | |
Can manually fix the jump table by making all offsets IMAGEREL: | |
$LN10@f: | |
DD IMAGEREL $LN5@f | |
DD IMAGEREL $LN4@f | |
DD IMAGEREL $LN3@f | |
DD IMAGEREL $LN2@f | |
DD IMAGEREL $LN1@f | |
DD IMAGEREL $LN1@f | |
DD IMAGEREL $LN1@f | |
DD IMAGEREL $LN1@f | |
(rest as before). Call this "bug2c.asm". This assembles to an object file with these relocations: | |
Dump of file bug2c.obj | |
File Type: COFF OBJECT | |
RELOCATIONS #1 | |
Symbol Symbol | |
Offset Type Applied To Index Name | |
-------- ---------------- ----------------- -------- ------ | |
0000000D REL32 00000000 A __ImageBase | |
00000017 ADDR32 00000000 C $LN10@f | |
00000038 ADDR32NB 00000000 D $LN5@f | |
0000003C ADDR32NB 00000000 E $LN4@f | |
00000040 ADDR32NB 00000000 F $LN3@f | |
00000044 ADDR32NB 00000000 10 $LN2@f | |
00000048 ADDR32NB 00000000 11 $LN1@f | |
0000004C ADDR32NB 00000000 11 $LN1@f | |
00000050 ADDR32NB 00000000 11 $LN1@f | |
00000054 ADDR32NB 00000000 11 $LN1@f | |
Note how the jump table is now correct, but the reference to the jump table is still broken. | |
The "natural" fix from where I'm standing would be to change the instruction from | |
mov edx, DWORD PTR $LN10@f[r8+rax*4] | |
to | |
mov edx, DWORD PTR (IMAGEREL $LN10@f)[r8+rax*4] | |
But alas, this produces: | |
C:\test>ml64 /nologo /c bug2d.asm | |
Assembling: bug2d.asm | |
bug2d.asm(25) : error A2102:cannot add memory expression and code label | |
Unless there's some other construct for this case that I'm not aware of, there seems to be | |
no way to assemble that jump table reference in a way that actually works. That is the actual | |
problem I was running into. | |
And either way, the fact that the listing produced by the compiler doesn't assemble with ML64, | |
and even after removing the "FLAT:" reference assembles to something that looks good but means | |
something different (and in particular has broken relocations) seems bad. |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment