You are on page 1of 7

Machine Language, Assemblers,

Interpretation
and Compilers
Long, long, time ago, I can still remember
how mnemonics used to make me smile...
When I find my code in tons of trouble,
Friends and colleagues come to me, Recall our model of Interpretation:
And I knew that with just the opcode names Speaking words of wisdom:
• Start with some hard-to-program
that I could play those assembly games
and maybe hack some programs for a while.
"Write in C."
Pgm
M2 machine, say M1
But 6.004 made me shiver
with every lecture that was delivered. • Write a single program for M1 which
Bad news at the door step,
I couldn’t read one more spec. M1 mimics the behavior of some easier
I can’t remember if I tried
WARD &
HALSTEAD machine, say M2
to get Factorial optimized,
But something touched my nerdish pride • Result: a “virtual” M2
the day my Beta died.
And I was singing…
6.004 “Layers” of interpretation: Structure Language
NERD KIT
• Often we use several layers of
DATA
interpretation to achieve APPLICATION
Applic Lang
desired behavior, eg: (())()
(()())
SCHEME
Application
(())()
• X86 (Pentium), running X86 Scheme
• Scheme, running Scheme Interp
X86 Instrs
• Application, interpreting Hardware
• Data.

6.004 – Fall 2001 10/23/01 modified10/23/2001 3:27 PM L12 – Instruction Set 1 6.004 – Fall 2001 10/23/01 L12 – Instruction Set 2

Compilation Interpretation vs Compilation


Model of Compilation:
P2 There are some characteristic differences between these two
• Given some hard-to-program powerful tools...
machine, say M1...

• Find some easier-to-program language


C2-1 P1
Interpretation Compilation
L2 (perhaps for a more complicated M1 How it treats input “x+2” computes x+2 generates a program that
machine, M2); write programs in that
computes x+2
language
When it happens During execution Before execution
• Build a translator (compiler) that translates programs from M2’s language
to M1’s language. May run on M1, M2, or some other machine. What it complicates/slows Program Execution Program Development
Decisions made at Run Time Compile Time
Interpretation & Compilation: two tools for improving programmability ...
• Both allow changes in the programming model
• Both afford programming applications in platform (e.g., processor)
Major design choice we’ll see repeatedly:
independent languages do it at Compile time or at Run time?
• Both are widely used in modern computer systems!

6.004 – Fall 2001 10/23/01 L12 – Instruction Set 3 6.004 – Fall 2001 10/23/01 L12 – Instruction Set 4
Back to Our programmability problem... Software: Abstraction Strategy
β Machine Language: 32-bit instructions
OPCODE rc ra rb unused Initial steps: compilation tools

arithmetic: ADD, SUB, MUL, DIV Ra and Rb are the operands, Assembler (UASM): Hides: bit-level representations,
compare: CMPEQ, CMPLT, CMPLE Rc is the destination. symbolic representation hex locations, binary values
boolean: AND, OR, XOR R31 reads as 0, unchanged by writes of machine language
shift: SHL, SHR, SAR
Compiler (C): symbolic Hides: Machine instructions,
OPCODE rc ra 16-bit signed constant representation of registers, machine
algorithm architecture

arithmetic: ADDC, SUBC, MULC, DIVC Two’s complement 16-bit constant for
compare: CMPEQC, CMPLTC, CMPLEC numbers from –32768 to 32767; sign- Subsequent steps: interpretive tools
boolean: ANDC, ORC, XORC extended to 32 bits before use.
Operating system Hides: Resource (memory, CPU,
shift: SHLC, SHRC, SARC I/O) limitiations and details
branch: BNE/BT, BEQ/BF (const = word displacement from PCNEXT)
jump: JMP (const not used) Browser Hides: Network; location; local
memory access: LD, ST (const = byte offset from Reg[ra]) parameters
How can we improve the programmability of the Beta?
6.004 – Fall 2001 10/23/01 L12 – Instruction Set 5 6.004 – Fall 2001 10/23/01 L12 – Instruction Set 6

