CSC231 Homework 7 Solution Programs
--D. Thiebaut 13:21, 1 November 2012 (EDT)
Contents
Program 1
- This solution is from Gavi and shows she got the hints I gave the class about this array of character. The trick here is that since all the characters are listed in order in the string, you have character '0' at index 0 in the string. Character '1' at Index 1. Character '2' at Index 2... Character '9' at Index 9. And now for the magic: Character 'A' is at Index 10. Character 'B' at Index 11, all the way to Character 'F' at Index 15. So we do not need to test whether the number we want to print in hex is less than 10 or not. We just take the number, use it as an index in the string and pull the character that corresponds to it!
;;; ; hw7a.asm
;;; ; Gavi Levy Haskell
;;; ; 231a-ae
;;; ;
;;; ;
;;; ; Displays the contents of a double-word in decimal and
;;; ; hexadecimal.
;;; ;
;;; ; Prints:
;;; ; x = 305441741 = 0x1234ABCD
;;; ;
;;; ;
;;; ; nasm -f elf -F stabs hw7a.asm
;;; ; gcc -m32 -o hw7a driver.c asm_io.o hw7a.o
;;; ; ./hw7a
%include "asm_io.inc"
;; -----------------
;; DATA SECTION
;; -----------------
section .data
x dd 0x1234ABCD
msg dd " x = ", 0x00
msg2 dd " = 0x", 0x00
hexChr db "0123456789ABCDEF"
;; -----------------
;; CODE SECTION
;; -----------------
section .text
global asm_main
asm_main:
mov eax, msg
call print_string ; print " x = "
mov eax, dword[x]
call print_int ; print "305441741"
mov eax, msg2
call print_string ; print " = 0x"
mov ecx, 8
for: mov ebx, dword[x] ; ebx <-- current rotation of x
rol ebx, 4 ; rotate first byte to end
mov dword[x], ebx ; save current rotation in x
and ebx, 0x000000F ; keep only last digit in ebx
mov al, byte[hexChr + ebx]
call print_char ; print the character of hexChr
; corresponding to the digit
loop for
call print_nl
;; return to C program
ret
Another good solution that doesn't use the array is provided by Naomi:
;;; hw7a.asm
;;; 231a-ad
;;; Naomi Long
;;;
;;; This program prints the decimal representation of the hex number
;;; 0x1234ABCD and then prints out the hex digits. The output is shown
;;; below, sandwiched between two prompts:
;;;
;;; [231a-ad@grendel ~/hw7]$ ./hw7a
;;; x = 305441741 = 0x1234ABCD
;;; [231a-ad@grendel ~/hw7]$
%include "asm_io.inc"
;;; -------------------------
;;; data segment
;;; -------------------------
section .data
x dd 0x1234ABCD
xeq db "x = ",0x00
eq db " = 0x",0x00
;;; -------------------------
;;; code area
;;; -------------------------
section .text
global asm_main
asm_main:
;;; print "x = "
mov eax, xeq
call print_string ; prints "x = "
;;; print decimal representation and " = 0x"
mov eax, dword[x]
call print_int ; prints 305441741
mov eax, eq
call print_string ; prints " = 0x"
;;; print hex representation
mov ecx, 8 ; 8 hex digits to loop over
start:
mov eax, dword[x] ; gets current hex rotation
rol eax, 4 ; moves first hex to last position
mov dword[x], eax ; saves rotation
and eax, 0x0000000f ; remove all but last hex digit
cmp eax, 10 ; check if hex digit letter or number
jae letr ; jump to treat letter as ascii char
call print_int ; prints last hex digit if number
jmp loop ; skip to end of loop
letr: add eax, 'A'-10 ; offset dec to ascii character
call print_char ; prints last hex number as ascii char
loop: loop start ; loop to print all 8 hex digits
call print_nl ; prints new line after loop is done
;;; return to C program
ret
Comments
Comments about the programs submitted from the class
- Put a header above each function. In it put
- the name of the function
- the parameters it receives
- whether it modifies any of the registers
- what it returns, if any
- Avoid unreachable code
ret ret
- Put the last ret instruction at the end of the main function, not at the end of the listing.
- Don't call functions func1 and func2.
- If you are working with characters, use a byte register, not a word or double word register.
- Use self-documenting labels that will help the reader follow the code better:
- Instead of
cmp al, 9 jgt grthn ... grthn:
- use
cmp al, 9 jgt printLetter ... printLetter:
- Don't be afraid to be clever!
xEqual db "x = ", 0x00 equal equ xEqual+1
- Don't be afraid to double check what you write:
add al, 'A' sub al, 10
- can be performed with just 1 operation:
add al, 'A'-10
Comments about the Hints
- See solution program above...
- Pushing the hints one more step: A python program to generate a lookup table in assembly!
# generateTableLookupHexadecimal.py
# D. Thiebaut
# Generates a lookup table for translating a byte into its string equivalent in hex.
# Note: This is for Python Version 2.X. For Version 3.X, add parentheses to the print
# statements.
# generate table declaration
s = "table\tdb\t"
# generate 256 strings of 2 bytes representing the 2 hex digits
for i in range(256):
#print "%d %02X" % (i, i )
if ( i!=0 and i%8==0 ):
s += "\n\tdb\t"
else:
if ( i!=0 ):
s += ", "
s += '"%02X"' % i
print s
Output
table db "00", "01", "02", "03", "04", "05", "06", "07"
db "08", "09", "0A", "0B", "0C", "0D", "0E", "0F"
db "10", "11", "12", "13", "14", "15", "16", "17"
db "18", "19", "1A", "1B", "1C", "1D", "1E", "1F"
db "20", "21", "22", "23", "24", "25", "26", "27"
db "28", "29", "2A", "2B", "2C", "2D", "2E", "2F"
db "30", "31", "32", "33", "34", "35", "36", "37"
db "38", "39", "3A", "3B", "3C", "3D", "3E", "3F"
db "40", "41", "42", "43", "44", "45", "46", "47"
db "48", "49", "4A", "4B", "4C", "4D", "4E", "4F"
db "50", "51", "52", "53", "54", "55", "56", "57"
db "58", "59", "5A", "5B", "5C", "5D", "5E", "5F"
db "60", "61", "62", "63", "64", "65", "66", "67"
db "68", "69", "6A", "6B", "6C", "6D", "6E", "6F"
db "70", "71", "72", "73", "74", "75", "76", "77"
db "78", "79", "7A", "7B", "7C", "7D", "7E", "7F"
db "80", "81", "82", "83", "84", "85", "86", "87"
db "88", "89", "8A", "8B", "8C", "8D", "8E", "8F"
db "90", "91", "92", "93", "94", "95", "96", "97"
db "98", "99", "9A", "9B", "9C", "9D", "9E", "9F"
db "A0", "A1", "A2", "A3", "A4", "A5", "A6", "A7"
db "A8", "A9", "AA", "AB", "AC", "AD", "AE", "AF"
db "B0", "B1", "B2", "B3", "B4", "B5", "B6", "B7"
db "B8", "B9", "BA", "BB", "BC", "BD", "BE", "BF"
db "C0", "C1", "C2", "C3", "C4", "C5", "C6", "C7"
db "C8", "C9", "CA", "CB", "CC", "CD", "CE", "CF"
db "D0", "D1", "D2", "D3", "D4", "D5", "D6", "D7"
db "D8", "D9", "DA", "DB", "DC", "DD", "DE", "DF"
db "E0", "E1", "E2", "E3", "E4", "E5", "E6", "E7"
db "E8", "E9", "EA", "EB", "EC", "ED", "EE", "EF"
db "F0", "F1", "F2", "F3", "F4", "F5", "F6", "F7"
db "F8", "F9", "FA", "FB", "FC", "FD", "FE", "FF"
Using this code, one can get a pointer to the string representing the hexadecimal value in, for example, al:
mov al, someValue mov bl, al ;bl contains the same value and ebx, 0x000000ff ;extend bl into ebx shl ebx, 1 ;multiply ebx by 2 (because the table is a table of words) lea ecx, [ebx+table] ;Load Effective Address ebx+table in ecx mov eax, 4 mov ebx, 1 mov edx, 2 ;get ready to print 2 chars int 0x80 ;print them
Problem 2
;;; 10/31/2012
;;; hw7b.asm
;;; Yoshie Sasaki (edited by D. Thiebaut)
;;;
;;; This program takes a string of bytes where two characters have been
;;; packed in each byte. The first nybble (high) represents the lower
;;; nybble of an uppercase ascii. Similarly for the second (low) nybble.
;;; Only ascii chars between '@' and 'O' can be represented that way
;;; (@, A, B, C, D, E, F, G, H, I, J, K, L, M, N, O)
;;; l
;;; Hexidecimal numbers 4 in the upper nibble represents chars "@ and
;;; A-O" in Ascii Code. If we want to just use these chars, memory
;;; can be saved. The data section can hold the lower nibbles, and the
;;; fixed upper nibble can be accounted for in the code/text section.
;;; The program connects the lower nibbles to the fixed upper to
;;; print the desired Ascii chars. A function is used to print the contents
;;; of each byte in memory. Strings from address "y" and "z" is printed.
;;;
;;; Example:
;;; yLen dd 18
;;; y db 0xd5, 0x54, 0x00, 0x31, 0xe4, 0x94, 0x0f, 0x21, 0xd1
;;; db 0x01, 0xe4, 0x02, 0xfe, 0x90, 0xf6, 0x07, 0x1e, 0x10
;;;
;;; get decoded as
;;; MEED CANDID OBAMA AND BONI OF GANA
;;;
;;; To Link and Run:
;;; nasm -f elf -F stabs hw7b.asm
;;; gcc -m32 -o hw7b driver.c asm_io.o hw7b.o
;;; ./hw7b
%include "asm_io.inc"
;; -------------------------
;; data segment
;; -------------------------
section .data
yLen dd 18
y db 0xd5, 0x54, 0x00, 0x31, 0xe4, 0x94, 0x0f, 0x21, 0xd1
db 0x01, 0xe4, 0x02, 0xfe, 0x90, 0xf6, 0x07, 0x1e, 0x10
zLen dd 24
z db 0xef, 0x07, 0xff, 0x40, 0xd1, 0x41, 0xd5, 0x03, 0x81
db 0xee, 0x5c, 0x01, 0xe4, 0x02, 0x14, 0x0d, 0x1e, 0x0d
db 0xf1, 0xe0, 0x9e, 0x0c, 0x9d, 0x10
;; -------------------------
;; code area
;; -------------------------
section .text
global asm_main
asm_main:
;;;
;;; --- Decode y string ---
;;;
mov eax, 0
mov ecx, dword[yLen] ;save memory length
mov edx, y
;Go through bytes in memory & print char A to O
fory: call printByte
inc edx ;inc byte count
loop fory
call print_nl
;;;
;;; --- Decode z string ---
;;;
mov eax, 0
mov ecx, dword[zLen];save memory length
mov edx, z
;Go through bytes in memory & print char A to O
forz: call printByte
inc edx ;inc byte count
loop forz
call print_nl
;;;
;;; --- END (return to C program)
;;;
ret
;;; -------------------------------------------------------------
;;; PrintByte(As in the contents of the byte in memory)
printByte: mov al, byte[edx] ;Get next byte
;;; print upper nybble...
ror al, 4 ;Rotate the upper half down
and al, 0x0F ;Hide the rest
add al, 0x40 ;Fill the top half with set Hex val
cmp al, 0x40
jne noSpaceU ;Skip next step if not "@"
mov al, ' ' ;Else, "@" = " "
noSpaceU: call print_char
;;; print lower nybble...
mov al, byte[edx] ;Get byte again(Now looking at lower)
and al, 0x0F ;Do the same as upper half
add al, 0x40
cmp al, 0x40
jne noSpaceL
mov al, ' '
noSpaceL: call print_char
ret