Skip to content

Commit

Permalink
Assembly: minimally support GAS assembly output
Browse files Browse the repository at this point in the history
  • Loading branch information
Marat Dukhan committed Jul 5, 2017
1 parent 886f382 commit 8375c37
Show file tree
Hide file tree
Showing 5 changed files with 80 additions and 24 deletions.
29 changes: 28 additions & 1 deletion peachpy/x86_64/function.py
Original file line number Diff line number Diff line change
Expand Up @@ -1486,11 +1486,38 @@ def format(self, assembly_format="peachpy", line_separator=os.linesep):
code = ["TEXT " + ",".join(text_arguments)]
if self.go_signature is not None:
code.insert(0, "// " + self.go_signature)
elif assembly_format == "gas":
from peachpy.util import ilog2
code_alignment = 16
code = [
"#ifdef __APPLE__",
".section __TEXT,__text,regular,pure_instructions",
".globl _{name}".format(name=self.mangled_name),
".p2align {ilog2alignment}, 0x90".format(
ilog2alignment=ilog2(code_alignment)),
"_{name}:".format(name=self.mangled_name),
"#else /* !__APPLE__ */",
".text",
".p2align {ilog2alignment},,{max_alignment_bytes}".format(
ilog2alignment=ilog2(code_alignment),
max_alignment_bytes=code_alignment - 1),
".globl " + self.mangled_name,
".type {name}, @function".format(name=self.mangled_name),
"{name}:".format(name=self.mangled_name),
"#endif /* !__APPLE */",
]
else:
code = []

code.extend(self.format_code(assembly_format, line_separator=None, indent=True))
if assembly_format == "go":
if assembly_format == "gas":
code += [
"#ifndef __APPLE__",
".size {name}, .-{name}".format(name=self.mangled_name),
"#endif /* !__APPLE__ */",
]

if assembly_format in ["go", "gas"]:
# Add trailing line or assembler will refuse to compile
code.append("")
if line_separator is None:
Expand Down
5 changes: 4 additions & 1 deletion peachpy/x86_64/instructions.py
Original file line number Diff line number Diff line change
Expand Up @@ -65,7 +65,10 @@ def format(self, assembly_format, indent):
elif assembly_format == "nasm":
return text + str(self)
elif assembly_format == "gas":
return text + str(self)
if self.operands:
return text + self.gas_name + " " + ", ".join(format_operand(op, assembly_format) for op in reversed(self.operands))
else:
return text + self.gas_name
elif assembly_format == "go":
if self.go_name:
from peachpy.util import is_int
Expand Down
27 changes: 20 additions & 7 deletions peachpy/x86_64/operand.py
Original file line number Diff line number Diff line change
Expand Up @@ -64,12 +64,12 @@ def get_operand_registers(operand):


def format_operand(operand, assembly_format):
assert assembly_format in {"peachpy", "gnu", "nasm", "go"}, \
"Supported assembly formats are 'peachpy', 'gnu', 'nasm', 'go'"
assert assembly_format in {"peachpy", "gas", "nasm", "go"}, \
"Supported assembly formats are 'peachpy', 'gas', 'nasm', 'go'"

immediate_prefix_map = {
"peachpy": "",
"gnu": "$",
"gas": "$",
"nasm": "",
"go": "$"
}
Expand Down Expand Up @@ -303,8 +303,8 @@ def __call__(self, mask):
return MemoryOperand(self.address, self.size, mask)

def format(self, assembly_format):
assert assembly_format in {"peachpy", "gnu", "nasm", "go"}, \
"Supported assembly formats are 'peachpy', 'gnu', 'nasm', 'go'"
assert assembly_format in {"peachpy", "gas", "nasm", "go"}, \
"Supported assembly formats are 'peachpy', 'gas', 'nasm', 'go'"

if assembly_format == "go":
text = str(self.address.displacement)
Expand All @@ -313,8 +313,21 @@ def format(self, assembly_format):
if self.address.index is not None:
text += "(%s*%d)" % (self.address.index.format(assembly_format), self.address.scale)
return text
elif assembly_format == "gnu":
return "%" + str(self)
elif assembly_format == "gas":
if isinstance(self.address, RIPRelativeOffset):
return str(self.address.offset) + "(%%rip)"
else:
base = self.address.base
if self.address.index is None:
return "{displacement}({base})".format(
displacement=self.address.displacement,
base=base.format(assembly_format))
else:
return "{displacement}({base},{index},{scale})".format(
displacement=self.address.displacement,
base="" if base is None else base.format(assembly_format),
index=self.address.index,
scale=self.address.scale)
else:
return str(self)

Expand Down
8 changes: 4 additions & 4 deletions peachpy/x86_64/pseudo.py
Original file line number Diff line number Diff line change
Expand Up @@ -30,8 +30,8 @@ def __str__(self):
return ".".join(map(str, self.name))