Abstraction step 1:

A Program for Writing Programs UASM Source Language


A UASM SOURCE FILE contains, in symbolic text, values
UASM - the 6.004 (Micro) Assembly Language of successive bytes to be loaded into memory... e.g. in
37 -3 255 decimal (default);

UASM
01101101
11000110
STREAM of Bytes 0b100101 binary (note the “0b” prefix);
00101111 to be loaded
PGM 10110001
into memory
..... 0x25 hexadecimal (note the “0x” prefix);
Symbolic UASM Binary
SOURCE Translator Machine Values can also be expressions; eg, the source file
text file program Language
37+0b10-0x10 24-0x1 4*0b110-1 0xF7&0x1F

UASM: generates 4 bytes of binary output, each with


1. A Symbolic LANGUAGE for representing strings of bits
2. A PROGRAM (“assembler” = primitive compiler) for translating the value 23!
UASM source to binary.

6.004 – Fall 2001 10/23/01 L12 – Instruction Set 7 6.004 – Fall 2001 10/23/01 L12 – Instruction Set 8
Symbolic Gestures Labels (Symbols for Addresses)
We can also define SYMBOLS for use in source programs:
LABELS are symbols that represent memory addresses.
x = 0x1000 | A variable location They can be set with the following special syntax:
y = 0x1004 | Another variable
| Symbolic names for registers: x: is an abbreviation for “x = .”
R0 = 0
R1 = 1
... An Example--
R31 = 31
---- MAIN MEMORY ---- . = 0x1000
Special variable “.” (period) means next byte address to be filled: 1000: 09 04 01 00 sqrs: 0 1 4 9
. = 0x100 | Assemble into 100 1004: 31 24 19 10 16 25 36 49
1 2 3 4 1008: 79 64 51 40 64 81 100 121
five = . | Symbol “five” is 0x104 100c: E1 C4 A9 90 144 169 196 225
5 6 7 8 1010: 00 00 00 10 slen: LONG(. - sqrs)
. = .+16 | Skip 16 bytes
3 2 1 0
9 10 11 12

6.004 – Fall 2001 10/23/01 L12 – Instruction Set 9 6.004 – Fall 2001 10/23/01 L12 – Instruction Set 10

Mighty Macroinstructions Down-and-dirty bit-twiddling


Macros are parameterized abbreviations, or shorthand Macros to assemble our Beta instruction formats:
| Macro to generate 4 consecutive bytes: OPCODE rc ra rb unused
.macro consec(n) n n+1 n+2 n+3
| Invocation of above macro: OPCODE rc ra 16-bit signed constant
consec(37) | Assemble Beta op instructions
Arrgh!
Has same effect as: .macro betaop(OP,RA,RB,RC) {
.align 4
37 38 39 40 LONG((OP<<26)+((RC%32)<<21)+((RA%32)<<16)+((RB%32)<<11))
Here are macros for breaking multi-byte data types into byte-sized chunks }

| Assemble into bytes, little-endian: | Assemble Beta opc instructions


“.align
“.align4”
4”ensures
ensuresinstructions
instructionswill
willbegin
beginon
on
.macro WORD(x) x%256 (x/256)%256 .macro betaopc(OP,RA,CC,RC) {
word
word boundary
boundary(i.e.,
(i.e.,address
address==00mod
mod 4)
4)
.macro LONG(x) WORD(x) WORD(x >> 16) .align 4
LONG((OP<<26)+((RC%32)<<21)+((RA%32)<<16)+(CC % 0x10000))
Boy, that’s hard to read. }
LONG(0xdeadbeef) Maybe, those big-endian
types do have a point.
Has same effect as: | Assemble Beta branch instructions
.macro betabr(OP,RA,RC,LABEL) betaopc(OP,RA,((LABEL-(.+4))>>2),RC)
0xef 0xbe 0xad 0xde

