Google Groups no longer supports new Usenet posts or subscriptions. Historical content remains viewable.
Dismiss

NASM - VC++ Linking Problems

387 views
Skip to first unread message

Jentje Goslinga

unread,
Jan 16, 2008, 11:39:03 AM1/16/08
to
Hi all,

I want to develop some code to run on Win and Lunix so I
am trying out NASM but am having trouble communicating
globals in my NASM file to the VC++ linker.
It seems as if any globals which I declare are not exported,
for example:

cpu 586

global _myfunc

_myfunc:
...
ret

nasm -f win32 mymodule.asm -o mymodule.obj
(Assembles fine)

Linking using the VC++ linker elicits the following message
from the linker:
mymodule.obj : error LNK2001: unresolved external symbol
_myfunc.
Inspection of the object file using various disassembly
utilities does not reveal any trace of the exported name
_myfunc, notably not with NDISASM which also disassembles
the header! Shouldn't any global (public) names be visible in
the .obj file header?

Anyone have any ideas why my symbols are not exported?

By the way, accessing globals *from* NASM works fine:

extern _malloc
...
call _malloc

I haven't tried mangled names yet but trust it will work.

Jen

Frank Kotler

unread,
Jan 16, 2008, 5:51:58 PM1/16/08
to
Jentje Goslinga wrote:
> Hi all,
>
> I want to develop some code to run on Win and Lunix so I
> am trying out NASM but am having trouble communicating
> globals in my NASM file to the VC++ linker.
> It seems as if any globals which I declare are not exported,
> for example:
>
> cpu 586
>
> global _myfunc
>
> _myfunc:
> ...
> ret
>
> nasm -f win32 mymodule.asm -o mymodule.obj
> (Assembles fine)
>
> Linking using the VC++ linker elicits the following message
> from the linker:
> mymodule.obj : error LNK2001: unresolved external symbol
> _myfunc.

This is odd. I would expect the unresolved external to crop up in the C
module, not the asm module...

> Inspection of the object file using various disassembly
> utilities does not reveal any trace of the exported name
> _myfunc, notably not with NDISASM which also disassembles
> the header! Shouldn't any global (public) names be visible in
> the .obj file header?
>
> Anyone have any ideas why my symbols are not exported?

I'm unable to duplicate this.

> By the way, accessing globals *from* NASM works fine:
>
> extern _malloc
> ...
> call _malloc

Be thankful for small favors! :)

> I haven't tried mangled names yet but trust it will work.

Good luck getting that to work portably!

Besides that issue ("extrn C myfunc"... whatever the syntax is), ELF
*doesn't* add the underscores. Nasm provides ways to deal with that...

"__NASM_CDecl__" is a "built in" macro. It's a per-output-format macro.
In outelf.c (32- and -64), it *removes* the underscore from anything so
declared.

Adding "--prefix _" to Nasm's command line will *add* an underscore to
everything declared global or extern.

You could also use homemade macros, perhaps using the (still
undocumented) "__OUTPUT_FORMAT__" macro...

%ifidn __OUTPUT_FORMAT__, win32
%define myfunc _myfunc
%endif

Or do it other-way-round, depending on whether you like to write 'em
with or without underscores in the body of your asm code. I like the
"--prefix _" option, myself.

But global/externs not appearing in the object file, I have not seen.
One exotic possibility... backslash was added as a "line continuation
character" around 0.98.25 (?). Older code sometimes ended a comment with
a backslash, which now causes the next line to also be treated as a
comment... (it's not a bug, it's a feature... they tell me...)

Given an empty function, just like you posted, assembled with "nasm -f
win32 --prefix _ myfile.asm", I'm seeing "_myfunc" at offset 151 in
myfile.obj. (ndisasm is probably not the appropriate tool...) I'm unable
to try linking it (works fine with gcc and/or ld - without the underscore).

If you can't get it working, post the actual code (if possible). I don't
*think* it's a "Nasm problem".

Best,
Frank

Jentje Goslinga

unread,
Jan 16, 2008, 5:35:56 PM1/16/08
to
OOPS... I believe I have resolved the problem, it seems
that a SECTION directive is needed:

section .text

_myfunc:

Thank you for your time anyway.

It seems NASM does everything I need including indexed
macro loops which I need, many thanks to all developers
for a very nice clean package.

Jen

Jentje Goslinga

unread,
Jan 16, 2008, 7:47:22 PM1/16/08
to
Frank Kotler wrote:

