Slide S2-14 Section 2.3.4 Program Blocks segments of code that are logically rearranged within a single object program unit ------------------- | ----------- | | | block 1 | | | ----------- | | ----------- | | | block 2 | | | ----------- | | ----------- | | | block 1 | | | ----------- | | ----------- | | | block 2 | | | ----------- | ------------------- Pass 1 - a separate location counter for each block - when storing a label in symbol table, store the block number as well At the end of pass 1, the length of each block is known; the assembler can now assign a starting address to each block Slide S2-15 Pass 2 the value for a label is the value in the symbol table plus the starting address for the block Note that the assembler does not physically rearrange the generated code in the object program (the assembler puts the load address with object code; loader will load accordingly) --------- | block 1 | 0000 ... --------- --------- | block 2 | 0300 ... --------- --------- | block 1 | 0150 ... --------- --------- | block 2 | 0450 ... --------- ====================================================================== ====================================================================== Slide S2-16 Section 2.3.5 Control Sections segments that are translated into independent object program units --------- | CSECT 1 | --------- --------- | CSECT 2 | --------- - need to link together different control sections . assembler cannot do the linking . assembler provides information for each external reference that will allow the loader to perform the required linking - need extended format (type 4) for instructions containing external references 15 0003 CLOOP +JSUB RDREC 4B 1 00000 / \ ni=11 e=1 bp=00 no relative addressing Slide S2-17 160 0017 +STCH BUFFER,X 57 9 00000 / \ ni=11 x=1 e=1 bp=00 190 0028 MAXLEN WORD BUFEND-BUFFER 000000 ====================================================================== ====================================================================== Slide S2-18 Two-Pass Assembler with Overlay Structure When memory was expensive, assemblers used this technique to reduce the space required. Since memory is cheap now, this technique is not used as much anymore. --------------------------- | main routine | root |---------------------------| segment | shared tables | | and routines | --------------------------- | ----------+----------- | | -------------- -------------- Pass 1 | Pass 1 | | Pass 2 | Pass 2 segment | tables and | | tables and | segment | routines | | routines | -------------- -------------- main segment : 20K Pass 1 segment : 50K Pass 2 segment : 60K ----- | | ----- | ------------------------+------------------------ | | | | ----- ----- ----- ----- | | | | | | | | ----- ----- ----- ----- | | | | -----+----- ... ... ... | | ----- ----- | | | | ----- ----- | | ... ... ====================================================================== ====================================================================== Slide S2-19 Section 2.4.1 One-Pass Assemblers Why did we need two passes? forward references - data items - labels Load-and-go one-pass assemblers generate object code in memory for immediate execution (no object program is written out, and no loader is needed) . . . 1000 J RDREC . . 101D J RDREC . . ------------------------ | name | value | ref | | | | ptr | |--------+-------+-------| | | | | --------- --------- | RDREC | | ----+---->| 1000 | |--->| 101D | | | | | | --------- --------- | | | | 2000 RDREC ... Slide S2-20 If the one-pass assembler generates object program on secondary storage, i.e., not load-and-go assembler - put zero when address not known (and remember the references using symtbl as before) - when address is known, generate records to fill references 1000 J RDREC 1000 J 0000 . . 101D J RDREC 101D J 0000 . . 2000 RDREC 1000 2000 101D 2000 ====================================================================== ====================================================================== Slide S2-21 Section 2.4.2 Multi-Pass Assemblers in the two-pass assembler symbol defining directives MAXLEN EQU BUFEND-BUFFER symbols on the right hand side must be defined previously A EQU B B EQU C C EQU HALFSZ EQU MAXLEN/2 symtbl --------------------------------------------- | | | #of | | ref | | name | value | undef | expression | ptr | | | | sym | | | |--------+-------+-------+--------------+-----| | | | | | | | HALFSZ | | 1 | MAXLEN/2 | | | | | | | | ---------- | MAXLEN | | | | --|-->| HALFSZ | | | | | | | | ---------- | | | | | | Slide S2-22 MAXLEN EQU BUFEND-BUFFER symtbl -------------------------------------------- | | | #of | | ref | | name | val | undef | expression | ptr | | | | sym | | | |--------+-----+-------+---------------+-----| | | | | | | | HALFSZ | | 1 | MAXLEN/2 | | | | | | | | ---------- | MAXLEN | | 2 | BUFEND-BUFFER | --|-->| HALFSZ | | | | | | | | ---------- | | | | | | ---------- | BUFEND | | | | --|-->| MAXLEN | | | | | | | | ---------- | | | | | | ---------- | BUFFER | | | | --|-->| MAXLEN | | | | | | | | ---------- | | | | | | PREVBT EQU BUFFER-1 ====================================================================== ====================================================================== (Bytes and Bits - Page 1) Slide S2-23 /* Some miscellaneous routines on bytes and bits (I'd like to acknowledge Mahesh Dodani's contribution in designing these routines). */ #include /* Note: A byte consisting of 8 bits is as follows: --------------- |8|7|6|5|4|3|2|1| --------------- When a byte is represented in the octal form as '\xyz', x is the value of bits |8|7|, y is the value of bits |6|5|4|, and z is the value of bits |3|2|1|. An integer is (on most machines) 4 bytes as follows: --------------------------- |Byte-1|Byte-2|Byte-3|Byte-4| --------------------------- Some machines put the most significant digit in Byte-1 and the least significant digit in Byte-4. Some machines put the most significant digit in Byte-4 and the least significant digit in Byte-1. */ typedef char byte; /* this means 'byte' is equivalent to 'char' */ char HEXDIG[16] = {'0', '1', '2', '3', '4', '5', '6', '7', '8', '9', 'A', 'B', 'C', 'D', 'E', 'F' }; byte RMHBHEX[16] = {'\000', '\001', '\002', '\003', '\004', '\005', '\006', '\007', '\010', '\011', '\012', '\013', '\014', '\015', '\016', '\017' }; /* different values for a byte when a hex digit is placed in its right-most half-byte (the four bits in the left-most half-byte are set to 0), e.g., 015 = 00001101 = D */ byte BITON[8] = {'\001', '\002', '\004', '\010', '\020', '\040', '\100', '\200' }; /* different values a byte can have when only one bit in it is on, i.e., only one bit is 1 and the other seven bits are 0 */ byte BITOFF[8] = {'\376', '\375', '\373', '\367', '\357', '\337', '\277', '\177' }; /* different values a byte can have when only one bit in it is off, i.e., only one bit is 0 and the other seven bits are 1 */ /*******************************************************************/ void byte_to_hex(onebyte) /* This routine accepts a byte and prints the hex form for the */ /* left-most half-byte and the hex form for the right-most */ /* half-byte. */ byte onebyte; { byte b; void prnt_bits(); (Bytes and Bits - Page 2) Slide S2-24 printf("The bits in the byte \n"); prnt_bits(onebyte); printf("The corresponding hex digits \n"); /* get the left-most half-byte */ b = onebyte >> 4; /* some systems do sign extension when performing a right shift */ /* make sure that the first 4 bits of b are 0's (note that '\017' */ /* is '00001111') */ b = b & '\017'; printf("%c", HEXDIG[b]); /* note that b will be used as an integer */ /* get the right-most half-byte (note that '\017' is '00001111') */ b = onebyte & '\017'; printf("%c \n", HEXDIG[b]); }/* end of byte_to_hex */ /*******************************************************************/ void copy_bit(byte_ptr, bitpos, bitval) /* This routine copies bitval (0 or 1) into a byte at position */ /* bitpos. */ byte *byte_ptr; int bitpos, bitval; { void turnon_bit(), turnoff_bit(); if ( bitval ) turnon_bit(byte_ptr, bitpos); else turnoff_bit(byte_ptr, bitpos); }/* end of copy_bit */ /*******************************************************************/ void turnon_bit(byte_ptr, bitpos) /* This routine sets the bit at position bitpos in a byte to 1. */ byte *byte_ptr; int bitpos; { *byte_ptr = *byte_ptr | BITON[bitpos - 1]; }/* end of turnon_bit */ /*******************************************************************/ void turnoff_bit(byte_ptr, bitpos) /* This routine sets the bit at position bitpos in a byte to 0. */ byte *byte_ptr; int bitpos; { (Bytes and Bits - Page 3) Slide S2-25 *byte_ptr = *byte_ptr & BITOFF[bitpos - 1]; }/* end of turnoff_bit */ /*******************************************************************/ void prnt_bits(onebyte) /* This routine prints all the bits in a byte. */ byte onebyte; { int i, is_bit_on(); for ( i = 8; i > 0; i-- ) if ( is_bit_on(onebyte, i) ) printf("1-"); else printf("0-"); printf("\n"); }/* end of prnt_bits */ /*******************************************************************/ int is_bit_on(onebyte, bitpos) /* This routine returns whether or not the bit at position */ /* bitpos in the byte onebyte is 1. */ byte onebyte; int bitpos; { byte b; int i; /* get the bit at bitpos all the way to the right of the byte */ b = onebyte >> (bitpos - 1); /* make sure the remaining bits are zero (note that '\001' is */ /* '00000001') */ b = b & '\001'; i = b; /* change b to integer (this is not really needed) */ return(i); /* note that we could have returned b */ }/* end of is_bit_on */ /*******************************************************************/ void prnt_int(i4) /* This routine prints all the bits in an integer (the integer */ /* is assumed to have 4 bytes). */ int i4; { int *int_ptr, k; byte *byte_ptr; (Bytes and Bits - Page 4) Slide S2-26 int_ptr = &i4; byte_ptr = (byte *) int_ptr; /* we are using the 'cast' operator to change 'pointer-to-integer' to 'pointer-to-byte'; byte_ptr is now pointing to Byte-1 of the integer */ /* If Byte-1 contains the most significant digit, byte_ptr is pointing to the most significant digit. So, this is what we do: for ( k = 1; k <= 4; ++k ) { prnt_bits(*byte_ptr); ++byte_ptr; } */ /* If Byte-1 contains the least significant digit, byte_ptr is pointing to the least significant digit. So, this is what we do: */ byte_ptr = byte_ptr + 3; /* byte_ptr is now pointing to Byte-4 */ for ( k = 1; k <= 4; ++k ) { prnt_bits(*byte_ptr); --byte_ptr; } }/* end of prnt_int */ /*******************************************************************/ void two_hex_to_byte(lmhb, rmhb, byte_ptr) /* This routine takes two hex characters and puts them in a */ /* byte. For example, it takes the hex characters 'D' and '7' */ /* and puts them in a byte to have 'D7' in the byte. */ char lmhb, /* left-most half-byte */ rmhb; /* right-most half-byte */ byte *byte_ptr; { int k; /* find which hex lmhb is */ for ( k = 0; HEXDIG[k] != lmhb; ++k ) ; /* put the lmhb in the byte */ *byte_ptr = RMHBHEX[k]; *byte_ptr = *byte_ptr << 4; /* find which hex rmhb is */ for ( k = 0; HEXDIG[k] != rmhb; ++k ) ; /* put the rmhb in the byte */ *byte_ptr = *byte_ptr | RMHBHEX[k]; }/* end of two_hex_to_byte */ /*******************************************************************/