x86: Fix implicit stack addressing in 64-bit mode
When in 64-bit mode, if the stack is accessed implicitly by an instruction the alternate address prefix should be ignored if present. This patch adds an extra flag to the ldstop which signifies when the address override should be ignored. Then, for all of the affected instructions, this patch adds two options to the ld and st opcode to use the current stack addressing mode for all addresses and to ignore the AddressSizeFlagBit. Finally, this patch updates the x86 TLB to not truncate the address if it is in 64-bit mode and the IgnoreAddrSizeFlagBit is set. This fixes a problem when calling __libc_start_main with a binary that is linked with a recent version of ld. This version of ld uses the address override prefix (0x67) on the call instruction instead of a nop. Note: This has not been tested in compatibility mode and only the call instruction with the address override prefix has been tested. See [1] page 9 (pdf page 45) For instructions that are affected see [1] page 519 (pdf page 555). [1] http://support.amd.com/TechDocs/24594.pdf Signed-off-by: Jason Lowe-Power <jason@lowepower.com>
This commit is contained in:
parent
87b9f0b87b
commit
153e5879c6
3 changed files with 69 additions and 35 deletions
|
@ -45,7 +45,7 @@ def macroop CALL_NEAR_I
|
||||||
limm t1, imm
|
limm t1, imm
|
||||||
rdip t7
|
rdip t7
|
||||||
# Check target of call
|
# Check target of call
|
||||||
st t7, ss, [0, t0, rsp], "-env.dataSize"
|
stis t7, ss, [0, t0, rsp], "-env.dataSize"
|
||||||
subi rsp, rsp, ssz
|
subi rsp, rsp, ssz
|
||||||
wrip t7, t1
|
wrip t7, t1
|
||||||
};
|
};
|
||||||
|
@ -58,7 +58,7 @@ def macroop CALL_NEAR_R
|
||||||
|
|
||||||
rdip t1
|
rdip t1
|
||||||
# Check target of call
|
# Check target of call
|
||||||
st t1, ss, [0, t0, rsp], "-env.dataSize"
|
stis t1, ss, [0, t0, rsp], "-env.dataSize"
|
||||||
subi rsp, rsp, ssz
|
subi rsp, rsp, ssz
|
||||||
wripi reg, 0
|
wripi reg, 0
|
||||||
};
|
};
|
||||||
|
|
|
@ -40,7 +40,7 @@ def macroop POP_R {
|
||||||
# Make the default data size of pops 64 bits in 64 bit mode
|
# Make the default data size of pops 64 bits in 64 bit mode
|
||||||
.adjust_env oszIn64Override
|
.adjust_env oszIn64Override
|
||||||
|
|
||||||
ld t1, ss, [1, t0, rsp], dataSize=ssz
|
ldis t1, ss, [1, t0, rsp], dataSize=ssz
|
||||||
addi rsp, rsp, ssz, dataSize=asz
|
addi rsp, rsp, ssz, dataSize=asz
|
||||||
mov reg, reg, t1
|
mov reg, reg, t1
|
||||||
};
|
};
|
||||||
|
@ -49,7 +49,7 @@ def macroop POP_M {
|
||||||
# Make the default data size of pops 64 bits in 64 bit mode
|
# Make the default data size of pops 64 bits in 64 bit mode
|
||||||
.adjust_env oszIn64Override
|
.adjust_env oszIn64Override
|
||||||
|
|
||||||
ld t1, ss, [1, t0, rsp], dataSize=ssz
|
ldis t1, ss, [1, t0, rsp], dataSize=ssz
|
||||||
cda seg, sib, disp, dataSize=ssz
|
cda seg, sib, disp, dataSize=ssz
|
||||||
addi rsp, rsp, ssz, dataSize=asz
|
addi rsp, rsp, ssz, dataSize=asz
|
||||||
st t1, seg, sib, disp, dataSize=ssz
|
st t1, seg, sib, disp, dataSize=ssz
|
||||||
|
@ -70,7 +70,7 @@ def macroop PUSH_R {
|
||||||
# Make the default data size of pops 64 bits in 64 bit mode
|
# Make the default data size of pops 64 bits in 64 bit mode
|
||||||
.adjust_env oszIn64Override
|
.adjust_env oszIn64Override
|
||||||
|
|
||||||
st reg, ss, [1, t0, rsp], "-env.stackSize", dataSize=ssz
|
stis reg, ss, [1, t0, rsp], "-env.stackSize", dataSize=ssz
|
||||||
subi rsp, rsp, ssz
|
subi rsp, rsp, ssz
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -79,7 +79,7 @@ def macroop PUSH_I {
|
||||||
.adjust_env oszIn64Override
|
.adjust_env oszIn64Override
|
||||||
|
|
||||||
limm t1, imm
|
limm t1, imm
|
||||||
st t1, ss, [1, t0, rsp], "-env.stackSize", dataSize=ssz
|
stis t1, ss, [1, t0, rsp], "-env.stackSize", dataSize=ssz
|
||||||
subi rsp, rsp, ssz
|
subi rsp, rsp, ssz
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -138,7 +138,7 @@ def macroop LEAVE {
|
||||||
.adjust_env oszIn64Override
|
.adjust_env oszIn64Override
|
||||||
|
|
||||||
mov t1, t1, rbp, dataSize=ssz
|
mov t1, t1, rbp, dataSize=ssz
|
||||||
ld rbp, ss, [1, t0, t1], dataSize=ssz
|
ldis rbp, ss, [1, t0, t1], dataSize=ssz
|
||||||
mov rsp, rsp, t1, dataSize=ssz
|
mov rsp, rsp, t1, dataSize=ssz
|
||||||
addi rsp, rsp, ssz, dataSize=ssz
|
addi rsp, rsp, ssz, dataSize=ssz
|
||||||
};
|
};
|
||||||
|
@ -156,7 +156,7 @@ def macroop ENTER_I_I {
|
||||||
# t1 is now the masked nesting level, and t2 is the amount of storage.
|
# t1 is now the masked nesting level, and t2 is the amount of storage.
|
||||||
|
|
||||||
# Push rbp.
|
# Push rbp.
|
||||||
st rbp, ss, [1, t0, rsp], "-env.dataSize"
|
stis rbp, ss, [1, t0, rsp], "-env.dataSize"
|
||||||
subi rsp, rsp, ssz
|
subi rsp, rsp, ssz
|
||||||
|
|
||||||
# Save the stack pointer for later
|
# Save the stack pointer for later
|
||||||
|
@ -172,8 +172,8 @@ def macroop ENTER_I_I {
|
||||||
|
|
||||||
limm t4, "ULL(-1)", dataSize=8
|
limm t4, "ULL(-1)", dataSize=8
|
||||||
topOfLoop:
|
topOfLoop:
|
||||||
ld t5, ss, [dsz, t4, rbp]
|
ldis t5, ss, [dsz, t4, rbp]
|
||||||
st t5, ss, [1, t0, rsp], "-env.dataSize"
|
stis t5, ss, [1, t0, rsp], "-env.dataSize"
|
||||||
subi rsp, rsp, ssz
|
subi rsp, rsp, ssz
|
||||||
|
|
||||||
# If we're not done yet, loop
|
# If we're not done yet, loop
|
||||||
|
@ -183,7 +183,7 @@ topOfLoop:
|
||||||
|
|
||||||
bottomOfLoop:
|
bottomOfLoop:
|
||||||
# Push the old rbp onto the stack
|
# Push the old rbp onto the stack
|
||||||
st t6, ss, [1, t0, rsp], "-env.dataSize"
|
stis t6, ss, [1, t0, rsp], "-env.dataSize"
|
||||||
subi rsp, rsp, ssz
|
subi rsp, rsp, ssz
|
||||||
|
|
||||||
skipLoop:
|
skipLoop:
|
||||||
|
|
|
@ -315,7 +315,8 @@ def template MicroLdStSplitOpConstructor {{
|
||||||
let {{
|
let {{
|
||||||
class LdStOp(X86Microop):
|
class LdStOp(X86Microop):
|
||||||
def __init__(self, data, segment, addr, disp,
|
def __init__(self, data, segment, addr, disp,
|
||||||
dataSize, addressSize, baseFlags, atCPL0, prefetch, nonSpec):
|
dataSize, addressSize, baseFlags, atCPL0, prefetch, nonSpec,
|
||||||
|
implicitStack):
|
||||||
self.data = data
|
self.data = data
|
||||||
[self.scale, self.index, self.base] = addr
|
[self.scale, self.index, self.base] = addr
|
||||||
self.disp = disp
|
self.disp = disp
|
||||||
|
@ -331,8 +332,11 @@ let {{
|
||||||
self.instFlags += " | (1ULL << StaticInst::IsDataPrefetch)"
|
self.instFlags += " | (1ULL << StaticInst::IsDataPrefetch)"
|
||||||
if nonSpec:
|
if nonSpec:
|
||||||
self.instFlags += " | (1ULL << StaticInst::IsNonSpeculative)"
|
self.instFlags += " | (1ULL << StaticInst::IsNonSpeculative)"
|
||||||
self.memFlags += " | (machInst.legacy.addr ? " + \
|
# For implicit stack operations, we should use *not* use the
|
||||||
"(AddrSizeFlagBit << FlagShift) : 0)"
|
# alternative addressing mode for loads/stores if the prefix is set
|
||||||
|
if not implicitStack:
|
||||||
|
self.memFlags += " | (machInst.legacy.addr ? " + \
|
||||||
|
"(AddrSizeFlagBit << FlagShift) : 0)"
|
||||||
|
|
||||||
def getAllocator(self, microFlags):
|
def getAllocator(self, microFlags):
|
||||||
allocator = '''new %(class_name)s(machInst, macrocodeBlock,
|
allocator = '''new %(class_name)s(machInst, macrocodeBlock,
|
||||||
|
@ -351,7 +355,8 @@ let {{
|
||||||
|
|
||||||
class BigLdStOp(X86Microop):
|
class BigLdStOp(X86Microop):
|
||||||
def __init__(self, data, segment, addr, disp,
|
def __init__(self, data, segment, addr, disp,
|
||||||
dataSize, addressSize, baseFlags, atCPL0, prefetch, nonSpec):
|
dataSize, addressSize, baseFlags, atCPL0, prefetch, nonSpec,
|
||||||
|
implicitStack):
|
||||||
self.data = data
|
self.data = data
|
||||||
[self.scale, self.index, self.base] = addr
|
[self.scale, self.index, self.base] = addr
|
||||||
self.disp = disp
|
self.disp = disp
|
||||||
|
@ -367,8 +372,11 @@ let {{
|
||||||
self.instFlags += " | (1ULL << StaticInst::IsDataPrefetch)"
|
self.instFlags += " | (1ULL << StaticInst::IsDataPrefetch)"
|
||||||
if nonSpec:
|
if nonSpec:
|
||||||
self.instFlags += " | (1ULL << StaticInst::IsNonSpeculative)"
|
self.instFlags += " | (1ULL << StaticInst::IsNonSpeculative)"
|
||||||
self.memFlags += " | (machInst.legacy.addr ? " + \
|
# For implicit stack operations, we should use *not* use the
|
||||||
"(AddrSizeFlagBit << FlagShift) : 0)"
|
# alternative addressing mode for loads/stores if the prefix is set
|
||||||
|
if not implicitStack:
|
||||||
|
self.memFlags += " | (machInst.legacy.addr ? " + \
|
||||||
|
"(AddrSizeFlagBit << FlagShift) : 0)"
|
||||||
|
|
||||||
def getAllocator(self, microFlags):
|
def getAllocator(self, microFlags):
|
||||||
allocString = '''
|
allocString = '''
|
||||||
|
@ -395,9 +403,11 @@ let {{
|
||||||
|
|
||||||
class LdStSplitOp(LdStOp):
|
class LdStSplitOp(LdStOp):
|
||||||
def __init__(self, data, segment, addr, disp,
|
def __init__(self, data, segment, addr, disp,
|
||||||
dataSize, addressSize, baseFlags, atCPL0, prefetch, nonSpec):
|
dataSize, addressSize, baseFlags, atCPL0, prefetch, nonSpec,
|
||||||
|
implicitStack):
|
||||||
super(LdStSplitOp, self).__init__(0, segment, addr, disp,
|
super(LdStSplitOp, self).__init__(0, segment, addr, disp,
|
||||||
dataSize, addressSize, baseFlags, atCPL0, prefetch, nonSpec)
|
dataSize, addressSize, baseFlags, atCPL0, prefetch, nonSpec,
|
||||||
|
implicitStack)
|
||||||
(self.dataLow, self.dataHi) = data
|
(self.dataLow, self.dataHi) = data
|
||||||
|
|
||||||
def getAllocator(self, microFlags):
|
def getAllocator(self, microFlags):
|
||||||
|
@ -435,7 +445,8 @@ let {{
|
||||||
calculateEA = 'EA = SegBase + ' + segmentEAExpr
|
calculateEA = 'EA = SegBase + ' + segmentEAExpr
|
||||||
|
|
||||||
def defineMicroLoadOp(mnemonic, code, bigCode='',
|
def defineMicroLoadOp(mnemonic, code, bigCode='',
|
||||||
mem_flags="0", big=True, nonSpec=False):
|
mem_flags="0", big=True, nonSpec=False,
|
||||||
|
implicitStack=False):
|
||||||
global header_output
|
global header_output
|
||||||
global decoder_output
|
global decoder_output
|
||||||
global exec_output
|
global exec_output
|
||||||
|
@ -460,17 +471,26 @@ let {{
|
||||||
exec_output += MicroLoadInitiateAcc.subst(iop)
|
exec_output += MicroLoadInitiateAcc.subst(iop)
|
||||||
exec_output += MicroLoadCompleteAcc.subst(iop)
|
exec_output += MicroLoadCompleteAcc.subst(iop)
|
||||||
|
|
||||||
|
if implicitStack:
|
||||||
|
# For instructions that implicitly access the stack, the address
|
||||||
|
# size is the same as the stack segment pointer size, not the
|
||||||
|
# address size if specified by the instruction prefix
|
||||||
|
addressSize = "env.stackSize"
|
||||||
|
else:
|
||||||
|
addressSize = "env.addressSize"
|
||||||
|
|
||||||
base = LdStOp
|
base = LdStOp
|
||||||
if big:
|
if big:
|
||||||
base = BigLdStOp
|
base = BigLdStOp
|
||||||
class LoadOp(base):
|
class LoadOp(base):
|
||||||
def __init__(self, data, segment, addr, disp = 0,
|
def __init__(self, data, segment, addr, disp = 0,
|
||||||
dataSize="env.dataSize",
|
dataSize="env.dataSize",
|
||||||
addressSize="env.addressSize",
|
addressSize=addressSize,
|
||||||
atCPL0=False, prefetch=False, nonSpec=nonSpec):
|
atCPL0=False, prefetch=False, nonSpec=nonSpec,
|
||||||
|
implicitStack=implicitStack):
|
||||||
super(LoadOp, self).__init__(data, segment, addr,
|
super(LoadOp, self).__init__(data, segment, addr,
|
||||||
disp, dataSize, addressSize, mem_flags,
|
disp, dataSize, addressSize, mem_flags,
|
||||||
atCPL0, prefetch, nonSpec)
|
atCPL0, prefetch, nonSpec, implicitStack)
|
||||||
self.className = Name
|
self.className = Name
|
||||||
self.mnemonic = name
|
self.mnemonic = name
|
||||||
|
|
||||||
|
@ -478,6 +498,9 @@ let {{
|
||||||
|
|
||||||
defineMicroLoadOp('Ld', 'Data = merge(Data, Mem, dataSize);',
|
defineMicroLoadOp('Ld', 'Data = merge(Data, Mem, dataSize);',
|
||||||
'Data = Mem & mask(dataSize * 8);')
|
'Data = Mem & mask(dataSize * 8);')
|
||||||
|
defineMicroLoadOp('Ldis', 'Data = merge(Data, Mem, dataSize);',
|
||||||
|
'Data = Mem & mask(dataSize * 8);',
|
||||||
|
implicitStack=True)
|
||||||
defineMicroLoadOp('Ldst', 'Data = merge(Data, Mem, dataSize);',
|
defineMicroLoadOp('Ldst', 'Data = merge(Data, Mem, dataSize);',
|
||||||
'Data = Mem & mask(dataSize * 8);',
|
'Data = Mem & mask(dataSize * 8);',
|
||||||
'(StoreCheck << FlagShift)')
|
'(StoreCheck << FlagShift)')
|
||||||
|
@ -544,10 +567,11 @@ let {{
|
||||||
def __init__(self, data, segment, addr, disp = 0,
|
def __init__(self, data, segment, addr, disp = 0,
|
||||||
dataSize="env.dataSize",
|
dataSize="env.dataSize",
|
||||||
addressSize="env.addressSize",
|
addressSize="env.addressSize",
|
||||||
atCPL0=False, prefetch=False, nonSpec=nonSpec):
|
atCPL0=False, prefetch=False, nonSpec=nonSpec,
|
||||||
|
implicitStack=False):
|
||||||
super(LoadOp, self).__init__(data, segment, addr,
|
super(LoadOp, self).__init__(data, segment, addr,
|
||||||
disp, dataSize, addressSize, mem_flags,
|
disp, dataSize, addressSize, mem_flags,
|
||||||
atCPL0, prefetch, nonSpec)
|
atCPL0, prefetch, nonSpec, implicitStack)
|
||||||
self.className = Name
|
self.className = Name
|
||||||
self.mnemonic = name
|
self.mnemonic = name
|
||||||
|
|
||||||
|
@ -574,7 +598,8 @@ let {{
|
||||||
'(StoreCheck << FlagShift) | Request::LOCKED_RMW',
|
'(StoreCheck << FlagShift) | Request::LOCKED_RMW',
|
||||||
nonSpec=True)
|
nonSpec=True)
|
||||||
|
|
||||||
def defineMicroStoreOp(mnemonic, code, completeCode="", mem_flags="0"):
|
def defineMicroStoreOp(mnemonic, code, completeCode="", mem_flags="0",
|
||||||
|
implicitStack=False):
|
||||||
global header_output
|
global header_output
|
||||||
global decoder_output
|
global decoder_output
|
||||||
global exec_output
|
global exec_output
|
||||||
|
@ -594,20 +619,30 @@ let {{
|
||||||
exec_output += MicroStoreInitiateAcc.subst(iop)
|
exec_output += MicroStoreInitiateAcc.subst(iop)
|
||||||
exec_output += MicroStoreCompleteAcc.subst(iop)
|
exec_output += MicroStoreCompleteAcc.subst(iop)
|
||||||
|
|
||||||
|
if implicitStack:
|
||||||
|
# For instructions that implicitly access the stack, the address
|
||||||
|
# size is the same as the stack segment pointer size, not the
|
||||||
|
# address size if specified by the instruction prefix
|
||||||
|
addressSize = "env.stackSize"
|
||||||
|
else:
|
||||||
|
addressSize = "env.addressSize"
|
||||||
|
|
||||||
class StoreOp(LdStOp):
|
class StoreOp(LdStOp):
|
||||||
def __init__(self, data, segment, addr, disp = 0,
|
def __init__(self, data, segment, addr, disp = 0,
|
||||||
dataSize="env.dataSize",
|
dataSize="env.dataSize",
|
||||||
addressSize="env.addressSize",
|
addressSize=addressSize,
|
||||||
atCPL0=False, nonSpec=False):
|
atCPL0=False, nonSpec=False, implicitStack=implicitStack):
|
||||||
super(StoreOp, self).__init__(data, segment, addr, disp,
|
super(StoreOp, self).__init__(data, segment, addr, disp,
|
||||||
dataSize, addressSize, mem_flags, atCPL0, False,
|
dataSize, addressSize, mem_flags, atCPL0, False,
|
||||||
nonSpec)
|
nonSpec, implicitStack)
|
||||||
self.className = Name
|
self.className = Name
|
||||||
self.mnemonic = name
|
self.mnemonic = name
|
||||||
|
|
||||||
microopClasses[name] = StoreOp
|
microopClasses[name] = StoreOp
|
||||||
|
|
||||||
defineMicroStoreOp('St', 'Mem = pick(Data, 2, dataSize);')
|
defineMicroStoreOp('St', 'Mem = pick(Data, 2, dataSize);')
|
||||||
|
defineMicroStoreOp('Stis', 'Mem = pick(Data, 2, dataSize);',
|
||||||
|
implicitStack=True)
|
||||||
defineMicroStoreOp('Stul', 'Mem = pick(Data, 2, dataSize);',
|
defineMicroStoreOp('Stul', 'Mem = pick(Data, 2, dataSize);',
|
||||||
mem_flags="Request::LOCKED_RMW")
|
mem_flags="Request::LOCKED_RMW")
|
||||||
|
|
||||||
|
@ -655,10 +690,10 @@ let {{
|
||||||
def __init__(self, data, segment, addr, disp = 0,
|
def __init__(self, data, segment, addr, disp = 0,
|
||||||
dataSize="env.dataSize",
|
dataSize="env.dataSize",
|
||||||
addressSize="env.addressSize",
|
addressSize="env.addressSize",
|
||||||
atCPL0=False, nonSpec=False):
|
atCPL0=False, nonSpec=False, implicitStack=False):
|
||||||
super(StoreOp, self).__init__(data, segment, addr, disp,
|
super(StoreOp, self).__init__(data, segment, addr, disp,
|
||||||
dataSize, addressSize, mem_flags, atCPL0, False,
|
dataSize, addressSize, mem_flags, atCPL0, False,
|
||||||
nonSpec)
|
nonSpec, implicitStack)
|
||||||
self.className = Name
|
self.className = Name
|
||||||
self.mnemonic = name
|
self.mnemonic = name
|
||||||
|
|
||||||
|
@ -694,7 +729,7 @@ let {{
|
||||||
def __init__(self, data, segment, addr, disp = 0,
|
def __init__(self, data, segment, addr, disp = 0,
|
||||||
dataSize="env.dataSize", addressSize="env.addressSize"):
|
dataSize="env.dataSize", addressSize="env.addressSize"):
|
||||||
super(LeaOp, self).__init__(data, segment, addr, disp,
|
super(LeaOp, self).__init__(data, segment, addr, disp,
|
||||||
dataSize, addressSize, "0", False, False, False)
|
dataSize, addressSize, "0", False, False, False, False)
|
||||||
self.className = "Lea"
|
self.className = "Lea"
|
||||||
self.mnemonic = "lea"
|
self.mnemonic = "lea"
|
||||||
|
|
||||||
|
@ -715,7 +750,7 @@ let {{
|
||||||
addressSize="env.addressSize"):
|
addressSize="env.addressSize"):
|
||||||
super(TiaOp, self).__init__("InstRegIndex(NUM_INTREGS)", segment,
|
super(TiaOp, self).__init__("InstRegIndex(NUM_INTREGS)", segment,
|
||||||
addr, disp, dataSize, addressSize, "0", False, False,
|
addr, disp, dataSize, addressSize, "0", False, False,
|
||||||
False)
|
False, False)
|
||||||
self.className = "Tia"
|
self.className = "Tia"
|
||||||
self.mnemonic = "tia"
|
self.mnemonic = "tia"
|
||||||
|
|
||||||
|
@ -727,10 +762,9 @@ let {{
|
||||||
addressSize="env.addressSize", atCPL0=False):
|
addressSize="env.addressSize", atCPL0=False):
|
||||||
super(CdaOp, self).__init__("InstRegIndex(NUM_INTREGS)", segment,
|
super(CdaOp, self).__init__("InstRegIndex(NUM_INTREGS)", segment,
|
||||||
addr, disp, dataSize, addressSize, "Request::NO_ACCESS",
|
addr, disp, dataSize, addressSize, "Request::NO_ACCESS",
|
||||||
atCPL0, False, False)
|
atCPL0, False, False, False)
|
||||||
self.className = "Cda"
|
self.className = "Cda"
|
||||||
self.mnemonic = "cda"
|
self.mnemonic = "cda"
|
||||||
|
|
||||||
microopClasses["cda"] = CdaOp
|
microopClasses["cda"] = CdaOp
|
||||||
}};
|
}};
|
||||||
|
|
||||||
|
|
Loading…
Reference in a new issue