> Jentje Goslinga wrote:
>> Hi all,
>>
>> I want to develop some code to run on Win and Lunix so I
>> am trying out NASM but am having trouble communicating
>> globals in my NASM file to the VC++ linker.
>> It seems as if any globals which I declare are not exported,
>> for example:
>>
>> cpu 586
>>
>> global _myfunc
>>
>> _myfunc:
>> ...
>> ret
>>
>> nasm -f win32 mymodule.asm -o mymodule.obj
>> (Assembles fine)
>>
>> Linking using the VC++ linker elicits the following message
>> from the linker:
>> mymodule.obj : error LNK2001: unresolved external symbol
>> _myfunc.
>
> This is odd. I would expect the unresolved external to crop up in the C
> module, not the asm module...

Actually, if I call it in the C module I get a message there
as well, obviously.
As I reported in my second post in this thread, I have resolved
the problem, it seems a SEGMENT directive is required, I will
investigate this.
Maybe NASM should say something when it does not write exported
symbols declared using the "global" directive to the OBJ file.

>> Inspection of the object file using various disassembly
>> utilities does not reveal any trace of the exported name
>> _myfunc, notably not with NDISASM which also disassembles
>> the header! Shouldn't any global (public) names be visible in
>> the .obj file header?
>>
>> Anyone have any ideas why my symbols are not exported?
>
> I'm unable to duplicate this.
>
>> By the way, accessing globals *from* NASM works fine:
>>
>> extern _malloc
>> ...
>> call _malloc
>
> Be thankful for small favors! :)
>

Everything in NASM works fine, I just ported some code and the
changes needed from my WASM (Watcom Assembler) code are minimal,
and there even is a manual! I should have switched much earlier.

>> I haven't tried mangled names yet but trust it will work.
>
> Good luck getting that to work portably!

I have no trouble using mangled names in NASM or whateverASM,
portably (as far as ASM is portable) by using the global symbols
defined by my compilers, and simply swap the exported names,
something like:

%ifdef _MSC_VER ; Microsoft Visual C/C++ Compiler
myfunc = VC_mangled_name
%elifdef __WATCOMC__ ; Watcom C/C++ Compiler
myfunc = Watcom_mangled_name
%endif

global myfunc

...
myfunc:
...

This actually does not work with WASM because of inability of the
macro language to use a defined symbol as a label, but it may work
with NASM if I can get Watcom to use NASM.

To find out what the mangled name is, instead of tediously composing
the name using Agner Fog's excellent "Calling Conventions" manual,
I simply declare the function header and omit the specification, which
elicits a linker message showing the expected name, since the linker
knows about the name mangling scheme used by its "companion" compiler,
even when mangling schemes change with package release versions.

> Besides that issue ("extrn C myfunc"... whatever the syntax is), ELF
> *doesn't* add the underscores. Nasm provides ways to deal with that...
>
> "__NASM_CDecl__" is a "built in" macro. It's a per-output-format macro.
> In outelf.c (32- and -64), it *removes* the underscore from anything so
> declared.
>
> Adding "--prefix _" to Nasm's command line will *add* an underscore to
> everything declared global or extern.
>
> You could also use homemade macros, perhaps using the (still
> undocumented) "__OUTPUT_FORMAT__" macro...
>
> %ifidn __OUTPUT_FORMAT__, win32
> %define myfunc _myfunc
> %endif
>
> Or do it other-way-round, depending on whether you like to write 'em
> with or without underscores in the body of your asm code. I like the
> "--prefix _" option, myself.

The prefix option sounds more portable, I'd put a comment in the code
showing the NASM call with the option. But since I already use the
compiler switches as outlined above, I may do it the old way so that
it is totally unambiguous from the code what the names are.

> But global/externs not appearing in the object file, I have not seen.
> One exotic possibility... backslash was added as a "line continuation
> character" around 0.98.25 (?). Older code sometimes ended a comment with
> a backslash, which now causes the next line to also be treated as a
> comment... (it's not a bug, it's a feature... they tell me...)
>
> Given an empty function, just like you posted, assembled with "nasm -f
> win32 --prefix _ myfile.asm", I'm seeing "_myfunc" at offset 151 in
> myfile.obj. (ndisasm is probably not the appropriate tool...) I'm unable
> to try linking it (works fine with gcc and/or ld - without the underscore).

Does NDISASM show the actual bytes of the characters constituting
the name?

> If you can't get it working, post the actual code (if possible). I don't
> *think* it's a "Nasm problem".
>
> Best,
> Frank

It seems to be working now, thanks a lot Frank,

Jen

Frank Kotler

unread,
Jan 17, 2008, 4:47:34 AM1/17/08
to
Jentje Goslinga wrote:

...


