| # Copyright (C) 2018-2020 Apple Inc. All rights reserved. |
| # |
| # Redistribution and use in source and binary forms, with or without |
| # modification, are permitted provided that the following conditions |
| # are met: |
| # 1. Redistributions of source code must retain the above copyright |
| # notice, this list of conditions and the following disclaimer. |
| # 2. Redistributions in binary form must reproduce the above copyright |
| # notice, this list of conditions and the following disclaimer in the |
| # documentation and/or other materials provided with the distribution. |
| # |
| # THIS SOFTWARE IS PROVIDED BY APPLE INC. ``AS IS'' AND ANY |
| # EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE |
| # IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR |
| # PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR |
| # CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, |
| # EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, |
| # PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR |
| # PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY |
| # OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT |
| # (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE |
| # OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. |
| |
| class ARM64E |
| # FIXME: This is fragile and needs to match the enum value in PtrTag.h. |
| CFunctionPtrTag = 2 |
| end |
| |
| class Sequence |
| def getModifiedListARM64E |
| result = riscLowerMisplacedAddresses(@list) |
| getModifiedListARM64(result) |
| end |
| end |
| |
| class Instruction |
| def self.lowerMisplacedAddressesARM64E(node, newList) |
| wasHandled = false |
| if node.is_a? Instruction |
| postInstructions = [] |
| annotation = node.annotation |
| codeOrigin = node.codeOrigin |
| case node.opcode |
| when "jmp", "call" |
| if node.operands.size == 3 |
| raise unless node.operands[2].value == 1 |
| raise unless node.operands[1].immediate? and node.operands[1].value <= 0xffff |
| raise unless node.operands[0].address? |
| address = Tmp.new(codeOrigin, :gpr) |
| target = Tmp.new(codeOrigin, :gpr) |
| newList << Instruction.new(codeOrigin, "leap", [node.operands[0], address], annotation) |
| newList << Instruction.new(codeOrigin, "loadp", [Address.new(codeOrigin, address, Immediate.new(codeOrigin, 0)), target], annotation) |
| tag = Tmp.new(codeOrigin, :gpr) |
| newList << Instruction.new(codeOrigin, "move", [Immediate.new(codeOrigin, node.operands[1].value << 48), tag], annotation) |
| newList << Instruction.new(codeOrigin, "xorp", [address, tag], annotation) |
| newList << node.cloneWithNewOperands([target, tag]) |
| wasHandled = true |
| elsif node.operands.size > 1 |
| if node.operands[1].is_a? RegisterID or node.operands[1].is_a? Tmp |
| tag = riscLowerOperandToRegister(node, newList, postInstructions, 1, "p", false) |
| else |
| tag = Tmp.new(codeOrigin, :gpr) |
| newList << Instruction.new(codeOrigin, "move", [node.operands[1], tag], annotation) |
| end |
| operands = [ |
| riscLowerOperandToRegister(node, newList, postInstructions, 0, "p", false), |
| tag |
| ] |
| newList << node.cloneWithNewOperands(operands) |
| wasHandled = true |
| end |
| when "tagCodePtr" |
| raise if node.operands.size < 1 or not node.operands[0].is_a? RegisterID |
| if node.operands.size == 4 |
| raise unless node.operands[3].register? |
| raise unless node.operands[2].immediate? and node.operands[2].value == 1 |
| raise unless node.operands[1].immediate? and node.operands[1].value <= 0xffff |
| address = node.operands[3] |
| if node.operands[1].immediate? |
| tag = Tmp.new(codeOrigin, :gpr) |
| newList << Instruction.new(codeOrigin, "move", [Immediate.new(codeOrigin, node.operands[1].value << 48), tag], annotation) |
| elsif operands[1].register? |
| tag = node.operands[1] |
| end |
| newList << Instruction.new(codeOrigin, "xorp", [address, tag], annotation) |
| newList << node.cloneWithNewOperands([node.operands[0], tag]) |
| wasHandled = true |
| end |
| when "untagArrayPtr" |
| newOperands = node.operands.map { |
| | operand | |
| if operand.address? |
| tmp = Tmp.new(codeOrigin, :gpr) |
| newList << Instruction.new(codeOrigin, "loadp", [operand, tmp], annotation) |
| tmp |
| else |
| operand |
| end |
| } |
| newList << node.cloneWithNewOperands(newOperands) |
| wasHandled = true |
| end |
| newList += postInstructions if wasHandled |
| end |
| return wasHandled, newList |
| end |
| |
| def lowerARM64E |
| case opcode |
| when "call" |
| if operands.size == 1 or operands[0].label? |
| lowerARM64 |
| elsif operands[1] == ARM64E::CFunctionPtrTag |
| emitARM64Unflipped("blraaz", [operands[0]], :ptr) |
| else |
| emitARM64Unflipped("blrab", operands, :ptr) |
| end |
| when "jmp" |
| if operands[0].label? |
| lowerARM64 |
| else |
| emitARM64Unflipped("brab", operands, :ptr) |
| end |
| when "tagCodePtr" |
| raise if operands.size > 2 |
| raise unless operands[0].register? |
| raise unless operands[1].register? |
| emitARM64Unflipped("pacib", operands, :ptr) |
| when "tagReturnAddress" |
| raise if operands.size < 1 or not operands[0].is_a? RegisterID |
| if operands[0].is_a? RegisterID and operands[0].name == "sp" |
| $asm.puts "pacibsp" |
| else |
| emitARM64Unflipped("pacib lr,", operands, :ptr) |
| end |
| when "untagReturnAddress" |
| raise if operands.size < 1 or not operands[0].is_a? RegisterID |
| if operands[0].is_a? RegisterID and operands[0].name == "sp" |
| $asm.puts "autibsp" |
| else |
| emitARM64Unflipped("autib lr,", operands, :ptr) |
| end |
| when "removeCodePtrTag" |
| raise unless operands[0].is_a? RegisterID |
| emitARM64Unflipped("xpaci ", operands, :ptr) |
| when "untagArrayPtr" |
| raise if operands.size != 2 or not operands.each { |operand| operand.is_a? RegisterID or operand.is_a? Tmp } |
| emitARM64("autdb ", operands, :ptr) |
| when "removeArrayPtrTag" |
| raise unless operands[0].is_a? RegisterID |
| emitARM64Unflipped("xpacd ", operands, :ptr) |
| when "ret" |
| $asm.puts "retab" |
| else |
| lowerARM64 |
| end |
| end |
| end |