# frozen_string_literal: true
#
# ronin-code-asm - A Ruby DSL for crafting Assembly programs and shellcode.
#
# Copyright (c) 2007-2022 Hal Brodigan (postmodern.mod3 at gmail.com)
#
# ronin-code-asm is free software: you can redistribute it and/or modify
# it under the terms of the GNU Lesser General Public License as published
# by the Free Software Foundation, either version 3 of the License, or
# (at your option) any later version.
#
# ronin-code-asm is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU Lesser General Public License for more details.
#
# You should have received a copy of the GNU Lesser General Public License
# along with ronin-code-asm. If not, see .
#
require 'ronin/code/asm/syntax/common'
module Ronin
module Code
module ASM
module Syntax
#
# Handles emitting Assembly source code in ATT syntax.
#
class ATT < Common
# Data sizes and their instruction mnemonics
WIDTHS = {
8 => 'q',
4 => 'l',
2 => 'w',
1 => 'b',
nil => ''
}
#
# Emits a register.
#
# @param [Register] reg
# The register.
#
# @return [String]
# The register name.
#
def self.emit_register(reg)
"%#{reg.name}"
end
#
# Emits an immediate operand.
#
# @param [ImmediateOperand] op
# The operand.
#
# @return [String]
# The formatted immediate operand.
#
def self.emit_immediate_operand(op)
"$#{emit_integer(op.value)}"
end
#
# Emits a memory operand.
#
# @param [MemoryOperand] op
# The operand.
#
# @return [String]
# The formatted memory operand.
#
def self.emit_memory_operand(op)
asm = emit_register(op.base)
if op.index
asm << ',' << emit_register(op.index)
asm << ',' << op.scale.to_s if op.scale > 1
end
asm = "(#{asm})"
asm = emit_integer(op.offset) + asm if op.offset != 0
return asm
end
#
# Emits multiple operands.
#
# @param [Array] ops
# The Array of operands.
#
# @return [String]
# The formatted operands.
#
def self.emit_operands(ops)
if ops.length > 1
[*ops[1..-1], ops[0]].map { |op| emit_operand(op) }.join(",\t")
else
super(ops)
end
end
#
# Emits an instruction.
#
# @param [Instruction] ins
# The instruction.
#
# @return [String]
# The formatted instruction.
#
def self.emit_instruction(ins)
line = emit_keyword(ins.name)
unless ins.operands.empty?
unless (ins.operands.length == 1 && ins.width == 1)
line << WIDTHS[ins.width]
end
line << "\t" << emit_operands(ins.operands)
end
return line
end
#
# Emits a section name.
#
# @param [Symbol] name
# The section name.
#
# @return [String]
# The formatted section name.
#
# @since 0.2.0
#
def self.emit_section(name)
".#{name}"
end
#
# Emits the program's prologue.
#
# @param [Program] program
# The program.
#
# @return [String]
# The formatted prologue.
#
# @since 0.2.0
#
def self.emit_prologue(program)
".code#{BITS[program.arch]}"
end
end
end
end
end
end