NASM assembly modification guidance

0

I am trying to figure out how to modify the following code and need to also modify the code. I am unsure how to do, as we have not covered this topic in my classes. I could really use some explanation on how to modify the code to meet the requirements. I have made attempts by changing the calculation of W to X and Z to 0x20. This was not correct. Please assist me with this.

Modify the code such that if Z = 0x20, then what does N need to equal so that (X * Y) = (X << N) and (Z / Y) = (N >> Z).

Code:

%ifdef _WINDOWS_
    %xdefine _SECTION_HDR_     segment
    %xdefine _START_         _main   ; _main
    %xdefine _EXIT_          _exit
    extern  _GetStdHandle@4
    extern  _WriteFile@20
    extern  _ExitProcess@4
%else
    %xdefine _SECTION_HDR_     section
    %xdefine _START_         _start
    %xdefine _EXIT_          _exit
%endif



_SECTION_HDR_ .data            ; Data section
    CR       db     0x0D            ; ASCII Carriage Return
    LF       db     0x0A            ; ASCII Line Feed
    W        dd     0x00000002
    X        dd     0x00000004
    Y        dd     0x00000008
    Z        dd     0x00000010
    N        db     0x03            ; Shift value
    W_CHAR   db     'W'
    X_CHAR   db     'X'
    Y_CHAR   db     'Y'
    Z_CHAR   db     'Z'
    N_CHAR   db     'N' 
    EQUAL_SIGN      db    ' = '
    EQUAL_SIGN_LEN  equ    $ - EQUAL_SIGN ; Length of string 
    HEX_IND      db    '0x'
    HEX_IND_LEN  equ    $ - HEX_IND       ; Length of string 
    MSG_A0    db     'W * Y = '
    LEN_A0    equ     $ - MSG_A0          ; Length of string 
    MSG_A1    db     'W << N = '   
    LEN_A1    equ     $ - MSG_A1          ; Length of string 
    MSG_B0    db     'Z / Y = ' 
    LEN_B0    equ    $ - MSG_B0           ; Length of string 
    MSG_B1    db     'Z >> N = ' 
    LEN_B1    equ    $ - MSG_B1           ; Length of string 
    RESULT    dd     0x00000000
    VAR_STR_LEN      equ    4              ; Length of string 

_SECTION_HDR_ .bss                        ; Uninitialized Data section
    VAR_STR         resb     VAR_STR_LEN
    global VAR_STR

_SECTION_HDR_ .text                  ; Code section
    global _START_                   ; Must be declared for using gcc

; *****************************************************************************
; MACRO:   Print_Result(MSG, LENGTH, RESULT)
; PURPOSE: Sends a formatted string to STDOUT
; INPUT:   MSG    [%1] :: Address of the string to print
;          LENGTH [%2] :: Length of the message (string)
;          RESULT [%3] :: Result (byte) -- to be converted to an ASCII string.
; OUTPUT:  NONE
; USES:    
; NOTES:   
; *****************************************************************************
%macro Print_Msg 3
    ; Print message
    mov edi, %1                ; STRING [edi] :: Address of the string to print
    mov esi, %2                ; LENGTH [esi] :: Length of the string
    call _Our_Print

    ; Print the HEXADECIMAL indicator (0x)
    mov edi, HEX_IND           ; STRING [edi] :: Address of the string to print
    mov esi, HEX_IND_LEN       ; LENGTH [esi] :: Length of the string
    call _Our_Print

    ; Convert the given byte to a character-string
    mov edi, [%3]              ; BYTE   [edi] :: Byte to convert to string
    mov esi, VAR_STR           ; STRING [esi] :: Address of the string
    mov edx, VAR_STR_LEN       ; LENGTH [edx] :: Length of the string
    call _Byte_to_String

    ; Print the converted byte integer
    mov edi, VAR_STR           ; STRING [edi] :: Address of the string to print
    mov esi, 2                 ; LENGTH [esi] :: Length of the string
    call _Our_Print

    ; Print an ASCII newline (CR) control-character
    mov edi, CR                ; STRING [edi] :: Address of the string to print
    mov esi, 1                 ; LENGTH [esi] :: Length of the string
    call _Our_Print

    ; Print an ASCII newline (LF) control-character
    mov edi, LF                ; STRING [edi] :: Address of the string to print
    mov esi, 1                 ; LENGTH [esi] :: Length of the string
    call _Our_Print
%endmacro

; *****************************************************************************
; MACRO:   Print_Var(VAR_STR, VAR_STR_LEN)
; PURPOSE: Sends a formatted string to STDOUT
; INPUT:   VAR_STR     [%1] :: Address of the string to print
;          VAR_STR_LEN [%2] :: Length of the message (string)
; OUTPUT:  NONE
; USES:    
; NOTES:   
; *****************************************************************************
%macro CALL_Our_Print 2
    ; Print the variable-name
    mov edi, %1                ; STRING [edi] :: Address of the string to print
    mov esi, %2                ; LENGTH [esi] :: Length of the string
    call _Our_Print
