Reputation: 605
The following is a linked list Assembly program found in Kip Irvine's Assembly Language x86 book. In main, a loop traverses the list and displays all the node values. Rather than using a fixed counter for the loop, the program checks for the null pointer in the tail node and stops looping when it is found. My question is the following:
(a) Can someone explain < Counter, ($ + Counter * SIZEOF ListNode) >? How does it work and what does it mean?
(b) Can someone explain (ListNode PTR [esi]).NextPtr? What does that mean?
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
Upvotes: 3
Views: 4128
Reputation: 244812
Can someone explain
(ListNode PTR [esi]).NextPtr
? What does that mean?
It means that there is a pointer to the beginning of a ListNode
structure in the ESI
register. It dereferences that pointer, and evaluates to the NextPtr
field.
It is basically like if you had the following in C:
ListNode* esi;
...
return esi->NextPtr;
Can someone explain
< Counter, ($ + Counter * SIZEOF ListNode) >
? How does it work and what does it mean?
No, honestly I cannot. Well, sorry, this turned out to be a pretty crappy answer. :-)
I can tell you how I would figure it out, though. First I'd go to the documentation for MASM and see if I could spot anything that looked relevant. I would find (or, actually, I already know) that $
means the current value of the location counter, and that SIZEOF
is an operator that returns the number of bytes in the specified type.
So this gobbledygook looks like it multiplies the value of Counter
by the size of the ListNode
structure, and then adds the current value of the location counter.
But I still have no idea what the angle brackets mean. So I'd try a Google search, something like "angle brackets MASM". I get this question, which isn't very useful, since it doesn't have an answer. In the MASM32 help file, I see:
Treats as a single literal string. Angle brackets are often used in macro calls and with the FOR directive to ensure that values in a parameter list are treated as a single parameter . . . The assembler removes one set of angle brackets each time it inserts an argument into a macro expansion.
but that doesn't really help me too much, either.
Where to go from here? Well, assuming that the code works, I'd assemble it and ask MASM to produce a listing file (/Fl
). I would then inspect this listing file to see what effect this actually had on the generated code.
Update: My dedication paid off, and I came across an old manual for MASM 6.1 online. I wasn't able to find this in Microsoft's online documentation, but in this manual, it clearly says on pg. 98:
Defining Structure and Union Variables
Once you have declared a structure or union type, you can define variables of that type. For each variable defined, memory is allocated in the current segment in the format declared by the type. The syntax for defining a structure or union variable is:
[[name]] typename < [[initializer [[,initializer]]...]] > [[name]] typename { [[initializer [[,initializer]]...]] } [[name]] typename constant DUP ({ [[initializer [[,initializer]]...]] })
The name is the label assigned to the variable. If you do not provide a name, the assembler allocates space for the variable but does not give it a symbolic name. The typename is the name of a previously declared structure or union type.
You can give an initializer for each field. Each initializer must correspond in type with the field defined in the type declaration. For unions, the type of the initializer must be the same as the type for the first field. An initialization list can also use the
DUP
operator.
So it looks like this declares an unnamed variable of type ListNode
, and the stuff in brackets is the initializer for the ListNode
struct, sort of like the C code:
struct ListNode { ... } = { Counter, ($ + Counter * sizeof(ListNode)) };
That fits with the feeble attempt at an explanatory comment:
; struct variables Counter, and ($+Counter*SIZEOF ListNode) being declared
since it's initializing the first two fields of the ListNode
struct, NodeData
and NextPtr
, with those values.
Upvotes: 2