> As I reported in my second post in this thread, I have resolved
> the problem, it seems a SEGMENT directive is required, I will
> investigate this.

Yeah. That's unexpected. Nasm defaults to ".text" if you don't specify a
segment/section (same thing). My "experiment" didn't have a "section" or
"segment" directive, and still the symbol appeared in the .obj.

> Maybe NASM should say something when it does not write exported
> symbols declared using the "global" directive to the OBJ file.

*Should* do what you tell it! I notice that Nasm doesn't complain about
"global" in "-f bin" mode, where it's meaningless (I thought it did). In
an output format where it's valid, Nasm should export a "global" symbol
- no excuses! I *hope* you'll find you were mistaken!

...


> Everything in NASM works fine, I just ported some code and the
> changes needed from my WASM (Watcom Assembler) code are minimal,
> and there even is a manual! I should have switched much earlier.

I been *tellin'* people this! :)

(I don't mean to knock Watcom - I haven't tried WASM, but the openwatcom
package as a whole is quite nice - unless I'm mistaken, the Windows
executable of Nasm at SF was built by Watcom - running on Linux!)

...


> I have no trouble using mangled names in NASM or whateverASM,
> portably (as far as ASM is portable) by using the global symbols
> defined by my compilers, and simply swap the exported names,
> something like:
>
> %ifdef _MSC_VER ; Microsoft Visual C/C++ Compiler
> myfunc = VC_mangled_name
> %elifdef __WATCOMC__ ; Watcom C/C++ Compiler
> myfunc = Watcom_mangled_name
> %endif
>
> global myfunc
>
> ...
> myfunc:
> ...

Okay. Nasm won't do "=", but "%define myfunc __myfunc@42" ought to work.

> This actually does not work with WASM because of inability of the
> macro language to use a defined symbol as a label, but it may work
> with NASM if I can get Watcom to use NASM.

I find it hard to imagine, but I hear Watcom likes a *trailing*
underscore. If so, "--postfix _" instead of "--prefix _"...

> To find out what the mangled name is, instead of tediously composing
> the name using Agner Fog's excellent "Calling Conventions" manual,
> I simply declare the function header and omit the specification, which
> elicits a linker message showing the expected name, since the linker
> knows about the name mangling scheme used by its "companion" compiler,
> even when mangling schemes change with package release versions.

Sounds good. I urge people to read error messages carefully, 'cause they
sometimes tell ya what you *do* want.

...


> The prefix option sounds more portable,

If you want to treat *all* global/extern symbols the same, it seems to
work fine. If you need some treated differently... we're back to doing
it "by hand".

> I'd put a comment in the code
> showing the NASM call with the option.

Yeah! Even if you've got a Makefile, it could get lost. Nasm's got
enough options that a clue may be needed. Same should go for any
included files, I suppose. Exactly *what* "system.inc" is this, and
where would I get it... Ideally...

> But since I already use the
> compiler switches as outlined above, I may do it the old way so that
> it is totally unambiguous from the code what the names are.

A lot to be said for "unambiguous"!!!

...


> Does NDISASM show the actual bytes of the characters constituting
> the name?

Yeah... but not as "characters". As you've noticed, ndisasm tries to
disassemble everything it sees. ("_myfunc" doesn't disassemble into
anything interesting) For that kind of work, I prefer "Biew" -
http://biew.sf.net - even a text editor would be better than ndisasm for
this, I'd think. There must be a "pedump", too - probably more than one
- which *would* know about the header (?).

...


> It seems to be working now, thanks a lot Frank,

That's the important thing! If you find that Nasm is really neglecting
to export your globals... let me know and I'll pass it on to the
development team.

Best,
Frank

Jentje Goslinga

unread,
Jan 18, 2008, 12:30:34 PM1/18/08
to

I decided I cannot leave this thread open ended, so here we go
one more time.

On the subject of NASM linking problems without SEGMENT directive:
I downloaded BIEW which Frank uses and dumped the object files
(-f win32) and differenced these with DELTA, an excellent legacy
difference program in DOS, probably the best differencer.
The second longword is different in both files, hope it is not a
time stamp, I am not an expert in object file headers (yawn):

I segment .text
II ; segment .text commented out, resulting in VC++ linker
; complaints

the first four longwords are in the OBJ files are
respectively for each case
I: 00000000: 4C 01 01 00 F2 C8 90 47 96 02 00 00 14 00 00 00
II: 00000000: 4C 01 01 00 64 CA 90 47 96 02 00 00 14 00 00 00

The remainder of the files are identical; in both cases all
labels are visible at the end of the OBJ file.


