Руководство по модификации сборки NASM

Я пытаюсь понять, как изменить следующий код, и мне также нужно изменить код. Я не знаю, как это сделать, поскольку мы не затрагивали эту тему на моих занятиях. Мне действительно не помешало бы некоторое объяснение того, как изменить код, чтобы он соответствовал требованиям. Я предпринял попытки изменить вычисление 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

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

Dave Newton 03.02.2019 17:53

Везде, где написано N>>Z, вместо этого следует говорить Z>>N. В некоторых местах в комментариях это правильно, и Z>>N - это то, что на самом деле делает код. Обратите внимание, что имя функции — Shift_Z_right_by_N, так что это явно то, что задумано.

prl 03.02.2019 19:09

Итак, немного подробнее о том, что мне нужно. В настоящее время, когда код скомпилирован, результаты следующие: 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. Тем не менее, математика верна, но я не знаю, как изменить метки при печати.

Joseph Hoffman 03.02.2019 20:08
mov eax, 0 ; Initialize eax prior to using it Это чистый шум/помехи. mov eax, [esi] перезаписывает полный регистр EAX без логической или ложной зависимости от старого значения регистра. Кроме того, используйте mov eax, [Z] вместо того, чтобы тратить инструкции на размещение адреса в регистре, особенно если вы не собираетесь использовать его повторно. Основная математическая часть вашего кода, вероятно, примерно в 5 раз длиннее, чем необходимо, и, следовательно, более сложна и трудна для понимания, чем если бы вы просто хранили все в регистрах.
Peter Cordes 04.02.2019 00:18

Для (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 имеет смысл.

Peter Cordes 04.02.2019 00:25
Стоит ли изучать PHP в 2026-2027 годах?
Стоит ли изучать PHP в 2026-2027 годах?
Привет всем, сегодня я хочу высказать свои соображения по поводу вопроса, который я уже много раз получал в своем сообществе: "Стоит ли изучать PHP в...
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
В JavaScript одним из самых запутанных понятий является поведение ключевого слова "this" в стрелочной и обычной функциях.
Приемы CSS-макетирования - floats и Flexbox
Приемы CSS-макетирования - floats и Flexbox
Здравствуйте, друзья-студенты! Готовы совершенствовать свои навыки веб-дизайна? Сегодня в нашем путешествии мы рассмотрим приемы CSS-верстки - в...
Тестирование функциональных ngrx-эффектов в Angular 16 с помощью Jest
В системе управления состояниями ngrx, совместимой с Angular 16, появились функциональные эффекты. Это здорово и делает код определенно легче для...
Концепция локализации и ее применение в приложениях React ⚡️
Концепция локализации и ее применение в приложениях React ⚡️
Локализация - это процесс адаптации приложения к различным языкам и культурным требованиям. Это позволяет пользователям получить опыт, соответствующий...
Пользовательский скаляр GraphQL
Пользовательский скаляр GraphQL
Листовые узлы системы типов GraphQL называются скалярами. Достигнув скалярного типа, невозможно спуститься дальше по иерархии типов. Скалярный тип...
0
5
707
0

Другие вопросы по теме