Рекурсия в сборке? - PullRequest
       19

Рекурсия в сборке?

3 голосов
/ 05 июня 2010

Я пытаюсь лучше понять сборку, и меня немного смущает вопрос о том, как рекурсивно вызывать функции, когда мне приходится иметь дело с регистрами, выталкиванием / нажатием и т. Д.

Я встраиваю сборку x86 в C ++. Здесь я пытаюсь создать метод, который с помощью массива целых чисел создаст связанный список, содержащий эти целые числа, в порядке их появления в массиве.

Я делаю это, вызывая рекурсивную функцию:

insertElem (struct elem *head, struct elem *newElem, int data) 

-головка: руководитель списка

-data: номер, который будет вставлен в конец списка

-newElem: указывает место в памяти, где я буду хранить новый элемент (поле данных)

Моя проблема в том, что я продолжаю перезаписывать регистры вместо типичного связанного списка. Например, если я передам ему массив {2,3,1,8,3,9}, мой связанный список вернет первый элемент (заголовок) и только последний элемент, потому что элементы продолжают перезаписывать друг друга после того, как заголовок больше не имеет значения.

Итак, мой связанный список выглядит примерно так: 2 -> 9 вместо 2 -> 3 -> 1 -> 8 -> 3 -> 9

Мне кажется, что я не понимаю, как организовывать и обрабатывать регистры. newElem находится в EBX и продолжает переписываться. Заранее спасибо!

Ответы [ 3 ]

7 голосов
/ 05 июня 2010

Сложно дать ответ, не увидев свой асм-код. Сначала я подумал, что для работы со связанными списками не нужны рекурсивные функции.

В любом случае, общий способ сохранения регистров при вызове функций - это поместить их в стек и затем вытолкнуть их:

;
; ebx = current element
;
TraverseList:

   ; If this is the end of the list we can skip the recursive invocation
   cmp [ebx+next], 0
   je NoNextElement

   push ebx               ; Save current element (ebx) on stack
     mov ebx, [ebx+next]  ; Put next element in ebx
     call TraverseList    ; Recursive invocation
   pop ebx                ; Restore current element (ebx) from stack

NoNextElement:

   ; Do stuff with the current element (ebx)
   ...
   ret
2 голосов
/ 05 июня 2010

Наиболее общий ответ на любой вопрос, связанный с ассемблером: gcc -S. Если у вас есть какие-либо сомнения, просто посмотрите, как приличный компилятор C переводит это в код более низкого уровня.

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

0 голосов
/ 06 июня 2010

Попробуйте что-то вроде этого в качестве своего кода asm

__asm{
        mov ebx, dword ptr[esp+4] //head
        mov ecx, dword ptr[esp+8] //newElem
        mov edx, dword ptr[esp+12] // data

    cmp [ebx+4], 0
    je NO_NEXT_ELEMENT

    mov ebx, [ebx+4]
    mov ecx, [ecx+4]

    push edx
    push ecx
    push ebx
    call insertElem
    pop ebx
    pop ecx
    pop edx


NO_NEXT_ELEMENT:


    mov dword ptr[ebx+4], ecx 
    mov dword ptr[ecx], edx
    mov [ecx+4], 0

    ret
}

РЕДАКТИРОВАТЬ: Просто запустил это и понял, что это не работает. Это дает нарушение прав доступа чтения / записи местоположения ошибок. Но, надеюсь, это даст вам начало, может быть, кто-то может немного его почистить.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...