Сортировка связанного списка C на языке ASMx64

#c #assembly #linked-list #x86-64 #nasm

#c #сборка #связанный список #x86-64 #nasm

Вопрос:

Я пытаюсь создать функцию, которая сортирует связанный список C в сборке, но это не работает, я не вижу, как я могу решить эту проблему, я работаю над этим часами, если кто-нибудь может помочь, было бы неплохо. Итак, прототип функции, которую я пытаюсь создать,:

 void ft_list_sort(t_list **begin_list, int (*cmp)());
  

Связанный список, над которым я работаю, — это просто простой базовый список:

 typedef struct s_list {
    void            *data;
    struct s_list   *next;
} t_list;
  

Вот мой ассемблерный код для функции с комментариями:

 global ft_list_sort

section .text
ft_list_sort:
    mov r8,  [rdi]              ;put begin pointer in r8
    mov r10, rsi                ;put cmp function in r10

main_loop:
    cmp  r8,  0                 ;check if current list is null
    je   exit                   ;if null we are at the end of list so exit
    mov  r9,  [r8   8]          ;put current list -> next in r9
    push r9                     ;save the value in the stack
    jmp  sort_loop              ;jump to our second loop

main_loop_after:
    pop  r8                     ;current list = current list -> next
    jmp  main_loop

sort_loop:
    cmp  r9,  0                 ;check if loop list is null
    je   main_loop_after        ;if null we are at the end of list so jump back in main loop
    mov  rdi, [r8]              ;put current list data in rdi
    mov  rsi, [r9]              ;put loop list data in rsi
    call r10                    ;call cmp function
    cmp  rax, 0                 ;check the result
    ja   swap                   ;if above zero jump to swap

sort_loop_after:
    mov  rdx, [r9   8]
    mov  r9,  rdx               ;loop list = loop list -> next
    jmp  sort_loop              ;go back to begin of loop

swap:
    mov  rdx, rdi
    mov  rdi, rsi               ;swap rsi and rdi (current list data and loop list data)
    mov  rsi, rdx
    jmp  sort_loop_after        ;go back to the loop

exit:
    ret
  

И я запускаю функцию с этим основным:

 #include <stdio.h>
#include <stdlib.h> 
#include <string.h>
#include <errno.h>

typedef struct s_list 
    void            *data;
    struct s_list   *next;
} t_list;

void                ft_list_push_front(t_list **begin_list, void *data);
int                 ft_list_size(t_list *begin_list);
void                ft_list_sort(t_list **begin_list, int (*cmp)());

t_list *lstnew(void *data) {
    t_list *newlist = malloc(sizeof(t_list));

    if (!newlist)
        return (NULL);
    newlist->data = data;
    newlist->next = NULL;
    return (newlist);
}

void lst_disp(t_list *lst) {
    while (lst) {
        printf("%dn", (int)lst->data);
        lst = lst->next;
    }
}

void lst_clear(t_list **lst) {
    t_list *head = (*lst)->next;
    while (*lst) {
        free(*lst);
        *lst = head;
        if (head)
            head = head->next;
    }
}

int int_comp(void *n1, void* n2)
{
    return ((int)n1 - (int)n2);
}

int main(void) {
    t_list *list = lstnew((void*)1);
    ft_list_push_front(amp;list, (void*)10); //This function is to add a member to the list
    ft_list_push_front(amp;list, (void*)3);
    ft_list_push_front(amp;list, (void*)20);
    ft_list_push_front(amp;list, (void*)5);
    ft_list_push_front(amp;list, (void*)42);
    printf("beforen");
    lst_disp(list);
    printf("aftern");
    ft_list_sort(amp;list, amp;int_comp);
    lst_disp(list);
    lst_clear(amp;list);
    return (0);
}
  

Это не сбой, но функция ничего не делает.
Вывод:

 before
42
5
20
3
10
1
after
42
5
20
3
10
1
  

Я попытался напечатать значения (int)n1 - (int)n2 в своей int_comp функции, и это приводит к сбоям, поэтому я предполагаю, что что-то не так swap: со значениями регистров, но я не знаю, что, спасибо за помощь.
Для компиляции я использую makefile, потому что я компилирую его вместе с другими функциями как библиотеку.
итак, для того, чтобы только этот файл:

 nasm -f elf64 ft_list_sort.s
ar rcs libasm_bonus.a ft_list_sort.o
gcc main.c libasm_bonus.a
  

Если вы хотите увидеть makefile, я разместил весь свой проект на github.

Комментарии:

1. «Не работает» нам не помогает, это не техническая диагностика. Сбросьте это в свой отладчик и выполните шаг, чтобы увидеть, что не так.

2. Я нигде не вижу в вашей функции, которую вы фактически записываете в память, т. Е. Нет mov [xxx], yyy , Поэтому список в памяти, таким образом, вообще не изменяется. Вы swap перемещаетесь по некоторым регистрам, но фактически не затрагиваете структуру списка.

3. @Fayeure: Тогда изучение того, как это сделать, является приоритетом № 1. Это не сложно, но попытка сделать что-либо в сборке, не зная, как выполнить один шаг, сделает процесс разработки значительно медленнее и более разочаровывающим.

4. @Fayeure: Нет, это не так. Регистры содержат копии этих значений, а не ссылки на них, и манипулирование значениями в регистрах не оказывает никакого влияния на память. Если вы хотите, чтобы память изменилась, вам нужно сохранить, например, выполнив mov [r8], rdi после ввода желаемого нового значения rdi .

5. В качестве аналогии с C рассмотрим long rdi; long *r8; rdi = *r8; rdi = 17; print(*r8); . Это значение не будет установлено *r8 17 .

Ответ №1:

Как отмечает @NateEldridge, ваш ассемблерный код на самом деле никогда ничего не записывает в память.

Похоже, суть проблемы связана с этой частью:

 swap:
    mov  rdx, rdi
    mov  rdi, rsi               ;swap rsi and rdi (current list data and loop list data)
    mov  rsi, rdx
    jmp  sort_loop_after        ;go back to the loop
  

Вместо замены узлов списка в памяти (что вы, похоже, хотите сделать, поскольку вы вызываете это, когда cmp функция указывает неправильный порядок) — это меняет местами значения в регистрах.