Hi Devoum,
I'm a terrible teacher. I found this out when my daughter was small, and I tried to help her with schoolwork. I'd explain something, and if she didn't understand it, I was stuck. I explained it, what else? I'm trying to get better at it.
I sympathize with your desire to "understand everything". This might be a time, temporarily, to "just shut up and do it". It isn't worth getting too "hung up" on this one issue. Better to understand what you're doing, and why, though!
I began to suspect, when you said, "$ is 1 in this case, right? And message is 12 obviously." that you understand '$' alright. It's other things that Nasm is doing - or not doing - for us that is leading to the confusion. My little "example" was supposed to illustrate that, but I guess I didn't explain what it was supposed to illustrate! I probably confused the issue by using two "sections", too. Lemme try again...
message db "hello world"
When Nasm sees "message", it knows it isn't an instruction or register name - must be a variable name. Nasm does not emit anything, at this point. It "remembers" the location of "message" by making an entry in its "symbol table". This information may be emitted into the header of a linkable object file (later), but nothing goes into the "code" (and data) part of the program. This value would be zero, if it were the first thing in the file - generally non-zero (in my example, it's 0x18). '$', if we had used it at this point, would have the same value.
When Nasm sees "db", it's a "pseudo-instruction". This tells Nasm "just emit these bytes, don't try to 'assemble' it" (that's why it's "pseudo", I guess). So Nasm puts 'h', 'e', 'l', 'l', 'o', ' ', 'w', 'o', 'r', 'l', 'd' (the ascii codes) into your file, counting "where are we" as it goes. Now...
msglen equ $ - message
None of this emits anything. "msglen", like "message" itself, is just a symbol. The equ" defines the value of "msglen" to be "where we are now" (0, or whatever "message" was, plus what we just emitted) minus "where we started". This "where we are now" minus "where we started" is (obviously?) the length of what we emitted. This too is "remembered". The value stored for "message" is the location, and the value stored for "msglen" is whatever we defined with "equ", so they're a "different kind of symbol", but all we've emitted so far - which is what '$' counts - is "hello world".
Now, when we go to "use" these symbols...
mov ecx, messsage
mov edx, msglen
or perhaps,
push msglen
push message
Nasm sees that "mov" or "push" is an instruction, so it emits the appropriate byte(s). (some instructions encode into a single byte, some require multiple bytes) Then the word "message" or "msglen" is replaced by the value we "remembered". All the CPU ever sees is a bunch of numbers. I mention this because another poster wanted to modify the label names at runtime - this isn't going to work.
Nasm has counted the "opcode plus operand" bytes that it has emitted, so '$' at this point would include them. In the "equ", '$' doesn't emit anything, but if we used it as an operand, it would:
mov eax, $
This will emit the opcode for "mov", and replace the '$' with its current value (the location at the beginning of the line - the "mov" opcode would not be included). If we used '$' again...
mov ebx, $
... Nasm would have counted the (5) bytes emitted by "mov eax, $", but nothing from the "mov ebx, $" yet. Only after Nasm has figured out how many bytes "mov ebx, $" is going to emit can it increment '$'. It isn't called '$' internally - I don't know what it's called, offhand. We can drag the source code in here and interrogate it, if that'll help...
That's about the same thing as Cyrill said, but differently. If neither of us can explain it "right" (for you), we'll get someone else in here to take a crack at it. The concept is not "too difficult" for you to understand, trust me!
In doing some research on a question about debugging, I came across the idea that "Why doesn't my program work?" is because "Something you believe to be true, is not true." Debugging is the process of figuring out what you believe to be true, at each stage of your program, and verifying that it really is true. The more you "understand everything" and the less you "just do it", the more successful you'll be, I figure. Don't let it hang you up forever, though. You can "just do it and move on" and come back to it later, if need be.
(By the way, this is not "off-topic" in the slightest. It's a good question!)
As Betov used to say, "Courage!"
Best,
Frank