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
User contributions licensed under CC BY-SA 3.0