def format(self, assembly_format):
assert assembly_format in {"peachpy", "gnu", "nasm", "go"}, \
"Supported assembly formats are 'peachpy', 'gnu', 'nasm', 'go'"
assert assembly_format in {"peachpy", "gas", "nasm", "go"}, \
"Supported assembly formats are 'peachpy', 'gas', 'nasm', 'go'"

if assembly_format == "go":
# Go assembler rejects label names with a dot, so we replace it with underscore symbol
Expand Down Expand Up @@ -60,8 +60,8 @@ def __str__(self):
return ".".join(map(str, self.identifier)) + ":"

def format(self, assembly_format, indent):
assert assembly_format in {"peachpy", "gnu", "nasm", "go"}, \
"Supported assembly formats are 'peachpy', 'gnu', 'nasm', 'go'"
assert assembly_format in {"peachpy", "gas", "nasm", "go"}, \
"Supported assembly formats are 'peachpy', 'gas', 'nasm', 'go'"

if assembly_format == "go":
# Go assembler rejects label names with a dot, so we replace it with underscore symbol
Expand Down
35 changes: 24 additions & 11 deletions peachpy/x86_64/registers.py
Original file line number Diff line number Diff line change
Expand Up @@ -226,14 +226,14 @@ def as_qword(self):
return GeneralPurposeRegister64(self.physical_id, self.virtual_id)

def format(self, assembly_format):
assert assembly_format in {"peachpy", "gnu", "nasm", "go"}, \
"Supported assembly formats are 'peachpy', 'gnu', 'nasm', 'go'"
assert assembly_format in {"peachpy", "gas", "nasm", "go"}, \
"Supported assembly formats are 'peachpy', 'gas', 'nasm', 'go'"

if assembly_format == "go":
assert not self.is_virtual, \
"Go assembler does not support virtual registers"
return GeneralPurposeRegister._go_physical_id_map[self.physical_id]
elif assembly_format == "gnu":
elif assembly_format == "gas":
return "%" + str(self)
else:
return str(self)
Expand Down Expand Up @@ -433,8 +433,8 @@ def __str__(self):
return GeneralPurposeRegister8._physical_id_map[(self.physical_id, self.mask)]

def format(self, assembly_format):
assert assembly_format in {"peachpy", "gnu", "nasm", "go"}, \
"Supported assembly formats are 'peachpy', 'gnu', 'nasm', 'go'"
assert assembly_format in {"peachpy", "gas", "nasm", "go"}, \
"Supported assembly formats are 'peachpy', 'gas', 'nasm', 'go'"

if assembly_format == "go":
assert not self.is_virtual, \
Expand Down Expand Up @@ -490,14 +490,14 @@ def __str__(self):
return MMXRegister._physical_id_map[self.physical_id]

def format(self, assembly_format):
assert assembly_format in {"peachpy", "gnu", "nasm", "go"}, \
"Supported assembly formats are 'peachpy', 'gnu', 'nasm', 'go'"
assert assembly_format in {"peachpy", "gas", "nasm", "go"}, \
"Supported assembly formats are 'peachpy', 'gas', 'nasm', 'go'"

if assembly_format == "go":
assert not self.is_virtual, \
"Go assembler does not support virtual registers"
return MMXRegister._go_physical_id_map[self.physical_id]
elif assembly_format == "gnu":
elif assembly_format == "gas":
return "%" + str(self)
else:
return str(self)
Expand Down Expand Up @@ -537,14 +537,14 @@ def __str__(self):
return XMMRegister._physical_id_map[self.physical_id]

def format(self, assembly_format):
assert assembly_format in {"peachpy", "gnu", "nasm", "go"}, \
"Supported assembly formats are 'peachpy', 'gnu', 'nasm', 'go'"
assert assembly_format in {"peachpy", "gas", "nasm", "go"}, \
"Supported assembly formats are 'peachpy', 'gas', 'nasm', 'go'"

if assembly_format == "go":
assert not self.is_virtual, \
"Go assembler does not support virtual registers"
return XMMRegister._go_physical_id_map[self.physical_id]
elif assembly_format == "gnu":
elif assembly_format == "gas":
return "%" + str(self)
else:
return str(self)
Expand Down Expand Up @@ -649,6 +649,19 @@ def __str__(self):
else:
return YMMRegister._physical_id_map[self.physical_id]

def format(self, assembly_format):
assert assembly_format in {"peachpy", "gas", "nasm", "go"}, \
"Supported assembly formats are 'peachpy', 'gas', 'nasm', 'go'"

if assembly_format == "go":
assert not self.is_virtual, \
"Go assembler does not support virtual registers"
return XMMRegister._go_physical_id_map[self.physical_id]
elif assembly_format == "gas":
return "%" + str(self)
else:
return str(self)

@property
def as_xmm(self):
return XMMRegister(self.physical_id, self.virtual_id)
Expand Down

0 comments on commit 8375c37

Please sign in to comment.