6.004 – Fall 2001 10/23/01 L12 – Instruction Set 11 6.004 – Fall 2001 10/23/01 L12 – Instruction Set 12
Finally, Beta Instructions Example Assembly
ADDC(R3,1234,R17)
| BETA Instructions:
.macro ADD(RA,RB,RC) betaop(0x20,RA,RB,RC) expand ADDC macro with RA=R3, C=1234, RC=R17
.macro ADDC(RA,C,RC) betaopc(0x30,RA,C,RC) betaopc(0x30,R3,1234,R17)
.macro AND(RA,RB,RC) betaop(0x28,RA,RB,RC)
.macro ANDC(RA,C,RC) betaopc(0x38,RA,C,RC) expand betaopc macro with OP=0x30, RA=R3, CC=1234, RC=R17
.macro MUL(RA,RB,RC) betaop(0x22,RA,RB,RC) .align 4
.macro MULC(RA,C,RC) betaopc(0x32,RA,C,RC) LONG((0x30<<26)+((R17%32)<<21)+((R3%32)<<16)+(1234 % 0x10000))


• expand LONG macro with X=0xC22304D2
.macro LD(RA,CC,RC) betaopc(0x18,RA,CC,RC) WORD(0xC22304D2) WORD(0xC22304D2 >> 16)
.macro LD(CC,RC) betaopc(0x18,R31,CC,RC) Convenience macros
so we don’t have to expand first WORD macro with X=0xC22304D2
.macro ST(RC,CC,RA) betaopc(0x19,RA,CC,RC)
.macro ST(RC,CC) betaopc(0x19,R31,CC,RC) specify R31… 0xC22304D2%256 (0xC22304D2/256)%256 WORD(0xC223)


• evaluate expressions, expand second WORD macro with X=0xC223
.macro BEQ(RA,LABEL,RC) betabr(0x1D,RA,RC,LABEL) 0xD2 0x04 0xC223%256 (0xC223/256)%256
.macro BEQ(RA,LABEL) betabr(0x1D,RA,r31,LABEL)
.macro BNE(RA,LABEL,RC) betabr(0x1E,RA,RC,LABEL) evaluate expressions
.macro BNE(RA,LABEL) betabr(0x1E,RA,r31,LABEL) 0xD2 0x04 0x23 0xC2
(from beta.uasm)
6.004 – Fall 2001 10/23/01 L12 – Instruction Set 13 6.004 – Fall 2001 10/23/01 L12 – Instruction Set 14

Don’t have it? Fake it! Abstraction step 2:

Convenience macros can be used to extend our assembly language:


High-level Languages
Most algorithms are naturally We’ve used (and will continue to use
.macro MOVE(RA,RC) ADD(RA,R31,RC) | Reg[RC] <- Reg[RA] expressed at a high level. Consider throughout 6.004) C, a “mature” and
.macro CMOVE(CC,RC) ADDC(R31,C,RC) | Reg[RC] <- C the following algorithm: common systems programming
.macro COM(RA,RC) XORC(RA,-1,RC) | Reg[RC] <- ~Reg[RA] struct Employee lanugage. Modern popular alternatives
.macro NEG(RB,RC) SUB(R31,RB,RC) | Reg[RC] <- -Reg[RB] { char *Name; /* Employee's name. */ include C++, Java, Python, and many
.macro NOP() ADD(R31,R31,R31) | do nothing long Salary; /* Employee's salary. */ others.
long Points;}/* Brownie points. */
.macro BR(LABEL) BEQ(R31,LABEL) | always branch
.macro BR(LABEL,RC) BEQ(R31,LABEL,RC) | always branch /* Annual raise program. */
.macro CALL(LABEL) BEQ(R31,LABEL,LP) | call subroutine Raise(struct Employee P[100]) Why use these, not assembler?
.macro BF(RA,LABEL,RC) BEQ(RA,LABEL,RC) | 0 is false { int i = 0; • readable
.macro BF(RA,LABEL) BEQ(RA,LABEL) while (i < 100)
• concise
.macro BT(RA,LABEL,RC) BNE(RA,LABEL,RC) | 1 is true { struct Employee *e = &P[i];
.macro BT(RA,LABEL) BNE(RA,LABEL) e->Salary = • unambiguous
e->Salary + 100 + e->Points; • portable
| Multi-instruction sequences e->Points = 0; /* Start over! */ (algorithms frequently outlast
.macro PUSH(RA) ADDC(SP,4,SP) ST(RA,-4,SP) i = i+1; their HW platforms)
.macro POP(RA) LD(SP,-4,RA) ADDC(SP,-4,SP) }
}
• Reliable (type checking, etc)

