External Dependencies in Assemblers

vid, 2007-08-15Revision: 1.0

Each assembler handles external dependencies on its own. I have investigated various assemblers and made interesting discussion.

Background

I am developing FASMLIB, a general purpose library for assembly language. It supports multiple 32bit x86 assemblers, namely FASM, MASM and NASM/YASM. GAS support is on the way (and will be extremely easy).

I ran into problems creating headers for these assemblers. The library is provided in object form, and linked with other objects that use it. Headers declare all the symbols that the library provides.

But not all symbols should be listed as dependencies for resulting object file. Only symbols that are actually used should be dependencies. If all symbols are declared as dependencies, the entire library is linked, not just the needed parts.

NASM

In NASM, you declare external dependencies using %extern. The problem is that every symbol declared as %extern always produces an external dependency in the resulting object file. There is no way to declare external dependency on symbol only if symbol is used.

The only way "solve" this problem is enforcing the use of macro on the user of the library. This macro itself declares symbols as external, and symbols cannot be used with anything other than the macro.

Same applies to YASM emulating NASM syntax.

GNU Assembler (gas)

GAS previously had "extern" functioning similar to NASM. My quess is that the authors realized this problem, and changed its behavior, but I am just speculating.

Currently, any undefined symbol that occurs in source is automatically declared as external. This means there are no extern declarations needed in header, but it also means that typos in names are not checked during compilation. In the case of typos, you get confusing error messages during linking, or even bad executable if you are unlucky.

However, gas is more a back-end assembler than "human" assembler so such behavior may be appropriate from this point of view.

MASM

In MASM, you declare external procedure using the PROTO statement, and external data should be declared using EXTERNDEF. These produce dependency only when the symbol is actually used. This is fine for our purposes, and suits MASM's high-level style well.

For its users, MASM solves this problem properly.

FASM

In FASM you have the extrn directive that works just like the ones in MASM and NASM. It always creates dependency, even when symbol is not referenced in sources. But FASM also has operator used that checks whether the symbol is used anywhere in source. You can use it to conditionally compile extrn statement. So you declare every external symbol this way:

if used something
  extrn something
end if

Conclusion

I was amazed by the inability of NASM to provide enough facilities for such a basic thing as a library header properly.

Now here comes a problem: how to write headers for NASM?


Comments

Continue to discussion board.

You can contact the author using e-mail vid@x86asm.net.

Visit author's home page.


Revisions

2007-08-151.0First public versionvid

(dates format correspond to ISO 8601)