The Assembly Process Trends in Computer Architecture

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