%endmacro

; *****************************************************************************
; MACRO:   Print_Var(VAR_STR, VAR_STR_LEN)
; PURPOSE: Sends a formatted string to STDOUT
; INPUT:   VAR_STR [%1] :: Address of the string to print
;          BYTE    [%2] :: Byte to convert to its ASCII equivalent
; OUTPUT:  NONE
; USES:    
; NOTES:   
; *****************************************************************************
%macro Print_Var 2
    ; Print the variable-name
    mov edi, %1                ; STRING [edi] :: Address of the string to print
    mov esi, 1                 ; LENGTH [esi] :: Length of the string
    call _Our_Print

    ; Print the EQUAL-SIGN
    mov edi, EQUAL_SIGN        ; STRING [edi] :: Address of the string to print
    mov esi, EQUAL_SIGN_LEN    ; LENGTH [esi] :: Length of the string
    call _Our_Print

    ; Print the HEXADECIMAL indicator (0x)
    mov edi, HEX_IND           ; STRING [edi] :: Address of the string to print
    mov esi, HEX_IND_LEN       ; LENGTH [esi] :: Length of the string
    call _Our_Print

    ; Convert the given byte to a character-string
    mov edi, [%2]              ; Address of BYTE [edi] :: Byte to convert to string
    mov esi, VAR_STR           ; STRING [esi] :: Address of the string
    mov edx, VAR_STR_LEN       ; LENGTH [edx] :: Length of the string
    call _Byte_to_String

    ; Print the converted byte integer
    mov edi, VAR_STR          ; STRING [edi] :: Address of the string to print
    mov esi, 2                ; LENGTH [esi] :: Length of the string
    call _Our_Print

    ; Print an ASCII carriage return (CR) control-character
    mov edi, CR               ; STRING [edi] :: Address of the string to print
    mov esi, 1                ; LENGTH [esi] :: Length of the string
    call _Our_Print

    ; Print an ASCII newline (LF) control-character
    mov edi, LF               ; STRING [edi] :: Address of the string to print
    mov esi, 1                ; LENGTH [esi] :: Length of the string
    call _Our_Print
%endmacro

%macro Exit_Program 0
    %ifdef _WINDOWS_
        push    0
        call    _ExitProcess@4
    %else
        mov eax, 1           ; System call number (sys_exit)
        int 0x80             ; Call kernel
    %endif
%endmacro

; *****************************************************************************
; MAIN:    Demo
; PURPOSE: Main entry-point to the EXECUTABLE.  
; NOTES:   Equivalent to C language main(argc, argv)
; *****************************************************************************
_START_:                     ; Tell linker entry point

; ======== Display current values ========
Display_variables:
%ifdef DEBUG
    ; Instructor Question 1: What are we doing here?
    Print_Var W_CHAR, W
    Print_Var X_CHAR, X
    Print_Var Y_CHAR, Y
    Print_Var Z_CHAR, Z
    Print_Var N_CHAR, N
    CALL_Our_Print CR, 1
    CALL_Our_Print LF, 1
%endif

; ======== Calculate W * Y ========
Multiply_WY:
    mov eax, 0            ; Initialize eax prior to using it
    mov ebx, 0            ; Initialize ebx prior to using it
    mov esi, W            ; Move the address of W into esi
    mov eax, [esi]        ; Move the value at W into eax
    mov esi, Y            ; Move the address of X into esi
    mov ebx, [esi]        ; Move the value at Y into ebx
    imul eax, ebx         ; Multiply: X * Y
    mov [RESULT], eax     ; Store the result

Display_WY_product:
    Print_Msg MSG_A0, LEN_A0, RESULT

; ======== Calculate X << N ========
Shift_W_left_by_N:
    mov eax, 0            ; Initialize eax prior to using it
    mov ecx, 0            ; Initialize ecx prior to using it
    mov esi, W            ; Move the address of W into esi
    mov eax, [esi]        ; Move the value at W into eax
    mov esi, N            ; Move the address of N into esi 
    mov ecx, [esi]        ; Move the value at N into cl register
    shl eax, cl           ; Shift W << N
    mov [RESULT], eax     ; Store the result

Display_W_left_shift:
    Print_Msg MSG_A1, LEN_A1, RESULT

    ; Instructor Question 1: Why is (W * Y) equal to (W << N) ?

; ======== Calculate Z / Y ========
Divide_ZY:
    mov edx, 0            ; Zero-out edx because idiv treats it as high bits above eax!
    mov eax, 0            ; Initialize eax prior to using it
    mov ecx, 0            ; Initialize ecx prior to using it
    mov esi, Z            ; Move the address of Z into esi
    mov eax, [esi]        ; Move the value at Z into eax
    mov esi, Y            ; Move the address of Y into esi
    mov ecx, [esi]        ; Move the value at Y into ecx
    div ecx               ; Divide: Z / Y
    mov [RESULT], eax     ; Store the result

