168
CHAPT ER 5 LANGUAGES AND T HE MACHINE
The
for
statement T he C
for
statement has the syntax:
for expr1; expr2; expr3 stmt;
T he C language definition says that this statement is equivalent to:
expr1; while expr2 {
stmt expr3;
}
T hus it is implemented exactly like the while statements above, with the addition of code for
expr1
and
expr3
.
5.2 The Assembly Process
T he process of translating an assembly language program into a machine lan- guage program is referred to as the
assembly process
. T he assembly process is straightforward and rather simple, since there is a straightforward one-to-one
mapping of assembly language statements to their machine language counter- parts. T his is in opposition to compilation, for example, in which a given
high-level language statement may be translated into a number of computation- ally equivalent machine language statements.
While assembly is a straightforward process, it is tedious and error-prone if done by hand. In fact, the assembler was one of the first software tools developed after
the invention of the digital electronic computer.
Commercial assemblers provide at least the following capabilities: • Allow the programmer to specify the run-time location of data values and
programs. Most often, however, the programmer would not specify an ab- solute starting location for a program, because the program will be moved
around, or relocated, by the linker and perhaps the loader, as discussed be- low.
• Provide a means for the programmer to initialize data values in memory prior to program execution.
CHAPT ER 5 LANGUAGES AND T HE MACHINE
169
• Provide assembly-language mnemonics for all machine instructions and ad- dressing modes, and translate valid assembly language statements into their
equivalent machine language binary values. • Permit the use of symbolic labels to represent addresses and constants.
• Provide a means for the programmer to specify the starting address of the program, if there is one. T here would not be a starting address if the mod-
ule being assembled is a procedure or function, for example. • Provide a degree of assemble-time arithmetic.
• Include a mechanism that allows variables to be defined in one assembly language program and used in another, separately assembled program.
• Provide for the expansion of
macro routines
, that is, routines that can be defined once, and then instantiated as many times as needed.
We shall illustrate how the assembly process proceeds by “hand assembling” a simple program from ARC assembly language to ARC machine language. T he
program we will assemble is similar to Figure 4-13, reproduced below for conve- nience as Figure 5-1. In assembling this program we use the ARC encoding for-
mats shown in Figure 4-10, reproduced here as Figure 5-2. T he figure shows the encoding of ARC machine language. T hat is, it specifies the target binary
machine language of the ARC computer that the assembler must generate from the assembly language text.
This program adds two numbers .org 2048
ld [x], r1
Load x into r1 ld
[y], r2 Load y into r2
addcc r1, r2, r3
r3 ←
r1 + r2 jmpl
r15 + 4, r0 Return
x: 15
y: 9
.end .begin
main:
z: st
r3, [z] Store r3 into z
Figure 5-1 A simple ARC program that adds two numbers
170
CHAPT ER 5 LANGUAGES AND T HE MACHINE
Assembly and two pass assemblers Most assemblers pass over the assembly language text twice, and are referred to as
“two-pass assemblers.” T he first pass is dedicated to determining the addresses of all data items and machine instructions, and selecting which machine instruction
should be produced for each assembly language instruction but not yet generat- ing machine code.
T he addresses of data items and instructions are determined by employing an assemble-time analog to the Program Counter, referred to as the
location counter.
T he location counter keeps track of the address of the current instruc- tion or data item as assembly proceeds. It is generally initialized to 0 at the start
of the first pass, and is incremented by the size of each instruction. T he
.org
pseudo operation causes the location counter to be set to the value specified by the
.org
statement. For example if the assembler encounters the statement
op3 op=10
010000 010001
010010 010110
100110 111000
addcc andcc
orcc orncc
srl jmpl
0001 0101
0110 0111
1000
cond
be bcs
bneg bvs
ba
branch
010 100
op2
branch sethi
Inst.
00 01
10 11
op
SETHIBranch CALL
Arithmetic Memory
Format
000000 000100
ld st
op3 op=11
op
CALL format
disp30
31 30 29 28 27 26 25 24 23 22 21 20 19 18 17 16 15 14 13 12 11 10 09 08 07 06 05 04 03 02 01 00
0 1
SETHI Format
imm22
31 30 29 28 27 26 25 24 23 22 21 20 19 18 17 16 15 14 13 12 11 10 09 08 07 06 05 04 03 02 01 00
rd disp22
cond 0 0
0 0 Branch Format
op2 op2
31 30 29 28 27 26 25 24 23 22 21 20 19 18 17 16 15 14 13 12 11 10 09 08 07 06 05 04 03 02 01 00
rs1 1
op3 simm13
1 op3
1
Memory Formats
1 rd
rd rs1
1 0 0 0 0 0 0 0 0
rs2
Arithmetic Formats
31 30 29 28 27 26 25 24 23 22 21 20 19 18 17 16 15 14 13 12 11 10 09 08 07 06 05 04 03 02 01 00
rs1 1
op3 simm13
1 op3
rd rd
rs1 1
0 0 0 0 0 0 0 0 rs2
i
PSR
31 30 29 28 27 26 25 24 23 22 21 20 19 18 17 16 15 14 13 12 11 10 09 08 07 06 05 04 03 02 01 00
z v c n
Figure 5-2 Instruction formats and PSR format for the ARC.
CHAPT ER 5 LANGUAGES AND T HE MACHINE
171
.org 1000
it would set the location counter to 1000, and the next instruction or data item would be assembled at that address. During this pass the assembler also performs
any assembly-time arithmetic operations, and inserts the definitions of all labels and constant values into a table, referred to as the
symbol table
. T he primary reason for requiring a second pass is to allow symbols to be used in
the program before they are defined, which is known as
forward referencing
. After the first pass, the assembler will have identified and entered all symbols into
its symbol table, and, during a second pass generates the machine code, inserting the values of symbols which are then known.
Let us now hand assemble the program shown in Figure 5-1 into machine code. When the assembler encounters the first instruction,
ld [x], r1
it uses a pattern-matching process to recognize that it is a load instruction. Fur- ther pattern matching deduces that it is of the form “load from a memory address
specified as a constant value
x
in this case plus the contents of a register
r0
in this case into a register
r1
in this case.” T his corresponds to the second Mem- ory format shown in Figure 5-2. Examining the second Memory format we find
that the
op
field for this instruction
ld
is
11
. T he destination of this
ld
instruction goes in the
rd
field, which is
00001
for
r1
in this case. T he
op3
field is
000000
for
ld
, as shown in the
op3
box below the Memory formats. T he
rs1
field identifies the register,
r0
in this case, that is added to the
simm13
field to form the source operand address. T he
i
bit comes next. Notice that the
i
bit is used to distinguish between the first Memory format
i=0
and the second
i=0
. T herefore the
i
bit is set to 1. T he
simm13
field specifies the address of the label
x
, which appears five words after the first instruction. Since the first instruction occurs at location 2048, and since each word is composed of
four bytes, the address of
x
is 5
×
4 = 20 bytes after the beginning of the pro- gram. T he address of
x
is then 2048 + 20 = 2068 which is represented by the bit pattern 0100000010100. T his pattern fits into the signed 13-bit
simm13
field. T he first line is thus assembled into the bit pattern shown below:
11 00001 000000 00000 1 0100000010100
op rd
op3 rs1
i simm13
172
CHAPT ER 5 LANGUAGES AND T HE MACHINE
T he next instruction is similar in form, and the corresponding bit pattern is:
T he assembly process continues until all eight lines are assembled, as shown below:
ld [x], r1 1100 0010 0000 0000 0010 1000 0001 0100
ld [y], r2 1100 0100 0000 0000 0010 1000 0001 1000
addcc r1,r2,r3 1000 0110 1000 0000 0100 0000 0000 0010 st r3, [z]
1100 0110 0010 0000 0010 1000 0001 1100 jmpl r15+4, r0 1000 0001 1100 0011 1110 0000 0000 0100
15 0000 0000 0000 0000 0000 0000 0000 1111
9 0000 0000 0000 0000 0000 0000 0000 1001
0000 0000 0000 0000 0000 0000 0000 0000
As a general approach, the assembly process is carried out by reading assembly language statements sequentially, from first to last, and generating machine code
for each statement. And as mentioned earlier, a difficulty with this approach is caused by forward referencing. Consider the program fragment shown in Figure
5-3. When the assembler sees the
call
statement, it does not yet know the loca-
tion of
sub_r
since the
sub_r
label has not yet been seen. T hus the reference is entered into the symbol table and marked as unresolved. T he reference is
resolved when the definition of
sub_r
is found later in the program. T he process of building a symbol table is described below.
Assembly and the symbol table In the first pass of the two-pass assembly process, a
symbol table
is created. A symbol is either a label or a symbolic name that refers to a value used during the
11 00010 000000 00000 1 0100000011000
op rd
op3 rs1
i simm13
call sub_r
sub_r: st
r1, [w] .
. .
. .
. .
. .
Subroutine is invoked here Subroutine is defined here
Figure 5-3 An example of forward referencing.
CHAPT ER 5 LANGUAGES AND T HE MACHINE
173
assembly process. T he symbol table is generated in the first pass of assembly. As an example of how a two-pass assembler operates, consider assembling the
code in Figure 4-14. Starting from the
.begin
statement, the assembler encounters the statement
.org 2048
T his causes the assembler to set the location counter to 2048, and assembly pro- ceeds from that address. T he first statement encountered is
a_start .equ
3000
An entry is created in the symbol table for
a_start
, which is given the value 3000. Note that
.equ
statements do not generate any code, and thus are not assigned addresses during assembly.
Assembly proceeds as the assembler encounters the first machine instruction,
ld [length],
r1
T his instruction is assembled at the address specified by the location counter, 2048. T he location counter is then incremented by the size of the instruction, 4
bytes, to 2052. Notice that when the symbol
length
is encountered the assem- bler has not seen any definition for it. An entry is created in the symbol table for
length
, but it is initially assigned the value “undefined” as shown by the “—” in Figure 5-4a.
Symbol Value
length 2092
loop 2060
done 2088
a 3000
b
Symbol Value
a_start 3000
a length
–– a_start
3000 address
2096
Figure 5-4 Symbol table for the ARC program shown in Figure 4-14, a after symbols a_start and length are seen; and b after completion.
174
CHAPT ER 5 LANGUAGES AND T HE MACHINE
T he assembler then encounters the second instruction
ld [address],
r2
It assembles this instruction at address 2052 and enters the symbol
address
into the symbol table, again setting its value to “undefined,” since its definition has not been seen. It then increments the location counter by 4 to 2056. T he
andcc
instruction is assembled at address 2056, and the location counter is incremented by the size of the instruction, again 4 bytes, to 2060. T he next sym-
bol that is seen is
loop
, which is entered into the symbol table with a value of 2060, the value of the location counter. T he next symbol that is encountered that
is not in the symbol table is
done
, which is also entered into the symbol table without a value since it likewise has not been defined.
T he first pass of assembly continues, and the unresolved symbols
length
,
address
, and
done
are assigned the values 2092, 2096, and 2088, respectively as they are encountered. T he label
a
is encountered, and is entered into the table with a value of 3000. T he label
done
appears at location 2088 because there are 10 instructions 40 bytes between the beginning of the program and
done
. Addresses for the remaining labels are computed in a similar manner. If any
labels are still undefined at the end of the first pass, then an error exists in the program and the assembler will flag the undefined symbols and terminate.
After the symbol table is created, the second pass of assembly begins. T he pro- gram is read a second time, starting from the
.begin
statement, but now object code is generated. T he first statement that is encountered that causes code to be
generated is
ld
at location 2048. T he symbol table shows that the address por- tion of the
ld
instruction is 2092
10
for the address of
length
, and so one word of code is generated using the Memory format as shown in Figure 5-5. T he
second pass continues in this manner until all of the code is translated. T he assembled program is shown in Figure 5-5. Notice that the displacements for
branch addresses are given in words, rather than in bytes, because the branch instructions multiply the displacements by four.
Final tasks of the assembler After assembly is complete the assembler must add additional information to the
assembled module for the linker and loader:
• T he module name and size. If the execution model involves memory seg-
CHAPT ER 5 LANGUAGES AND T HE MACHINE
175
ments for code, data, stack, etc. then the sizes and identities of the various segments must be specified.
• T he address of the start symbol, if one is defined in the module. Most as- semblers and high level languages provide for a special reserved label that
the programmer can use to indicate where the program should start execu- tion. For example, C specifies that execution will start at the function
named
main
. In Figure 5-1 the label “main” is a signal to the assembler that execution should start at that location.
• Information about global and external symbols. T he linker will need to know the addresses of any global symbols defined in the module and ex-
ported by it, and it will likewise need to know which symbols remain un- defined in the module because they are defined as global in another
module.
• Information about any library routines that are referenced by the module. Some libraries contain commonly used functionality such as math or other
specialized functions. We will have more to say about library usage in the sections below.
.begin .org 2048
a_start .equ 3000 ld [length],r1
11000010 00000000 00101000 00101100 ld [address],r2
11000100 00000000 00101000 00110000 andcc r3,r0,r3
10000110 10001000 11000000 00000000 loop: andcc r1,r1,r0
10000000 10001000 01000000 00000001 be done
00000010 10000000 00000000 00000110 addcc r1,-4,r1
10000010 10000000 01111111 11111100 addcc r1,r2,r4
10001000 10000000 01000000 00000010 ld r4,r5
11001010 00000001 00000000 00000000 addcc r3,r5,r3
10000110 10000000 11000000 00000101 ba loop
00010000 10111111 11111111 11111011 done: jmpl r15+4,r0
10000001 11000011 11100000 00000100 length:
20 00000000 00000000 00000000 00010100
.org a_start a:
25 00000000 00000000 00000000 00011001
-10 11111111 11111111 11111111 11110110
33 00000000 00000000 00000000 00100001
-5 11111111 11111111 11111111 11111011
Object code Instruction
Location counter
2048 2052
2056 2060
2064 2068
2072 2076
2080 2084
2088
3004 3000
3008 3012
3016 2092
.end 7
00000000 00000000 00000000 00000111 address: a_start
00000000 00000000 00001011 10111000 2096
Figure 5-5 Output from the second pass of the assembler for the ARC program shown in Figure 4-14.
176
CHAPT ER 5 LANGUAGES AND T HE MACHINE
• T he values of any constants that are to be loaded into memory. Some load- ers expect data initialization to be specified separately from the binary code.
• Relocation information. When the linker is invoked most of the modules that are to be linked will need to be relocated as the modules are concate-
nated. T he whole issue of module relocation is complicated because some address references can be relocated and others cannot. We discuss reloca-
tion later, but here we note that the assembler specifies which addresses can be relocated and which others cannot.
Location of programs in memory Up until now we have assumed that programs are located in memory at an
address that is specified by a
.org
pseudo operation. T his may indeed be the case in systems programming, where the programmer has a reason for wanting a
program to be located at a specific memory location, but typically the program- mer does not care where the program is located in memory. Furthermore, when
separately assembled or compiled programs are linked together, it is difficult or impossible for the programmer to know exactly where each module will be
located after linking, as they are concatenated one after the other. For this reason most addresses are specified as being
relocatable
in memory, except perhaps for addresses such as IO addresses, which may be fixed at an absolute memory loca-
tion.
In the next section we discuss relocation in more detail; here we merely note that it is the assembler’s responsibility to mark symbols as being relocatable. Whether
a given symbol is relocatable or not depends upon both the assembly language and the operating system’s conventions. In any case, this relocation information
is included in the assembled module for use by the linker andor loader in a
relo- cation dictionary
. Symbols that are relocatable are often marked with an “R” after their value in the assembler’s listing file.
5.3 Linking and Loading