以下是在Kip Irvine的汇编语言x86书中找到的汇编程序链接列表。在main中,循环遍历列表并显示所有节点值。程序没有在循环中使用固定的计数器,而是在尾节点中检查空指针,并在找到后停止循环。我的问题如下:
(a)有人可以解释
(b)有人可以解释(ListNode PTR [esi])。NextPtr吗?那是什么意思?INCLUDE Irvine32.inc
ListNode STRUCT
NodeData DWORD ?
NextPtr DWORD ?
ListNode ENDS
TotalNodeCount = 15
NULL = 0
Counter = 0
.data
putc macro ptr
push eax
mov al, ptr
call writechar
pop eax
endm
;to use:
;putc 'a'
LinkedList LABEL PTR ListNode
REPEAT TotalNodeCount
Counter = Counter + 1
ListNode <Counter, ($ + Counter * SIZEOF ListNode)>
;struct variables Counter, and ($+Counter*SIZEOF ListNode) being declared
;
ENDM
ListNode <0,0> ; tail node
.code
main PROC
mov esi,OFFSET LinkedList
; Display the integers in the NodeData fields.
NextNode:
; Check for the tail node.
putc 'a'; ->first node, then third node
mov eax,(ListNode PTR [esi]).NextPtr
cmp eax,NULL
je quit
; Display the node data.
putc 'b' ;->fourth node
mov eax,(ListNode PTR [esi]).NodeData
call WriteDec
call Crlf
; Get pointer to next node.
putc 'c' ;->first node
putc 'd' ;->second node
mov esi,(ListNode PTR [esi]).NextPtr
;references a struct using [esi]
jmp NextNode
quit:
exit
main ENDP
END main
最佳答案
有人可以解释(ListNode PTR [esi]).NextPtr
吗?那是什么意思?
这意味着在ListNode
寄存器中有一个指向ESI
结构开始的指针。它取消引用该指针,并求值为NextPtr
字段。
基本上就像您在C中具有以下内容:
ListNode* esi;
...
return esi->NextPtr;
有人可以解释
< Counter, ($ + Counter * SIZEOF ListNode) >
吗?它是如何工作的,它是什么意思?不,老实说我不能。好吧,对不起,这真是一个糟糕的答案。 :-)
不过,我可以告诉您如何解决。首先,我要去the documentation for MASM,看看是否可以发现任何看起来相关的东西。我会发现(或者,实际上,我已经知道)
$
表示the current value of the location counter,而SIZEOF
是an operator that returns the number of bytes in the specified type。因此,该混搭看起来像是将
Counter
的值乘以ListNode
结构的大小,然后将位置计数器的当前值相加。但是我仍然不知道尖括号的含义。因此,我尝试使用Google搜索,例如“尖括号MASM”。我得到this question,它不是很有用,因为它没有答案。在MASM32帮助文件中,我看到:
视为单个文字字符串。尖括号通常用于宏调用中,并与FOR指令一起使用,以确保将参数列表中的值视为单个参数。 。 。每次将参数插入宏扩展时,汇编器都会删除一组尖括号。
但这对我也没有太大帮助。
然后去哪儿?好吧,假设代码可以正常工作,我将其汇编并要求MASM生成列表文件(
/Fl
)。然后,我将检查该清单文件,以查看其实际上对生成的代码产生了什么影响。更新:我的奉献得到了回报,我遇到了an old manual for MASM 6.1 online。我无法在Microsoft的在线文档中找到它,但是在本手册中,它在pg上明确指出。 98:
定义结构和联合变量
声明结构或联合类型后,即可定义该类型的变量。对于定义的每个变量,将以类型声明的格式在当前段中分配内存。定义结构或联合变量的语法为:
[[name]] typename < [[initializer [[,initializer]]...]] >
[[name]] typename { [[initializer [[,initializer]]...]] }
[[name]] typename constant DUP ({ [[initializer [[,initializer]]...]] })
名称是分配给变量的标签。如果不提供名称,则汇编器会为变量分配空间,但不会给它提供符号名称。 typename是先前声明的结构或联合类型的名称。
您可以为每个字段指定一个初始化程序。每个初始化程序的类型必须与类型声明中定义的字段相对应。对于联合,初始化程序的类型必须与第一个字段的类型相同。初始化列表也可以使用
DUP
运算符。因此,它看起来像这样声明了一个
ListNode
类型的未命名变量,并且括号中的内容是ListNode
结构的初始化程序,有点像C代码:struct ListNode { ... } = { Counter, ($ + Counter * sizeof(ListNode)) };
这与试图做出解释性评论的微不足道的尝试相吻合:
; struct variables Counter, and ($+Counter*SIZEOF ListNode) being declared
因为它使用这些值初始化
ListNode
结构的前两个字段NodeData
和NextPtr
。