Skip to content

Commit 83680f8

Browse files
authored
[X86AsmParser] Check displacement overflow (#75747)
A displacement is an 8-, 16-, or 32-bit value. LLVM integrated assembler silently encodes an out-of-range displacement. GNU assembler checks the displacement and may report a warning or error (error is for 64-bit addressing, done as part of https://sourceware.org/PR10636). ``` movq 0x80000000(%rip), %rax Error: 0x80000000 out of range of signed 32bit displacement movq -0x080000001(%rax), %rax Error: 0xffffffff7fffffff out of range of signed 32bit displacement movl 0x100000001(%eax), %eax Warning: 0x100000001 shortened to 0x1 ``` For 32-bit addressing, GNU assembler gives no diagnostic when the displacement is within `[-2**32,2**32)`. 16-bit addressing is similar. ``` movl 0xffffffff(%eax), %eax # no diagnostic movl -0xffffffff(%eax), %eax # no diagnostic ``` Supporting a larger range is probably because wraparound using a large constant is more reasonable. E.g. Linux kernel arch/x86/kernel/head_32.S has `leal -__PAGE_OFFSET(%ecx),%esp` where `__PAGE_OFFSET` is 0xc0000000. This patch implements a similar behavior.
1 parent b9935bb commit 83680f8

File tree

5 files changed

+99
-32
lines changed

5 files changed

+99
-32
lines changed

llvm/lib/Target/X86/AsmParser/X86AsmParser.cpp

Lines changed: 29 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3062,6 +3062,35 @@ bool X86AsmParser::ParseMemOperand(unsigned SegReg, const MCExpr *Disp,
30623062
ErrMsg))
30633063
return Error(BaseLoc, ErrMsg);
30643064

3065+
// If the displacement is a constant, check overflows. For 64-bit addressing,
3066+
// gas requires isInt<32> and otherwise reports an error. For others, gas
3067+
// reports a warning and allows a wider range. E.g. gas allows
3068+
// [-0xffffffff,0xffffffff] for 32-bit addressing (e.g. Linux kernel uses
3069+
// `leal -__PAGE_OFFSET(%ecx),%esp` where __PAGE_OFFSET is 0xc0000000).
3070+
if (BaseReg || IndexReg) {
3071+
if (auto CE = dyn_cast<MCConstantExpr>(Disp)) {
3072+
auto Imm = CE->getValue();
3073+
bool Is64 = X86MCRegisterClasses[X86::GR64RegClassID].contains(BaseReg) ||
3074+
X86MCRegisterClasses[X86::GR64RegClassID].contains(IndexReg);
3075+
bool Is16 = X86MCRegisterClasses[X86::GR16RegClassID].contains(BaseReg);
3076+
if (Is64) {
3077+
if (!isInt<32>(Imm))
3078+
return Error(BaseLoc, "displacement " + Twine(Imm) +
3079+
" is not within [-2147483648, 2147483647]");
3080+
} else if (!Is16) {
3081+
if (!isUInt<32>(Imm < 0 ? -uint64_t(Imm) : uint64_t(Imm))) {
3082+
Warning(BaseLoc, "displacement " + Twine(Imm) +
3083+
" shortened to 32-bit signed " +
3084+
Twine(static_cast<int32_t>(Imm)));
3085+
}
3086+
} else if (!isUInt<16>(Imm < 0 ? -uint64_t(Imm) : uint64_t(Imm))) {
3087+
Warning(BaseLoc, "displacement " + Twine(Imm) +
3088+
" shortened to 16-bit signed " +
3089+
Twine(static_cast<int16_t>(Imm)));
3090+
}
3091+
}
3092+
}
3093+
30653094
if (SegReg || BaseReg || IndexReg)
30663095
Operands.push_back(X86Operand::CreateMem(getPointerWidth(), SegReg, Disp,
30673096
BaseReg, IndexReg, Scale, StartLoc,
Lines changed: 38 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,38 @@
1+
# RUN: not llvm-mc -triple=x86_64 %s 2>&1 | FileCheck %s --check-prefixes=CHECK,64 --implicit-check-not=error: --implicit-check-not=warning:
2+
# RUN: llvm-mc -triple=i686 --defsym A16=1 %s 2>&1 | FileCheck %s --check-prefixes=CHECK,32 --implicit-check-not=error: --implicit-check-not=warning:
3+
4+
.ifndef A16
5+
movq 0x80000000-1(%rip), %rax
6+
leaq -0x80000000(%rip), %rax
7+
8+
# 64: [[#@LINE+1]]:17: error: displacement 2147483648 is not within [-2147483648, 2147483647]
9+
movq 0x80000000(%rip), %rax
10+
11+
# 64: [[#@LINE+1]]:18: error: displacement -2147483649 is not within [-2147483648, 2147483647]
12+
leaq -0x80000001(%rip), %rax
13+
.endif
14+
15+
movl 0xffffffff(%eax), %eax
16+
leal -0xffffffff(%eax), %eax
17+
18+
# CHECK: [[#@LINE+1]]:19: warning: displacement 4294967296 shortened to 32-bit signed 0
19+
movl 0xffffffff+1(%eax), %eax
20+
21+
# CHECK: [[#@LINE+1]]:20: warning: displacement -4294967296 shortened to 32-bit signed 0
22+
leal -0xffffffff-1(%eax), %eax
23+
# CHECK: [[#@LINE+1]]:20: warning: displacement -4294967297 shortened to 32-bit signed -1
24+
leal -0xffffffff-2(%eax), %eax
25+
26+
{disp8} leal 0x100(%ebx), %eax
27+
{disp8} leal -0x100(%ebx), %eax
28+
29+
.ifdef A16
30+
.code16
31+
movw $0, 0xffff(%bp)
32+
movw $0, -0xffff(%si)
33+
34+
# 32: [[#@LINE+1]]:19: warning: displacement 65536 shortened to 16-bit signed 0
35+
movw $0, 0xffff+1(%bp)
36+
# 32: [[#@LINE+1]]:20: warning: displacement -65536 shortened to 16-bit signed 0
37+
movw $0, -0xffff-1(%si)
38+
.endif

llvm/test/MC/X86/x86-64.s

Lines changed: 26 additions & 26 deletions
Original file line numberDiff line numberDiff line change
@@ -346,11 +346,11 @@ fnstsw %ax
346346

347347
// rdar://8431880
348348
// CHECK: rclb %bl
349-
// CHECK: rcll 3735928559(%ebx,%ecx,8)
349+
// CHECK: rcll 2125315823(%ebx,%ecx,8)
350350
// CHECK: rcrl %ecx
351351
// CHECK: rcrl 305419896
352352
rcl %bl
353-
rcll 0xdeadbeef(%ebx,%ecx,8)
353+
rcll 0x7eadbeef(%ebx,%ecx,8)
354354
rcr %ecx
355355
rcrl 0x12345678
356356

@@ -573,9 +573,9 @@ leaq 8(%rax), %rsi
573573
// CHECK: encoding: [0x48,0x8d,0x70,0x08]
574574

575575

576-
cvttpd2dq 0xdeadbeef(%ebx,%ecx,8),%xmm5
577-
// CHECK: cvttpd2dq 3735928559(%ebx,%ecx,8), %xmm5
578-
// CHECK: encoding: [0x67,0x66,0x0f,0xe6,0xac,0xcb,0xef,0xbe,0xad,0xde]
576+
cvttpd2dq 0x7eadbeef(%ebx,%ecx,8),%xmm5
577+
// CHECK: cvttpd2dq 2125315823(%ebx,%ecx,8), %xmm5
578+
// CHECK: encoding: [0x67,0x66,0x0f,0xe6,0xac,0xcb,0xef,0xbe,0xad,0x7e]
579579

580580
// rdar://8490728 - llvm-mc rejects 'movmskpd'
581581
movmskpd %xmm6, %rax
@@ -906,8 +906,8 @@ xchgl %ecx, 368(%rax)
906906
// CHECK: xchgl %ecx, 368(%rax)
907907

908908
// rdar://8407548
909-
xchg 0xdeadbeef(%rbx,%rcx,8),%bl
910-
// CHECK: xchgb %bl, 3735928559(%rbx,%rcx,8)
909+
xchg 0x7fffffff(%rbx,%rcx,8),%bl
910+
// CHECK: xchgb %bl, 2147483647(%rbx,%rcx,8)
911911

912912

913913

@@ -1112,31 +1112,31 @@ mov %gs, (%rsi) // CHECK: movw %gs, (%rsi) # encoding: [0x8c,0x2e]
11121112
//CHECK: divb %bl
11131113
//CHECK: divw %bx
11141114
//CHECK: divl %ecx
1115-
//CHECK: divl 3735928559(%ebx,%ecx,8)
1115+
//CHECK: divl 2125315823(%ebx,%ecx,8)
11161116
//CHECK: divl 69
11171117
//CHECK: divl 32493
11181118
//CHECK: divl 3133065982
11191119
//CHECK: divl 305419896
11201120
//CHECK: idivb %bl
11211121
//CHECK: idivw %bx
11221122
//CHECK: idivl %ecx
1123-
//CHECK: idivl 3735928559(%ebx,%ecx,8)
1123+
//CHECK: idivl 2125315823(%ebx,%ecx,8)
11241124
//CHECK: idivl 69
11251125
//CHECK: idivl 32493
11261126
//CHECK: idivl 3133065982
11271127
//CHECK: idivl 305419896
11281128
div %bl,%al
11291129
div %bx,%ax
11301130
div %ecx,%eax
1131-
div 0xdeadbeef(%ebx,%ecx,8),%eax
1131+
div 0x7eadbeef(%ebx,%ecx,8),%eax
11321132
div 0x45,%eax
11331133
div 0x7eed,%eax
11341134
div 0xbabecafe,%eax
11351135
div 0x12345678,%eax
11361136
idiv %bl,%al
11371137
idiv %bx,%ax
11381138
idiv %ecx,%eax
1139-
idiv 0xdeadbeef(%ebx,%ecx,8),%eax
1139+
idiv 0x7eadbeef(%ebx,%ecx,8),%eax
11401140
idiv 0x45,%eax
11411141
idiv 0x7eed,%eax
11421142
idiv 0xbabecafe,%eax
@@ -1510,9 +1510,9 @@ vmovd %xmm0, %eax
15101510
vmovd %xmm0, %rax
15111511
vmovq %xmm0, %rax
15121512

1513-
// CHECK: seto 3735928559(%r10,%r9,8)
1514-
// CHECK: encoding: [0x43,0x0f,0x90,0x84,0xca,0xef,0xbe,0xad,0xde]
1515-
seto 0xdeadbeef(%r10,%r9,8)
1513+
// CHECK: seto 2125315823(%r10,%r9,8)
1514+
// CHECK: encoding: [0x43,0x0f,0x90,0x84,0xca,0xef,0xbe,0xad,0x7e]
1515+
seto 0x7eadbeef(%r10,%r9,8)
15161516

15171517
// CHECK: monitorx
15181518
// CHECK: encoding: [0x0f,0x01,0xfa]
@@ -1550,9 +1550,9 @@ vmovq %xmm0, %rax
15501550
// CHECK: encoding: [0x47,0x89,0x3c,0x3f]
15511551
movl %r15d, (%r15,%r15)
15521552

1553-
// CHECK: nopq 3735928559(%rbx,%rcx,8)
1554-
// CHECK: encoding: [0x48,0x0f,0x1f,0x84,0xcb,0xef,0xbe,0xad,0xde]
1555-
nopq 0xdeadbeef(%rbx,%rcx,8)
1553+
// CHECK: nopq 2125315823(%rbx,%rcx,8)
1554+
// CHECK: encoding: [0x48,0x0f,0x1f,0x84,0xcb,0xef,0xbe,0xad,0x7e]
1555+
nopq 0x7eadbeef(%rbx,%rcx,8)
15561556

15571557
// CHECK: nopq %rax
15581558
// CHECK: encoding: [0x48,0x0f,0x1f,0xc0]
@@ -1562,17 +1562,17 @@ nopq %rax
15621562
// CHECK: encoding: [0xf3,0x0f,0xc7,0xf8]
15631563
rdpid %rax
15641564

1565-
// CHECK: ptwritel 3735928559(%rbx,%rcx,8)
1566-
// CHECK: encoding: [0xf3,0x0f,0xae,0xa4,0xcb,0xef,0xbe,0xad,0xde]
1567-
ptwritel 0xdeadbeef(%rbx,%rcx,8)
1565+
// CHECK: ptwritel 2125315823(%rbx,%rcx,8)
1566+
// CHECK: encoding: [0xf3,0x0f,0xae,0xa4,0xcb,0xef,0xbe,0xad,0x7e]
1567+
ptwritel 0x7eadbeef(%rbx,%rcx,8)
15681568

15691569
// CHECK: ptwritel %eax
15701570
// CHECK: encoding: [0xf3,0x0f,0xae,0xe0]
15711571
ptwritel %eax
15721572

1573-
// CHECK: ptwriteq 3735928559(%rbx,%rcx,8)
1574-
// CHECK: encoding: [0xf3,0x48,0x0f,0xae,0xa4,0xcb,0xef,0xbe,0xad,0xde]
1575-
ptwriteq 0xdeadbeef(%rbx,%rcx,8)
1573+
// CHECK: ptwriteq 2125315823(%rbx,%rcx,8)
1574+
// CHECK: encoding: [0xf3,0x48,0x0f,0xae,0xa4,0xcb,0xef,0xbe,0xad,0x7e]
1575+
ptwriteq 0x7eadbeef(%rbx,%rcx,8)
15761576

15771577
// CHECK: ptwriteq %rax
15781578
// CHECK: encoding: [0xf3,0x48,0x0f,0xae,0xe0]
@@ -1586,9 +1586,9 @@ wbnoinvd
15861586
// CHECK: encoding: [0x0f,0x1c,0x40,0x04]
15871587
cldemote 4(%rax)
15881588

1589-
// CHECK: cldemote 3735928559(%rbx,%rcx,8)
1590-
// CHECK: encoding: [0x0f,0x1c,0x84,0xcb,0xef,0xbe,0xad,0xde]
1591-
cldemote 0xdeadbeef(%rbx,%rcx,8)
1589+
// CHECK: cldemote 2125315823(%rbx,%rcx,8)
1590+
// CHECK: encoding: [0x0f,0x1c,0x84,0xcb,0xef,0xbe,0xad,0x7e]
1591+
cldemote 0x7eadbeef(%rbx,%rcx,8)
15921592

15931593
// CHECK: umonitor %r13
15941594
// CHECK: encoding: [0xf3,0x41,0x0f,0xae,0xf5]

llvm/test/MC/X86/x86_64-asm-match.s

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -31,9 +31,9 @@
3131
// CHECK: Opcode result: complete match, selecting this opcode
3232
// CHECK: AsmMatcher: found 2 encodings with mnemonic 'crc32l'
3333
// CHECK: Trying to match opcode CRC32r32r32
34-
// CHECK: Matching formal operand class MCK_GR32 against actual operand at index 1 (Memory: ModeSize=64,BaseReg=rbx,IndexReg=rcx,Scale=8,Disp=3735928559,SegReg=gs): Opcode result: multiple operand mismatches, ignoring this opcode
34+
// CHECK: Matching formal operand class MCK_GR32 against actual operand at index 1 (Memory: ModeSize=64,BaseReg=rbx,IndexReg=rcx,Scale=8,Disp=2125315823,SegReg=gs): Opcode result: multiple operand mismatches, ignoring this opcode
3535
// CHECK: Trying to match opcode CRC32r32m32
36-
// CHECK: Matching formal operand class MCK_Mem32 against actual operand at index 1 (Memory: ModeSize=64,BaseReg=rbx,IndexReg=rcx,Scale=8,Disp=3735928559,SegReg=gs): match success using generic matcher
36+
// CHECK: Matching formal operand class MCK_Mem32 against actual operand at index 1 (Memory: ModeSize=64,BaseReg=rbx,IndexReg=rcx,Scale=8,Disp=2125315823,SegReg=gs): match success using generic matcher
3737
// CHECK: Matching formal operand class MCK_GR32 against actual operand at index 2 (Reg:ecx): match success using generic matcher
3838
// CHECK: Matching formal operand class InvalidMatchClass against actual operand at index 3: actual operand index out of range
3939
// CHECK: Opcode result: complete match, selecting this opcode
@@ -62,7 +62,7 @@
6262
pshufb CPI1_0(%rip), %xmm1
6363
sha1rnds4 $1, %xmm1, %xmm2
6464
pinsrw $3, %ecx, %xmm5
65-
crc32l %gs:0xdeadbeef(%rbx,%rcx,8),%ecx
65+
crc32l %gs:0x7eadbeef(%rbx,%rcx,8),%ecx
6666
maskmovdqu %xmm0, %xmm1
6767
vmaskmovdqu %xmm0, %xmm1
6868

llvm/test/MC/X86/x86_64-encoding.s

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -29,9 +29,9 @@ movq %gs:(%rdi), %rax
2929
// CHECK: encoding: [0xf2,0x0f,0x38,0xf1,0x43,0x04]
3030
crc32l 4(%rbx), %eax
3131

32-
// CHECK: crc32l 3735928559(%rbx,%rcx,8), %ecx
33-
// CHECK: encoding: [0xf2,0x0f,0x38,0xf1,0x8c,0xcb,0xef,0xbe,0xad,0xde]
34-
crc32l 0xdeadbeef(%rbx,%rcx,8),%ecx
32+
// CHECK: crc32l 2125315823(%rbx,%rcx,8), %ecx
33+
// CHECK: encoding: [0xf2,0x0f,0x38,0xf1,0x8c,0xcb,0xef,0xbe,0xad,0x7e]
34+
crc32l 0x7eadbeef(%rbx,%rcx,8),%ecx
3535

3636
// CHECK: crc32l 69, %ecx
3737
// CHECK: encoding: [0xf2,0x0f,0x38,0xf1,0x0c,0x25,0x45,0x00,0x00,0x00]

0 commit comments

Comments
 (0)