(from beta.uasm) Reference: C handout (6.004 web site)


6.004 – Fall 2001 10/23/01 L12 – Instruction Set 15 6.004 – Fall 2001 10/23/01 L12 – Instruction Set 16
How Compilers Work Compiling Expressions
C code:
Contemporary compilers go far
beyond the macro-expansion
What int x, y;
y = (x-3)*(y+123456)
x:
y:
c: 123456
technology of UASM. They
• Perform sophisticated
compilers
Beta assembly code:
analyses of the source code
• Invoke arbitrary algorithms to
do is • VARIABLES are assigned
memory locations and
x: LONG(0)
generate efficient object code
for the target machine not y:
c:
LONG(0)
LONG(123456)
accessed via LD or ST
• Apply “optimizations” at both • OPERATORS translate to
source and object-code levels
to improve run-time efficiency.
all that ... ALU instructions
LD(x, r1)
• SMALL CONSTANTS
Compilation to unoptimized code
is pretty straightforward...
complicat SUBC(r1,3,r1)
LD(y, r2)
translate to “literal-mode”
ALU instructions
following is a brief glimpse.
ed. LD(C, r3)
ADD(r2,r3,r2) • LARGE CONSTANTS
(at least, in principle)
MUL(r2,r1,r1) translate to initialized
ST(r1,y) variables
6.004 – Fall 2001 10/23/01 L12 – Instruction Set 17 6.004 – Fall 2001 10/23/01 L12 – Instruction Set 18

Data Structures: Arrays Data Structures: Structs


Memory: struct Point
The C source code { int x, y; Memory:
int Hist[100]; } P1, P2, *p;
... hist: ...
P1.x = 157;
Hist[score] += 1; ...

p = &P1;
might translate to: p->y = 157;
P1: P1.x
hist: .=.+4*100 | Leave room for 100 ints score might translate to: P1.y
... P2: P2.x
<score in r1> P1: .=.+8 P2.y
MULC(r1,4,r2) | index -> byte offset P2: .=.+8
LD(r2,hist,r0) | hist[score]
x=0 | Offset for x component
ADDC(r0,1,r0) | increment
y=4 | Offset for y component
ST(r0,hist,r2) | hist[score] Hist[score] ...

ADDC(r31,157,r0) | r0 <- 157


