// Copyright (c) 2023, Compiler Explorer Authors // All rights reserved. // // Redistribution and use in source and binary forms, with or without // modification, are permitted provided that the following conditions are met: // // * Redistributions of source code must retain the above copyright notice, // this list of conditions and the following disclaimer. // * 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 THE COPYRIGHT HOLDERS AND CONTRIBUTORS "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 THE COPYRIGHT HOLDER 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. import {InstructionSet} from '../../../types/instructionsets.js'; import {BaseInstructionSetInfo, InstructionType} from './base.js'; export class ArmInstructionSetInfo extends BaseInstructionSetInfo { static conditions = `(?:${[ 'eq', 'ne', 'cs', 'hs', 'cc', 'lo', 'mi', 'pl', 'vs', 'vc', 'hi', 'ls', 'ge', 'lt', 'gt', 'le', 'al', ].join('|')})`; // handling: // bcc label // bxcc reg // popcc {..., pc} // popcc {..., tmp}; bxcc tmp // mov pc, reg // currently not handling: // blcc label // blxcc label // blxcc reg // movcc pc, reg static conditionalJumps = new RegExp( '\\b(?:' + [ `b\\.?${ArmInstructionSetInfo.conditions}(?:\\.w)?`, `bx${ArmInstructionSetInfo.conditions}`, `bxj${ArmInstructionSetInfo.conditions}`, `cbz`, `cbnz`, `tbz`, `tbnz`, ] .map(re => `(?:${re})`) .join('|') + ')\\b', ); static unconditionalJumps = new RegExp( '\\b(?:' + [`b(?:\\.w)?`, `bx`, `bxj`].map(re => `(?:${re})`).join('|') + ')\\b', ); static returnInstruction = new RegExp( '(?:' + [`bx`, `ret`].map(re => `(?:${re})`).join('|') + ')\\b.*' + `|pop\\s*\\{(?:r(?:\\d{2,}|[4-9]),\\s*)*pc\\}.*` + `|mov\\s*pc\\s*,.*`, ); static override get key(): InstructionSet[] { return ['arm32', 'aarch64']; } override isJmpInstruction(instruction: string) { const opcode = instruction.trim().split(' ')[0].toLowerCase(); return ( ArmInstructionSetInfo.conditionalJumps.test(opcode) || ArmInstructionSetInfo.unconditionalJumps.test(opcode) ); } override getInstructionType(instruction: string) { const opcode = instruction.trim().split(' ')[0].toLowerCase(); if (ArmInstructionSetInfo.conditionalJumps.test(opcode)) return InstructionType.conditionalJmpInst; else if (ArmInstructionSetInfo.unconditionalJumps.test(opcode)) return InstructionType.jmp; else if (ArmInstructionSetInfo.returnInstruction.test(instruction.trim().toLocaleLowerCase())) { return InstructionType.retInst; } else { return InstructionType.notRetInst; } } }