Display_ZY_quotient:
    Print_Msg MSG_B0, LEN_B0, RESULT

; ======== Calculate N >> Z ========
Shift_Z_right_by_N:
    mov eax, 0            ; Initialize ebx prior to using it
    mov ecx, 0            ; Initialize ecx prior to using it
    mov esi, Z            ; Move the address of Z into esi
    mov eax, [esi]        ; Move the value at Z into eax
    mov esi, N            ; Move the address of N into esi
    mov ecx, [esi]        ; Move the value at N into ecx register
    shr al, cl            ; Shift: N >> Z
    mov [RESULT], eax     ; Store the result

Display_Z_right_shift:
    Print_Msg MSG_B1, LEN_B1, RESULT
    ; Instructor Question 2: Why is (Z / Y) equal to (N >> Z) ?

_EXIT_:
    Exit_Program

; END OF MAIN()

; *****************************************************************************
; PROC:    Byte_to_String(BYTE, STRING, LENGTH)
; PURPOSE: Convert byte integer into its ASCII (printable) equivalent.
; INPUT:   BYTE   [edi] :: Byte to convert to string
;          STRING [esi] :: Address of the string
;          LENGTH [edx] :: Length of the string
; OUTPUT:  eax :: Returns 0 if successful, else -1.  If successful, then the 
;                 Contents of the given string [ecx] contains the convert integer.
; USES:    eax :: Contains high/low-order nibble of byte to convert
; NOTES:   
; *****************************************************************************
_Byte_to_String:           ; Start of procedure definition
    push eax               ; Save off the current contents of the regs
    push ebx
    push ecx

    cmp  edx, 0x3          ; Make sure that given string is large enough
    jl   Bad_B2S           ; It's not, so do not perform the operation

    mov  eax, edi          ; Byte to convert to string
    mov  ecx, esi          ; Get the address of the string buffer
    and  eax, 0x000000F0   ; Mask off the high-order nibble
    shr  eax, 4            ; Push the high-order nibble to the low-order nibble

    ; Instructor Question 3: Why do we do this?
    add  eax, '0'          ;
    mov  [ecx], eax        ; Write the converted high-order nibble to the string
    add  ecx, 1            ; Move the pointer to the next character position in the string

    mov  eax, edi          ; Byte to convert to string
    and  eax, 0x0000000F   ; Mask off the low-order nibble
    add  eax, '0'          ;
    mov  [ecx], eax        ; Write the converted low-order nibble to the string
    add  ecx, 1            ; Move the pointer to the next character position in the string

    mov  eax, 0            ; Move a ZERO into eax letting the caller know that we were SUCCESSFUL
    mov  [ecx], eax        ; Put a trailing zero in the string.
    jmp  Done_B2S          ; We're done -- restore the registers used and return

Bad_B2S:
    mov eax, -1            ; Move a ZERO into eax letting the caller know that we were unSUCCESSFUL

Done_B2S:
    pop eax                ; Restore the previous contents of the regs
    pop ebx
    pop ecx

    ret
; End of procedure definition

; *****************************************************************************
; PROC:    Our_Print(STRING, LENGTH)
; PURPOSE: Implements the system write call.
; INPUT:   STRING [edi] :: Address of the string to print
;          LENGTH [esi] :: Length of the string
; OUTPUT:  eax :: Returns 0 if successful, else -1.  If successful, then the 
;                 Contents of the given string [ecx] contains the convert integer.
; USES:    eax :: Contains high/low-order nibble of byte to convert
; NOTES:   
; *****************************************************************************
_Our_Print:               ; Start of procedure definition
    push eax              ; Save off the current contents of the regs
    push ebx
    push ecx
    push edx

%ifdef _WINDOWS_
    ; hStdOut = GetstdHandle( STD_OUTPUT_HANDLE)
    push    -11
    call    _GetStdHandle@4
    mov     ebx, eax    

    ; WriteFile( hstdOut, message, length(message), &bytes, 0);
    push    0
    lea     eax, [ebp-4]
    push    eax
    push    (message_end - message)
    push    message
    push    ebx
    call    _WriteFile@20
%else
    ; Instructor Question 4: What are we doing here?
    mov eax, 4            ; System call number (sys_write)
    mov ebx, 1            ; File descriptor (stdout)
    mov ecx, edi          ; Address of the message to write
    mov edx, esi          ; Message length
    int 0x80              ; Call the kernel
%endif

Done_Our_Print:
    pop eax               ; Restore the previous contents of the regs
    pop ebx
    pop ecx
    pop edx
    ret
; End of procedure definition
assembly
x86
nasm
asked on Stack Overflow Feb 3, 2019 by Joseph Hoffman • edited Feb 3, 2019 by Paul R

0 Answers

Nobody has answered this question yet.


User contributions licensed under CC BY-SA 3.0