#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
функция указывает неправильный порядок) — это меняет местами значения в регистрах.