目前我获得了一个链接列表,只有一个下一个指针但不是一个prev指针。从名单上走下来,相对容易。
movl NEXT(%ebx), %ebx # ebx is the current node
但是,当尝试从头到尾逐个删除列表时,我似乎无法制定解决方案。目前,我已经想到了1.保持上一次保存。
subl $4, %esp # reserve space to put in the prev pointer
movl %ebx, -4(%ebp) # store current pointer into prev pointer
movl NEXT(%ebx), %ebx # walk down the list
然后在
movl -4(%ebp), %edx # putting the prev pointer into edx
pushl (%edx) # two pushes to give parameters for func call
pushl (%ebx)
call remove_func
并在删除功能
中 movl 12(%ebp), %edx # store prev pointer to edx
movl 8(%ebp), %ebx # store current pointer aka node to be deleted at ebx
movl NEXT(%ebx), %eax # temporarily store curr->next to eax
movl %eax, NEXT(%edx) # prev->next=eax
movl $0, (%ebx) # curr=NULL
pushl %ebx # pushes params for func call
call free_node
你有一般的想法,我在这里尝试做什么。当您正在使用NEXT走下列表时,基本上将prev指针推到堆栈上。但是,通过这种实现,我仍然不确定它是否会起作用,因为我不知道它是否可以递归到顶部或者它会在第一次删除时停止。我的第二种方法是将prev指针存储在寄存器中而不会压入堆栈。说%edi
movl %ebx,%edi
movl NEXT(%ebx), %ebx
call remove_func
感谢您的帮助。很抱歉这个问题很长。 编辑:列表需要以相反的顺序删除。这是我试图实施的经典导弹指挥游戏。
答案 0 :(得分:1)
我不确定你遇到了什么问题,但我有一个有趣的想法来实现这个,它利用调用堆栈作为堆栈数据结构,同时向前遍历,并使用它进行arg传递回来的路上,无需在任何地方复制任何东西。
假设:在释放列表节点时不需要修改它们。这是一个free-everything函数,所以我们可以设置HEAD = NULL,因此链接列表的任何其他用户(例如在信号处理程序或其他线程中)将看到它为空,而我们仍在通过释放它们的节点。
# gas AT&T syntax, x86 32-bit, SysV calling convention
# untested
.globl list_free
list_free: # void list_free(struct node **phead)
mov 4(%esp), %eax # phead: node**
mov (%eax), %edx # p=head: node* (points to the first node)
# p (pointer to old head) in %edx
test %edx,%edx # check that head wasn't NULL to start
jz .Llist_was_empty # free(NULL) is safe, but we would also try to dereference
xor %ecx,%ecx # count = 0
mov %ecx, (%eax) # *phead=NULL (chop the list off at the head)
# loop over the list, pushing the address of each node on the stack
.Lforward_loop # do {
push %edx # push p
mov NEXT(%edx), %edx # p=p->next
inc %ecx # count++
test %edx,%edx
jnz .Lforward_loop # } while(p)
# walk back up the stack, using each pointer as an arg to free()
.Lbackward_loop # do {
call free # free takes one arg, which is already on the stack
add $4, %esp # or just pop %edx, which will run faster on Intel CPUs: doesn't force a stack-sync uop
dec %ecx # } while(--count);
jnz .Lbackward_loop
.Llist_was_empty:
ret
我故意没有“保持简单”或其他任何东西,因为IDK实际上需要什么样的帮助。在考虑了你的问题之后,我基本上是为了自己的娱乐而写的。指令越少,理解的越少。 :)
我只需要三个寄存器,所以我没有保存/恢复任何寄存器。而且我不需要任何本地人,所以我也没有用ebp制作堆栈帧。
在64位代码中(AMD64 SysV调用约定,其中第一个arg进入%rdi),向后循环将是:
.Lbackward_loop # do {
pop %rdi
call free # free(p)
dec %ecx # } while(--count);
jnz .Lbackward_loop