Difference between revisions of "CSC231 Homework 8 2017"

From dftwiki3
Jump to: navigation, search
(Problem #1: Programming in C)
(Testing Your Code)
 
(42 intermediate revisions by the same user not shown)
Line 1: Line 1:
<center>
+
--[[User:Thiebaut|D. Thiebaut]] ([[User talk:Thiebaut|talk]]) 16:09, 14 April 2017 (EDT)
 +
----
 +
 
 +
<!--center>
 
<font size="+2">Page under construction!</font>
 
<font size="+2">Page under construction!</font>
 
</center>
 
</center>
Line 5: Line 8:
 
<center>
 
<center>
 
[[File:UnderConstruction.jpg|300px]]
 
[[File:UnderConstruction.jpg|300px]]
</center>
+
</center-->
 
<br />
 
<br />
 
<br />
 
<br />
Line 11: Line 14:
 
=Problem #1: Programming in C=
 
=Problem #1: Programming in C=
 
<br />
 
<br />
Write a C program that receives 3 DNA strings on the ''command line'', one called '''marker1''', one called '''marker2''' and one called '''DNA''', and which zaps the bases (characters) in '''DNA''' that sit between '''marker1''' and '''marker2''' (and including those of the markers), replacing them with dashes.
+
Write a C program that receives 3 DNA strings on the ''command line'', the first one will be saved under the variable (pointer) called '''marker1''', the second one '''marker2''', and the last one'''DNA'''.  Your C program will search for the markers in the DNA, and will zap all the bases (characters) it finds between '''marker1''' and '''marker2''' (and including those of the markers), replacing them with dashes.
 
<br />
 
<br />
 
Here are some examples of how your program should operate:
 
Here are some examples of how your program should operate:
Line 50: Line 53:
 
void main( int argc, char *argv[] ) {
 
void main( int argc, char *argv[] ) {
 
   char *marker1, *marker2, *DNA;
 
   char *marker1, *marker2, *DNA;
  char *fileName;
 
  
 
   if (argc < 4 ) {
 
   if (argc < 4 ) {
Line 79: Line 81:
 
</source>
 
</source>
 
<br />
 
<br />
You should uncomment the section ''print the markers and DNA" to see how the program gets the 3 strings.
+
You may want to uncomment the section under the "print the markers and DNA" comment to see how the program gets the 3 strings.  Comment it back when you understand what happens.
 
<br />
 
<br />
 +
 
==Testing Your Program==
 
==Testing Your Program==
 
<br />
 
<br />
Line 91: Line 94:
 
# Your name
 
# Your name
 
# Tests the hw8_1 program by feeding it different markers and DNA strings.
 
# Tests the hw8_1 program by feeding it different markers and DNA strings.
# The output is fed in "cat -v" which will display unprintable (junk) characters.
+
# The output is fed to "cat -v" which will display unprintable (junk) characters,
 +
# if any.
  
 
prog="./hw8_1"
 
prog="./hw8_1"
Line 117: Line 121:
 
  cp testHw8_1.sh  testHw8_1sol.sh
 
  cp testHw8_1.sh  testHw8_1sol.sh
 
   
 
   
* Next, edit the second script and change the assignment into the $prog variable:
+
* Next, edit the second script and change the assignment to the $prog variable to:
 
   
 
   
 
  prog="hw8_1sol"
 
  prog="hw8_1sol"
 
   
 
   
: (no dot dashes here!)
+
: (no dot-slash here!)
 
* You now have two scripts that should output '''the exact same text''', if your program is correct.
 
* You now have two scripts that should output '''the exact same text''', if your program is correct.
* You can go one more step toward being certain of the correctness of your output by using the '''diff''' command, as you did in  previous assignment.
+
* You can go one more step toward being certain of the correctness of your output by using the '''diff''' command, as you did in a previous assignment.
 +
<br />
 +
 
 +
==Hints==
 +
<br />
 +
You should look up the '''C string.h''' library on the Web, for ideas...
 +
<br />
 +
 
 +
==Moodle Submission==
 +
<br />
 +
* Look for the '''Homework 8 Problem 1''' section.
 +
<br />
 +
=Problem #2=
 +
<br />
 +
Write an assembly program called '''hw8_2.asm''' that contains several functions, but no main program.  The main program will be in a separate file, that will be assembled separately, and linked to your program to create a fully executable file.
 +
 
 +
The functions should behave as follows:
 +
<br />
 +
* '''f1( s )'''.  Receives the address of a string '''s''' in the stack, and converts the string to uppercase, replacing all the alphabetic characters in the string to uppercase.  We assume that the string, as in C, is terminated by a '\0' char.  Here is an example of how to call the function:
 +
::<source lang="asm">
 +
s1          db      "Hello world!", 0
 +
s1Len      equ      $-s1
 +
 
 +
...
 +
 
 +
            mov    eax, s1
 +
            push    eax
 +
            call    f1
 +
 
 +
            mov    ecx, s1
 +
            mov    edx, s1Len-1    ; figure out why the -1!
 +
            mov    eax, 4
 +
            mov    ebx, 1
 +
            int    0x80
 +
</source>
 +
:The code above will print "HELLO WORLD!"
 +
<br />
 +
* '''f2(a, b, c)''': f2 receives 3 integer parameters in the stack and computes '''2a + 3b -c''' and returns this value in eax.
 +
:Here is an example of how to call the function:
 +
::<source lang="asm">
 +
a          dd      3
 +
b          dd      5
 +
c          dd      7
 +
 
 +
...
 +
            push    dword[a]
 +
            push    dword[b]
 +
            push    dword[c]
 +
            call    f2
 +
           
 +
; upon return from f2, eax contains 2a + 3b - c = 2*3 + 3*5 - 7 = 14
 +
 
 +
</source>
 +
<br />
 +
* '''f3( table, n )''': this function receives in the stack the address of an array of ints, and the number of ints in the array.  It returns in eax the number of even ints in the array.  <font color="magenta">f3 should not modify any of the other registers, besides eax, of course!</font>
 +
:Here is an example of how to call the function f3:
 +
::<source lang="asm">
 +
array    dd      3, 5, 0, 1, 2, 10, 100, 4, 1
 +
arrayLen  equ      ($-array)/4                      ; figure out the /4 part.
 +
 
 +
 
 +
...
 +
            mov    eax, array
 +
            push    eax
 +
            mov    eax, arrayLen
 +
            push    eax
 +
            call    f3
 +
            ; upon return from f3, eax contains 5, because there are 5 even numbers in array.
 +
 
 +
</source>
 +
<br />
 +
==Making Your Functions Known to Other Programs==
 +
<br />
 +
Your '''hw8_2.asm''' program should contain only the 3 functions described above.  No need for a data segment or for a _Start label.  However, you need to make your functions known to the main program that is in a different file, and that will be linked with your program.  So you need to add these 3 lines at the top of your program:
 +
<br />
 +
<br />
 +
::<source lang="asm">
 +
          global f1
 +
          global f2
 +
          global f3
 +
</source>
 +
<br />
 +
 
 +
==Testing Your Code==
 +
<br />
 +
Create the following program and call it test.asm.  It will be the test program for your hw8_2.asm program:
 +
<br />
 +
::<source lang="asm">
 +
;;;------------------------------------------------------------
 +
;;; test.asm   
 +
;;; tests the functions in hw8_2.asm by calling each one
 +
;;; and printing its result.
 +
;;;------------------------------------------------------------
 +
extern _printString
 +
extern _println
 +
extern _printDec
 +
 
 +
extern f1        ; f1, f2, and f3 are declared somewhere else
 +
extern  f2
 +
extern f3
 +
 
 +
;;;------------------------------------------------------------
 +
;;; some variables to pass to the functions
 +
;;;------------------------------------------------------------
 +
section .data
 +
s1 db "Hello there! 12345", 0
 +
s1Len equ $-s1
 +
Table dd 1, 2, 3, 30, 100, 200
 +
TableLen equ ($-Table)/4
 +
x1 dd 10
 +
x2 dd 20
 +
x3 dd -1
 +
 
 +
;;;------------------------------------------------------------
 +
;;; main program
 +
;;;------------------------------------------------------------
 +
section .text
 +
global _start
 +
_start:
 +
;;; test f1
 +
mov eax, s1 ; pass s1 to f1
 +
push eax
 +
call f1
 +
mov ecx, s1
 +
mov edx, s1Len
 +
call _printString
 +
call _println
 +
 +
;;; test f2
 +
push dword[x1] ; pass x1, x2, x3 to f2
 +
push dword[x2]
 +
push dword[x3]
 +
call f2
 +
call _printDec
 +
call _println
 +
 
 +
;;; test f3
 +
mov eax, Table ; pass Table and length to f3
 +
push eax
 +
mov eax, TableLen
 +
push eax
 +
call f3
 +
call _printDec
 +
call _println
 +
 +
;;; ; exit
 +
mov    ebx, 0
 +
mov    eax, 1
 +
int    0x80
 +
</source>
 +
<br />
 +
* Assemble, link, and run as follows:
 +
 +
231b@aurora ~ '''nasm -f elf test.asm'''
 +
231b@aurora ~ '''nasm -f elf hw8_2.asm'''
 +
231b@aurora ~ '''nasm -f elf 231Lib.asm'''
 +
231b@aurora ~ '''ld -melf_i386  -o test test.o hw8_2.o 231Lib.o'''
 +
231b@aurora ~ '''./test'''
 +
HELLO THERE! 12345
 +
81
 +
4
 +
 +
;Note:
 +
: The test program above does not check that f3 does not modify the ebx, ecx, edx, esi, or edi registers.  You can add additional  testing yourself! 
 +
<br />
 +
<br />
 +
 
 +
<!-- ==================================================================== -->
 +
 
 +
<onlydft>
 +
<br />
 +
<br /><br />
 +
<br /><br />
 +
<br /><br />
 +
<br /><br />
 +
<br /><br />
 +
<br /><br />
 +
<br /><br />
 +
<br /><br />
 +
<br /><br />
 +
<br /><br />
 +
<br /><br />
 +
<br /><br />
 +
<br /><br />
 +
<br /><br />
 +
<br /><br />
 +
<br /><br />
 +
<br />
 +
=Solution Program=
 +
==Problem 1==
 +
 
 +
<br />
 +
::<source lang="C">
 +
#include <stdio.h>
 +
#include <stdlib.h>
 +
#include <string.h>
 +
 
 +
 
 +
void main( int argc, char *argv[] ) {
 +
  char *marker1, *marker2, *DNA;
 +
  char *fileName;
 +
 
 +
  if (argc < 4 ) {
 +
    printf( "syntax: %s marker1 marker2 DNA\n", argv[0] );
 +
    return;
 +
  }
 +
 
 +
  marker1 = argv[1];
 +
  marker2 = argv[2];
 +
  DNA    = argv[3];
 +
 
 +
  //--- print the markers and DNA ---
 +
  /* (for debugging purposes)
 +
  printf( "Marker1 = %s\n", marker1 );
 +
  printf( "Marker2 = %s\n", marker2 );
 +
  if ( strlen( DNA ) > 80 )
 +
    printf( "DNA    = %.*s...%s (%d bases)\n\n",
 +
          10, DNA, DNA+((int)strlen(DNA)-10),
 +
  (int) strlen( DNA) );
 +
  else
 +
    printf( "DNA    = %s\n\n", DNA );
 +
  */
 +
 
 +
  //--- add your code below this point ---
 +
  char *first, *second;
 +
  first = strstr( DNA, marker1 );
 +
  if ( first == NULL ) {
 +
    printf( "%s\n", DNA );
 +
    return;
 +
  }
 +
  second = strstr( first+1, marker2 );
 +
  if ( second == NULL ) {
 +
    printf( "%s\n", DNA );
 +
    return;
 +
  }
 +
 
 +
  char *p;
 +
  for ( p= first; p < second+strlen(marker2); p++ )
 +
    *p = '-';
 +
 
 +
  printf( "%s\n", DNA );
 +
}
 +
</source>
 +
==Problem 2==
 +
<br />
 +
::<source lang="asm">
 +
;;; ------------------------------------------------------
 +
;;; hw8_2.asm
 +
;;; D. Thiebaut
 +
;;; ------------------------------------------------------
 +
 
 +
global f1
 +
global f2
 +
global f3
 +
 
 +
;;; ------------------------------------------------------
 +
;;; f1( s ): modifies s in place and make it uppercase.
 +
f1: push ebp
 +
mov ebp, esp
 +
push ebx
 +
mov ebx, dword[ebp+8]
 +
.for: cmp byte[ebx], 0
 +
je .done
 +
cmp byte[ebx],'a'
 +
jl .endfor
 +
cmp byte[ebx],'z'
 +
jg .endfor
 +
add byte[ebx],'A'-'a'
 +
.endfor:
 +
inc ebx
 +
jmp .for
 +
.done:
 +
pop ebx
 +
pop ebp
 +
ret 4
 +
 
 +
;;; ------------------------------------------------------
 +
;;; f2( a, b, c )
 +
;;; returns 2a + 3b -c in eax
 +
;;; computes it as 2(a+b) + b - c (fewer operations)
 +
f2: push ebp
 +
mov ebp, esp
 +
mov eax, dword[ebp+8+4+4] ; get first param
 +
add eax, dword[ebp+8+4]  ; eax <- a+b
 +
add eax, eax       ; eax <- 2(a+b)
 +
add eax, dword[ebp+8+4]  ; eax <- 2(a+b) + b
 +
sub eax, dword[ebp+8]    ; eax <- 2a + 3b -c
 +
pop ebp       ;
 +
ret 4*3       ; return and get rid of 3 ints
 +
 
 +
 
 +
;;; ------------------------------------------------------
 +
;;; f3( array, n )
 +
;;; computes the number of even ints in array, of length n.
 +
;;; returns this number in eax.
 +
f3: push ebp
 +
mov ebp, esp
 +
 +
push ebx
 +
push ecx
 +
 +
mov ebx, dword[ebp+8+4] ; ebx <- array
 +
mov ecx, dword[ebp+8] ; ecx <- n
 +
mov eax, 0 ; number of even ints
 +
.for: and dword[ebx], 1 ; and array[i] with 1
 +
jnz .notEven ; if result is 1, then odd number
 +
.even: inc eax ; otherwise, add 1 to counter.
 +
.notEven:
 +
add ebx, 4
 +
loop .for
 +
 
 +
pop ecx
 +
pop ebx
 +
 +
pop ebp
 +
ret 2*4
 +
 
 +
</source>
 +
</onlydft>
 +
<br />
 +
<br />
 +
<br />
 +
<br />
 +
<br />
 +
<br />
 +
<br />
 +
<br />
 +
<br />
 +
<br />
 +
<br />
 +
<br />
 +
<br />
 +
<br />
 +
<br />
 +
<br />
 +
<br />
 +
<br />
 +
<br />
 +
<br />
 +
<br />
 +
[[Category:CSC231]][[Category:Nasm]][[Category:Homework]]

Latest revision as of 04:40, 25 April 2017

--D. Thiebaut (talk) 16:09, 14 April 2017 (EDT)





Problem #1: Programming in C


Write a C program that receives 3 DNA strings on the command line, the first one will be saved under the variable (pointer) called marker1, the second one marker2, and the last one, DNA. Your C program will search for the markers in the DNA, and will zap all the bases (characters) it finds between marker1 and marker2 (and including those of the markers), replacing them with dashes.
Here are some examples of how your program should operate:

231b@aurora ~ $ ./hw8_1 AGC ACC ACCGGGGGAGCCAAAGCTTTTTACCTT
ACCGGGGG-----------------TT
 
231b@aurora ~ $ ./hw8_1 AGCA ACC ACCGGGGGAGCCAAAGCTTTTTACCTT
ACCGGGGGAGCCAAAGCTTTTTACCTT

231b@aurora ~ $ ./hw8_1 AGC AT ACCGGGGGAGCCAAAGCTTTTTACCTT
ACCGGGGGAGCCAAAGCTTTTTACCTT

231b@aurora ~ $ ./hw8_1 AC TG ACACACACGGGGGGTGTGTGTG
----------------TGTGTG

231b@aurora ~ $  ./hw8_1 AC TG TGACACACACGGGGGGTGTGTGTG
TG----------------TGTGTG


Notes
When the first or second markers are not found in the DNA, the program outputs the original DNA string.
When the first marker appears several time, the first occurrence is the one used.
When the second marker appears several times, its first occurrence after an occurrence of the first marker is used.
When found, the two markers are also zapped with dashes.


Starting Seed


Start with this skeleton program, and call it hw8_1.c.

#include <stdio.h>
#include <stdlib.h>
#include <string.h>


void main( int argc, char *argv[] ) {
  char *marker1, *marker2, *DNA;

  if (argc < 4 ) {
    printf( "syntax: %s marker1 marker2 DNA\n", argv[0] );
    return;
  }

  marker1 = argv[1];
  marker2 = argv[2];
  DNA     = argv[3];
  
  //--- print the markers and DNA ---
  /* (for debugging purpose)
  printf( "Marker1 = %s\n", marker1 );
  printf( "Marker2 = %s\n", marker2 );
  if ( strlen( DNA ) > 80 )
    printf( "DNA     = %.*s...%s (%d bases)\n\n",
          10, DNA, DNA+((int)strlen(DNA)-10), 
	  (int) strlen( DNA) );
  else
    printf( "DNA     = %s\n\n", DNA );
  */

  //--- add your code below this point ---


}


You may want to uncomment the section under the "print the markers and DNA" comment to see how the program gets the 3 strings. Comment it back when you understand what happens.

Testing Your Program


I have made the executable version of the solution available. It should already be in your PATH, so you don't need to "getcopy" it. To perform a batch test of your program against the solution, first create a batch file using the code below, and call it testHw8_1.sh.

#! /bin/bash
# testHw8_1.sh
# Your name
# Tests the hw8_1 program by feeding it different markers and DNA strings.
# The output is fed to "cat -v" which will display unprintable (junk) characters,
# if any.

prog="./hw8_1"

echo AGC ACC ACCGGGGGAGCCAAAGCTTTTTACCTT
$prog AGC ACC ACCGGGGGAGCCAAAGCTTTTTACCTT | cat -v 

echo AGCA ACC ACCGGGGGAGCCAAAGCTTTTTACCTT
$prog AGCA ACC ACCGGGGGAGCCAAAGCTTTTTACCTT | cat -v

echo AGC AT ACCGGGGGAGCCAAAGCTTTTTACCTT
$prog AGC AT ACCGGGGGAGCCAAAGCTTTTTACCTT | cat -v

echo AC TG ACACACACGGGGGGTGTGTGTG
$prog AC TG ACACACACGGGGGGTGTGTGTG | cat -v

echo AC TG TGACACACACGGGGGGTGTGTGTG
$prog AC TG TGACACACACGGGGGGTGTGTGTG | cat -v


  • Then copy this script file into another script file called testHw8_1sol.sh.
cp testHw8_1.sh  testHw8_1sol.sh

  • Next, edit the second script and change the assignment to the $prog variable to:
prog="hw8_1sol"

(no dot-slash here!)
  • You now have two scripts that should output the exact same text, if your program is correct.
  • You can go one more step toward being certain of the correctness of your output by using the diff command, as you did in a previous assignment.


Hints


You should look up the C string.h library on the Web, for ideas...

Moodle Submission


  • Look for the Homework 8 Problem 1 section.


Problem #2


Write an assembly program called hw8_2.asm that contains several functions, but no main program. The main program will be in a separate file, that will be assembled separately, and linked to your program to create a fully executable file.

The functions should behave as follows:

  • f1( s ). Receives the address of a string s in the stack, and converts the string to uppercase, replacing all the alphabetic characters in the string to uppercase. We assume that the string, as in C, is terminated by a '\0' char. Here is an example of how to call the function:
s1          db       "Hello world!", 0
s1Len       equ      $-s1

 ...

             mov     eax, s1
             push    eax
             call    f1

             mov    ecx, s1
             mov    edx, s1Len-1    ; figure out why the -1!
             mov    eax, 4
             mov    ebx, 1
             int    0x80
The code above will print "HELLO WORLD!"


  • f2(a, b, c): f2 receives 3 integer parameters in the stack and computes 2a + 3b -c and returns this value in eax.
Here is an example of how to call the function:
a           dd       3
b           dd       5
c           dd       7

 ...
             push    dword[a]
             push    dword[b]
             push    dword[c]
             call    f2
             
; upon return from f2, eax contains 2a + 3b - c = 2*3 + 3*5 - 7 = 14


  • f3( table, n ): this function receives in the stack the address of an array of ints, and the number of ints in the array. It returns in eax the number of even ints in the array. f3 should not modify any of the other registers, besides eax, of course!
Here is an example of how to call the function f3:
array     dd       3, 5, 0, 1, 2, 10, 100, 4, 1
arrayLen  equ      ($-array)/4                      ; figure out the /4 part.


 ...
             mov     eax, array
             push    eax
             mov     eax, arrayLen
             push    eax
             call    f3
             ; upon return from f3, eax contains 5, because there are 5 even numbers in array.


Making Your Functions Known to Other Programs


Your hw8_2.asm program should contain only the 3 functions described above. No need for a data segment or for a _Start label. However, you need to make your functions known to the main program that is in a different file, and that will be linked with your program. So you need to add these 3 lines at the top of your program:

           global f1
           global f2
           global f3


Testing Your Code


Create the following program and call it test.asm. It will be the test program for your hw8_2.asm program:

;;;------------------------------------------------------------
;;; test.asm     
;;; tests the functions in hw8_2.asm by calling each one
;;; and printing its result.
;;;------------------------------------------------------------
	extern	_printString
	extern	_println
	extern 	_printDec

	extern	f1        ; f1, f2, and f3 are declared somewhere else
	extern  f2
	extern	f3

;;;------------------------------------------------------------
;;; some variables to pass to the functions
;;;------------------------------------------------------------
	 section .data
s1	 db	 "Hello there! 12345", 0
s1Len	 equ	 $-s1
Table	 dd	 1, 2, 3, 30, 100, 200
TableLen equ	 ($-Table)/4
x1	 dd	 10
x2	 dd	 20
x3	 dd	 -1

;;;------------------------------------------------------------
;;; main program
;;;------------------------------------------------------------
	 section .text
	 global	 _start
_start:
;;; test f1
	 mov	 eax, s1	; pass s1 to f1
	 push	 eax
	 call	 f1
	 mov	 ecx, s1
	 mov	 edx, s1Len
	 call	 _printString
	 call	 _println
	
;;; test f2
	 push	dword[x1]	; pass x1, x2, x3 to f2
	 push	dword[x2]
	 push	dword[x3]
	 call	f2
	 call	_printDec
	 call	_println

;;; test f3
	 mov	eax, Table	; pass Table and length to f3
	 push	eax
	 mov	eax, TableLen
	 push	eax
	 call	f3
	 call	_printDec
	 call	_println
	
;;; ; exit
	mov     ebx, 0
	mov     eax, 1
	int     0x80


  • Assemble, link, and run as follows:
231b@aurora ~ nasm -f elf test.asm
231b@aurora ~ nasm -f elf hw8_2.asm
231b@aurora ~ nasm -f elf 231Lib.asm
231b@aurora ~ ld -melf_i386  -o test test.o hw8_2.o 231Lib.o
231b@aurora ~ ./test
HELLO THERE! 12345
81
4

Note
The test program above does not check that f3 does not modify the ebx, ecx, edx, esi, or edi registers. You can add additional testing yourself!





...