ST(r0,P1+x) | P1.x = 157 Address:
Address:
VARIABLE
VARIABLEbase
baseaddress
address++
...
Address:
Address: <p in r3>
CONSTANT CONSTANT
CONSTANTcomponent
componentoffset
offset
CONSTANTbase
baseaddress
address++ ST(r0,y,r3) | p->y = 157;
VARIABLE
VARIABLE offset computedfrom
offset computed fromindex
index
6.004 – Fall 2001 10/23/01 L12 – Instruction Set 19 6.004 – Fall 2001 10/23/01 L12 – Instruction Set 20
Conditionals Loops
C code: Beta assembly: There are little tricks Beta assembly: Alternate Beta
C code:
if (expr) (compile expr into rx) that come into play assembly:
Lwhile:
{ BF(rx, Lendif) when compiling while (expr)
BR(Ltest)
conditional code blocks. (compile expr into rx)
STUFF {
(compile STUFF) BF(rx,Lendwhile) Lwhile:
} For instance, the STUFF (compile STUFF)
Lendif: statement: } (compile STUFF) Ltest:
BR(Lwhile) (compile expr into rx)
C code: Beta assembly: if (y > 32) Lendwhile:
{ BT(rx,Lwhile)
(compile expr into rx) there’s no
if (expr) x = x + 1; >32 Lendwhile:
{ BF(rx, Lelse) } instruction!
STUFF1 (compile STUFF1)
} compiles to: Compilers spend a lot of time optimizing in and around loops.
BR(Lendif)
else LD(y,R1) - moving all possible computations outside of loops
Lelse: CMPLEC(R1,32,R1)
{ BT(R1,Lendif)
- unrolling loops to reduce branching overhead
STUFF2 (compile STUFF2) ADDC(R2,1,R2) - simplifying expressions that depend on “loop variables”
} Lendif: Lendif:

6.004 – Fall 2001 10/23/01 L12 – Instruction Set 21 6.004 – Fall 2001 10/23/01 L12 – Instruction Set 22

Optimizing Our Favorite Program Optimizations


int n = 20, r; n: LONG(20) int n = 20, r; n: LONG(20)
r: LONG(0) Cleverness:
Cleverness: r: LONG(0)
None…
None…
r = 1; ADDC(r31, 1, r0) straightforward
straightforward r = 1;
compilation ADDC(r31, 1, r0)
ST(r0, r) compilation ST(r0, r)
loop:
(11
(11instructions
instructionsinin LD(n,r1) ; keep n in r1
LD(n, r1)
while (n > 0) loop...)
loop...) LD(r,r3) ; keep r in r3
CMPLT(r31, r1, r2)
{ loop:
BF(r2, done)
Optimizations while (n > 0) CMPLT(r31, r1, r2) Cleverness:
Cleverness:
LD(r, r3) are what make { BF(r2, done) We
Wemove
moveLDs/STs
LDs/STs
LD(n,r1) compilers
out
r = r*n; interesting r = r*n; MUL(r1, r3, r3) outof
ofloop!
loop!
MUL(r1, r3, r3) complicated!
n = n-1; SUBC(r1, 1, r1)
ST(r3, r) (Still,
(Still,55instructions
instructions
} BR(loop) ininloop...)
LD(n,r1) loop...)
n = n-1; done:
SUBC(r1, 1, r1)
ST(r1,n) ; save final n
ST(r1, n)
} ST(r3,r) ; save final r
BR(loop)
done:
6.004 – Fall 2001 10/23/01 L12 – Instruction Set 23 6.004 – Fall 2001 10/23/01 L12 – Instruction Set 24
Coming Attractions:
Really Optimizing… Procedures & Stacks
int n = 20, r; n: LONG(20)
r: LONG(0)

LD(n,r1) ; keep n in r1
r = 1; ADDC(r31, 1, r3) ; keep r in r3
BEQ(r1, done) ; why? Cleverness:
Cleverness:
We
Weavoid
avoidoverhead
overhead
while (n > 0) loop:
of
ofconditional!
conditional!
{ r = r*n; MUL(r1, r3, r3)
n = n-1; SUBC(r1, 1, r1) (Now
(Now33instructions
instructionsinin
} BNE(r1,loop) loop...)
loop...)
done:
ST(r1,n) ; save final n
ST(r3,r) ; save final r

UNFORTUNATELY, 20! = 2,432,902,008,176,640,000 > 261


12! = 479,001,600 = 0x1c8cfc00
6.004 – Fall 2001 10/23/01 L12 – Instruction Set 25 6.004 – Fall 2001 10/23/01 L12 – Instruction Set 26

You might also like