I am only start in FASM and just now I try understand how works some of the macros from FASM pack.
This is two small macros cutted from IMPORT.INC and pared-down:
macro L name
if ~ name#.needed
display "name NO needed"
display "name YES to needed"
end if

macro I name
;;;sser db 222
if $ > name
name#.needed = 0 ;false
name#.needed = 1 ;true
end if

L kop
I kop
Yes, it's work fine and display right message according to have the string 'sser db 222' been comment or not.
But I can't understand such thing: if L-macro execute BEFORE and I-macro AFTER how L-macro can
know value of 'kop.needed'? Does it mean FASM opened I before L though in text all vice versa?
And second question: who can explain me how RVA operator work? With example, if possible.

Thanks in advance!
Posted on 2003-02-04 10:25:30 by Smarty
Hi to all!!

I've almost finish my own asm compiler but I still have some troubles with labels...
For example if I've:

jmp ciao
ciao: ...

how can I solve label 'ciao' relative address when I compile jmp???
I had try to ignore jmp instruction until I found 'ciao' relative address but in this case I don't know 'jmp ciao' opcode length and then all successive relative addresses are wrong! (I increment relative address by instruction length every time I compile an instruction)

Can someone help me??? ie. Privalov:grin:

Posted on 2003-02-05 11:13:22 by Nikso
Originally posted by Nikso
I've almost finish my own asm compiler but I still have some troubles with labels...

You've almost finished your own assembler but you don't know how to resolve a relative address between the jump and the target destination? Doesn't look like it's 'almost finished' :confused:

Anyway, there are multiple versions of jmp (jmp (E9) and jmps/jump short (E8)). The first takes 5 bytes, the second only two. So you need to take that into account as well. As for the solution to your problem, it depends on how your assembler is structured. You can determine the relative offset of the jump and the target by adding the sizes of the instructions in between. But it's likely that there are instructions there with multiple forms too so you probably need some more passes to figure everything out. When the form of the instructions in between is fixed, you're done. If not, you first need to find out the sizes of the instructions in between, and adjust the jump later.

I increment relative address by instruction length every time I compile an instruction

This would work fine if each instruction has a unique form but often there are shorter forms of the same instruction for small relative addresses or low values. The form of an instruction depends on the possible forms for that specific instance of the instruction, and often on the form of other instructions (in the case of a jump over other instructions with multiple forms).


edit: did some moderator merge the thread with some other by accident? It now has Smarty's post as the first one :confused:
Posted on 2003-02-05 11:32:14 by Thomas
I've attached Nikso's thread here because my answer is common.

FASM is a multi-pass assembler and therefore allows many kinds of forward references. You can access a label before it's defined and check whether it's used before it's actually used, because when FASM is not sure it can give you the right result on the first pass, it does the second, when all values of labels are already known. But it may happen that something (eg. opcode size) was predicted wrong and therefore some labels have changed. In such case FASM does one more pass, on so on.

FASM determines that the one more pass is needed if one of the following situations happens:

    [*]Undefined symbols: when some symbol is undefined, second pass is done to determine whether it's forward-referenced, this happens only in first pass. In later passes it causes an error, but when FASM needs to do still one more pass, it ignores such error and does the next pass anyway.
    [*]Changed labels: some labels (or forward-referenced contants, the numerical constants that are defined only once in source can be forward-referenced) have been defined with different values than in previous pass. But if label wasn't actually used, it doesn't cause the next pass.
    [*]"Used" misprediction: when "used" operator is given a symbol that has not been used in current pass, it has to predict whether it'll be used or not, if it was used in previous pass, it's predicted to be used in next, otherwise it's predicted to be not used. If after finishing the pass FASM determines that some of such predictions were wrong, it does one more pass.
    [*]Lost definitions: when some label was defined in previous pass but not in the current (it's checked after finishing the whole pass, like the "used" mispredictions), one more pass is done. But if such label wasn't used at all in the current pass, this case is ignored.
    [*]Addresses changed due to formatter's work: after assembler has finished all its passes it may happen that formatter forces it to do once more, when some structures in header have changed their size (eg. there were more sections in PE defined than default 4K header can hold) and therefore all addresses have to move. This is a rare case.

    I will explain it everything in details in my "Guide to FASM internals", that I've promised to write (I swear, will make it soon...), including the details of how it's done and what kind of data structures is involved.
Posted on 2003-02-05 11:53:25 by Tomasz Grysztar
thanks to had clear my ideas!
You are the best community in the web!!:alright:

Posted on 2003-02-06 09:59:05 by Nikso
Great explanation!!! Thanks,Mr.Privalov. :)
I am looking forward to promised "Guid..."
Posted on 2003-02-06 14:10:42 by Smarty