Сборка JMP и RET - PullRequest
       2

Сборка JMP и RET

0 голосов
/ 16 марта 2020

Я новичок в Assembly.
И у меня есть этот код

section .data                   ; we define (global) initialized variables in .data section
    an: dd 0                    ; an is a local variable of size double-word, we use it to count the string characters

section .text                   ; we write code in .text section
    global do_Str               ; 'global' directive causes the function do_Str(...) to appear in global scope

section .text                   ; we write code in .text section
    global do_Str               ; 'global' directive causes the function do_Str(...) to appear in global scope

do_Str:                         ; do_Str function definition - functions are defined as labels
    push ebp                    ; save Base Pointer (bp) original value
    mov ebp, esp                ; use Base Pointer to access stack contents (do_Str(...) activation frame)
    pushad                      ; push all signficant registers onto stack (backup registers values)
    mov ecx, dword [ebp+8]      ; get function argument on stack
                                ; now ecx register points to the input string
    yourCode:                   ; use label to build a loop for treating the input string characters
        cmp byte [ecx], ' '
        JE  updateAndCount
        inc ecx                 ; increment ecx value; now ecx points to the next character of the string
        cmp byte [ecx], 0       ; check if the next character (character = byte) is zero (i.e. null string termination)
        jnz yourCode            ; if not, keep looping until meet null termination character

    updateAndCount:
        mov byte [ecx], '_'
        inc dword[an]
        ret

    popad                       ; restore all previously used registers
    mov eax,[an]                ; return an (returned values are in eax)
    mov esp, ebp                ; free function activation frame
    pop ebp                     ; restore Base Pointer previous value (to returnt to the activation frame of main(...))
    ret                         ; returns from do_Str(...) function

, но когда я его запускаю (у меня есть c код, вызывающий его), я получаю эту ошибку:

Ошибка сегментации (ядро сброшено)

Я знаю, что это как-то связано с возвратом из updateAndCount, но я не уверен, как это исправить.

1 Ответ

1 голос
/ 16 марта 2020

Расширение из моих комментариев с примером.

Фрагмент, начинающийся с метки updateAndCount, не должен заканчиваться ret, он должен прыгать (или проваливаться) туда, где вы хотите, чтобы ваш l oop для продолжения. Однако это не единственная ошибка потока управления. После jnz yourCode вы, вероятно, захотите безусловный переход к эпилогу функции (который начинается с popad). Или переместите эпилог вокруг, чтобы следовать непосредственно за jnz yourCode, а затем позвольте ему провалиться, если jnz не прыгает.

Кроме того, вы не инициализировали переменную an в функции, чтобы она Действуйте как переменная stati c в C, то есть если ваша функция вызывается повторно an будет продолжать увеличиваться и не будет сбрасываться при последующем вызове вашей функции. Это может быть преднамеренным, но вы не указали, какое поведение предполагается. Кроме того, yourCode является исключительно неописательным ярлыком. Я бы порекомендовал заменить его на .loop - ведущая точка делает его локальной меткой для NASM . Имя должно описывать намерение этой цели перехода.

Вот пример, исправляющий поток управления, инициализирующий переменную an и изменяющий метки на описательные и локальные метки. Я не буду ни оптимизировать программу, ни делать ее поточно-ориентированной (что не связано с глобальной переменной).

section .data                   ; we define (global) initialized variables in .data section
    an: dd 0                    ; an is a local variable of size double-word, we use it to count the string characters

section .text                   ; we write code in .text section
    global do_Str               ; 'global' directive causes the function do_Str(...) to appear in global scope

do_Str:                         ; do_Str function definition - functions are defined as labels
    push ebp                    ; save Base Pointer (bp) original value
    mov ebp, esp                ; use Base Pointer to access stack contents (do_Str(...) activation frame)
    pushad                      ; push all signficant registers onto stack (backup registers values)
    mov dword [an], 0

;;; continues in the next code block
;;; all the code blocks in this answer combine to one function with one loop

При нулевой инициализации переменная обнуляется. (Я бы использовал and с нулем лично, что немного короче, чем mov с нулевым непосредственным числом. Но для ясности мы будем использовать mov.)

    mov ecx, dword [ebp+8]      ; get function argument on stack
                                ; now ecx register points to the input string
    jmp .first

Этот безусловный переход исправляет другую ошибку logi c. Если самый первый байт в строке является байтом NUL, мы, скорее всего, должны соблюдать его, а не продолжать обрабатывать то, что следует после него.

.loop:                          ; use label to build a loop for treating the input string characters
    cmp byte [ecx], ' '
    jne .do_not_updateAndCount

Я инвертировал код условия перехода. Теперь он скачет, если мы не хотим запускать часть .updateAndCount.

.updateAndCount:
    mov byte [ecx], '_'
    inc dword [an]

Я сохранил ваш ярлык (теперь локальный с лидирующей точкой), хотя на него нигде нет ссылок. Однако он может служить комментарием к тому, что должен делать этот блок.

Важно, что поток управления проваливается после окончания блока .updateAndCount здесь. Эквивалентно, вы можете добавить безусловный jmp .next в конце, чтобы прыгнуть (назад) в l oop. Если вы переместились вокруг блока .updateAndCount (например, за эпилогом ret), тогда потребуется jmp .next.

.do_not_updateAndCount:

.next:
    inc ecx                     ; increment ecx value; now ecx points to the next character of the string
.first:
    cmp byte [ecx], 0           ; check if the next character (character = byte) is zero (i.e. null string termination)
    jnz .loop                   ; if not, keep looping until meet null termination character

    popad                       ; restore all previously used registers
    mov eax, [an]               ; return an (returned values are in eax)
    mov esp, ebp                ; free function activation frame
    pop ebp                     ; restore Base Pointer previous value (to returnt to the activation frame of main(...))
    ret                         ; returns from do_Str(...) function
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...