On the subject of Watcom, Watcom always was a great compiler
but I am not sure it is up to date anymore and there is some
stuff I don't like.
I like using more than one compiler and Watcom gives me a
different perspective of my code and warns of possible problems
which may be overlooked by other compilers.
It also has the option to show the FPU and memory in Hex which
my version of VC does not have.

However, I have had the following problems with WASM:

There is no real manual so I had to scavenge for WASM files
on the Internet to deduce the macro looping syntax, how deep
can one stoop!

Now that I a may have to swap mangled names the ASM by keying
on an externally supplied definition I have found that WASM
does not allow me to substitute for labels (i.e. function names)
so the following is illegal:

K:\Watcom\binnt\WASM $(InputName) -d_MSC_VER -mf -5r -fp5 -fpi87
-w4 -e5 -fo=debug\ -q

K:NASM\NASM -f win32$(InputName).asm -d_MSC_VER
-o debug\$(InputName).obj

Assembler Code (corrected):

%ifdef _MSC_VER ; Microsoft Visual C/C++ Compiler

%define myfunc VC_mangled_name


%elifdef __WATCOMC__ ; Watcom C/C++ Compiler

%define myfunc Watcom_mangled_name ; <<===
%endif
...
myfunc: ; <<===

It seems that WASM does not allow such substitutions which
is a total road block, but it works fine with NASM. Someone
let me now if I am wrong.

I apologize, I was sloppy, I forgot to say that I set the
compiler symbols in the IDE (they are not propagated by the
IDE) and am using the same symbols which the compilers emit.

Another gripe against Watcom (now OpenWatcom) is that I just
read that they have truncated the extended precision evaluation
in the FPU, for "compatibility reasons", I surely hope this
"feature" can be turned off. It must be something like

FSTP QWORD somewhere
FLD QWORD somewhere

following every FPU operation

It is true that FPU results using the Intel chip are not
compliant with IEEE double since FPU operations are always
in Extended Precision regardless of the setting of the
precision bitS (except for FDIV and FSQRT whose result is
computed only to precision equivalent to IEEE float, IEEE
double, depending on the precision bits), unless these are
set to Extended Precision, but they are more accurate!

Note that VC++ has dropped extended precision and now maps
long double to double whereas GNU C++ still supports it
(also the Intel compiler 599$ PER PLATFORM), which is one
of the reasons I am porting my code to Linux.


In the mean time I wrote a few hundred lines of NASM code
and it works fine.
In summary, I am quite happy now, since NASM allows me to
develop an entirely portable system in C++ and ASM, which
uses VC++ (maybe even Intel$) plus NASM under Windows,
and GNU C++ plus NASM under Linux.
I have C++ stubs for my Intel ASM functions so that on
other platforms people would have to live with the (much)
slower speed or invest a few days rewriting the ASM for
their microprocessor.


I would like to thank Frank for his support and extend
my thanks to the NASM team for a very nice package.

Jen

nbaker2328

unread,
Jan 18, 2008, 2:18:38 PM1/18/08
to
On Jan 16, 11:39 am, Jentje Goslinga <spamt...@crayne.org> wrote:
> Hi all,
>
> I want to develop some code to run on Win and Lunix so I
> am trying out NASM but am having trouble communicating
> globals in my NASM file to the VC++ linker.

Does Microsoft have a VC++ suite for L'unix? It seems to me that if
you want to make the cross-platform task easy, you'd settle for the
same tool-chain on both systems. Visit MinGW.org for the GNU linker/
make/etc for Windows. From what I can tell, any C library calls you
make (in Windows) are translated into calls to Microsoft's C run-time
dll, so you aren't 'totally' leaving the MS-friendly environment.

Nathan.

Charles Crayne

unread,
Jan 18, 2008, 9:37:37 PM1/18/08
to
On Fri, 18 Jan 2008 09:30:34 -0800
Jentje Goslinga <spam...@crayne.org> wrote:

> the first four longwords are in the OBJ files are
> respectively for each case
> I: 00000000: 4C 01 01 00 F2 C8 90 47 96 02 00 00 14 00 00 00
> II: 00000000: 4C 01 01 00 64 CA 90 47 96 02 00 00 14 00 00 00
>
> The remainder of the files are identical; in both cases all
> labels are visible at the end of the OBJ file.

I'm not that familiar with the win32 object file format, but according
to the NASM code which writes that header, this is what it means:

4C 01 /* MACHINE_i386 */
01 00 /* number of sections */
F2 C8 90 47 /* time stamp */
96 02 00 00 /* file size */
14 00 00 00 /* number of symbols */

-- Chuck

0 new messages