Topics

GOTO statement considered harmful (x86_64 report)

Robin Hodson
 

I don't see what's so complicated about programming an assembler anyway.
The 6502 and ARM assembly to machine code conversion both look much
easier than understanding all the addressing modes, and there are only
so many of those due to the need to extract as much value as possible
per area of silicon.

My impression of an assembler:
1. Lookup a (tokenised) opcode, write a byte; read in operand values
from the parser, write out bytes.
2. If something doesn't work, throw an error.
3. Update P% and the other status integers.
4. Check you haven't crossed a page boundary; do the last line again
if you have.

I appreciate as processors become more complex, assemblers have to
include other features, and the temptation is always there to add
features to a standard assembly language to make it easier for the user,
but it isn't a compiler or even an interpreter, and you have the
existing interpreter to do the tokenising/detokenising, variable
handling, and parsing for you.


I thought I'd better read through the x64 spec properly/quickly:

===== Short report follows =====

I looked briefly at x86_64 assembly code just now, and there aren't
thousands of instructions or modes. The only new things are the ability
to call functions, rather like an SWI, and the requirement to reference
arrays in memory. Even then, the assembler doesn't need to understand
them. There's also something about stack allocation, but that's the
processor's problem. Most of it is things which are somebody else's problem.

The instruction set is 8 general purpose instructions,
6 decimal arithmetic instrs,
12 logical/bitwise/test instrs,
6 branch/interrupt instrs,
in, out,
4 instructions for strings,
4 flag control,
8 misc instrs,
16 system instrs,
and some extensions for the FPU and MMX/SSE registers (there are a lot
of these)
-Then the different addressing modes and conditional variants for all those
-And four assembler directives, one for page boundaries and three for
debugging

There are 64 main registers and the MMX etc blocks have their own
registers as well.

The specified multi-pass assembly and preprocessor directives, macro
directives etc are redundant.

It reminds me a lot of ARMcode, only less compact.


SUMMARY

About 64 basic instruction codes, most of which are variants of each other,
a longer list of bolt-on extensions which are all alike,
about 8 addressing modes, and 16 conditional variants,
and a complication in operand placement due to being able to specify
which of them are x bytes long.

There are a lot of registers to index, and examples of the assembly code
make it look like it wants to resemble a high-level language, but it
isn't of course. It has looping instructions at processor level, which
look like a gift to parallel processing.

There are so many combinations of instruction codes, it'd be necessary
to have some convention to avoid variable names clashing with them.

The syntax for referring to hexadecimal etc numbers is different, of course.


CONCLUSION

A fairly long-but-repetitive list of instruction codes/names and
register names to index/tokenise,
only 8 addressing modes which are mainly syntax checking,
and a further how-many-bytes-in-a-word specifier - that last one's the
only new complexity.


REF

I used this as a reference:
http://flatassembler.net/docs.php?article=manual

It seems the root URL of that has another OSS assembler:
http://flatassembler.net/

Richard Russell
 

On Mon, Nov 6, 2017 at 07:02 pm, Robin Hodson wrote:
I don't see what's so complicated about programming an assembler anyway.
You have to be kidding!  The existing IA-32 assembler in BB4W/BBCSDL is 180 Kbytes of (assembler) source code which corresponds to about 15 Kbytes of binary object code; it's the second biggest module in the entire interpreter (put another way it's about the same size as the entire 6502 BBC BASIC interpreter)!  It's massively complicated, not least because the x86 instruction set is so irregular (almost every register has some unique role for example).  Bear in mind that the 32-bit x86 can execute all the instructions of the 16-bit 8086/88 as well, so it's a bit like having two CPUs in one!

Having in my time written the Z80 assembler in BBC BASIC (Z80), the 16-bit 8086 assembler in BBC BASIC (86) and the IA-32 assembler in BB4W/BBCSDL (all from scratch) I am very familiar with the architecture of assemblers and with the instruction set of the x86 range of CPUs.  Your analysis of the complexity of an x86-64 assembler greatly underestimates the difficulty, and it is beyond my current abilities.

Here are some statistics from the existing IA-32 assembler in BB4W/BBCSDL: 

 Number of unique opcode mnemonics: 361
 Number of unique operand mnemonics: 72
 Number of instruction variants: 754

The x86-64 has a lot more!

Richard.