Я пытаюсь понять, как изменить следующий код, и мне также нужно изменить код. Я не знаю, как это сделать, поскольку мы не затрагивали эту тему на моих занятиях. Мне действительно не помешало бы некоторое объяснение того, как изменить код, чтобы он соответствовал требованиям. Я предпринял попытки изменить вычисление W на X и Z на 0x20. Это было неправильно. Пожалуйста, помогите мне с этим.
Измените код так, чтобы если Z = 0x20, то чему должно быть равно N, чтобы (X * Y) = (X << N) и (Z / Y) = (N >> Z).
Код:
%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
Везде, где написано N>>Z, вместо этого следует говорить Z>>N. В некоторых местах в комментариях это правильно, и Z>>N - это то, что на самом деле делает код. Обратите внимание, что имя функции — Shift_Z_right_by_N, так что это явно то, что задумано.
Итак, немного подробнее о том, что мне нужно. В настоящее время, когда код скомпилирован, результаты следующие: W * Y = 0x10, W << N = 0x10, Z / Y = 0x02 и Z >> N = 0x02. Его необходимо изменить, чтобы отображать X * Y = значение, X << N = то же значение, что и X * Y, Z/Y = значение (должно быть 0x04, так как Z теперь 0x20). и N << Z должны равняться одному и тому же значению. Я примерно понял, как это сделать, заменив W на X и изменив Z с 0x00000010 на 0x20. Тем не менее, математика верна, но я не знаю, как изменить метки при печати.
mov eax, 0 ; Initialize eax prior to using it Это чистый шум/помехи. mov eax, [esi] перезаписывает полный регистр EAX без логической или ложной зависимости от старого значения регистра. Кроме того, используйте mov eax, [Z] вместо того, чтобы тратить инструкции на размещение адреса в регистре, особенно если вы не собираетесь использовать его повторно. Основная математическая часть вашего кода, вероятно, примерно в 5 раз длиннее, чем необходимо, и, следовательно, более сложна и трудна для понимания, чем если бы вы просто хранили все в регистрах.
Для (N >> Z) с Z=0x20 x86 маскирует счетчик сдвига по модулю 32. Таким образом, это сдвиг 0, если вы используете shr eax, cl, оставляя EAX без изменений. Это то, что они имели в виду, или они имели в виду, что это должно сдвинуть все биты? Вы используете 32-битные загрузки из N, но затем используете только al, поэтому вы может смещаете все биты с shr al, cl с cl=0x10 & 0x1f = 0x10, но не с cl = 0x20 & 0x1f = 0. felixcloutier.com/x86/sal:sar:shl:shr (маска подсчета фиксирована на 0x1f для узких сдвигов, поэтому 16- и 8-битные сдвиги могут сдвинуть все биты.) О, \@prl был прав, Z>>N имеет смысл.





Так это задача по математике?