• Please review our updated Terms and Rules here

Watcom assembler, local labels, & NASM

eeguru

Veteran Member
Joined
Mar 14, 2011
Messages
1,618
Location
Atlanta, GA, USA
For most of my real-mode x86 programming I use Open Watcom as it is one of the few (if only?) real-mode compilers that will run natively on Linux. Up until now, I've choked down the Watcom assembler as a necessity. But in order to stay with it, I need to find a solution to local labels. Does anyone know how to describe a local label in Watcom assembler? The GAS and NASM notations do not seem to work.

Also should I just bit the bullet and go with NASM instead? I have been reluctant as an Open Watcom install has a (sort of) perfectly good assembler with it. But I've seen other open source projects use the combination of NASM + Watcom C. And pitfall advice?
 
Does anyone know how to describe a local label in Watcom assembler? The GAS and NASM notations do not seem to work.

Watcom assembler is designed to be compatible with MASM so I guess it should work the same as MASM, although there are some differences between them*. I haven't used either of them in years so I might be wrong on this but IIRC any label between PROC and ENDP is considered local to that procedure so the assembler will use the local label if you have labels with the exact same name in other procedures. I *think* you need to use unique labels if you want to use any label outside of the procedure but I could be wrong about this (I suspect Chuck will know).

I'm curious why this is a problem to begin with?

* IIRC, all procedures are PUBLIC in MASM (unless you tell it otherwise) whereas in Watcom assembler nothing is PUBLIC unless you explicitly declare it as such.

Also should I just bit the bullet and go with NASM instead?

Maybe. Probably. I would. :) But I guess it all comes down to what you're most comfortable with. Use what works best for you.
 
For most of my real-mode x86 programming I use Open Watcom as it is one of the few (if only?) real-mode compilers that will run natively on Linux. Up until now, I've choked down the Watcom assembler as a necessity. But in order to stay with it, I need to find a solution to local labels. Does anyone know how to describe a local label in Watcom assembler? The GAS and NASM notations do not seem to work.

Also should I just bit the bullet and go with NASM instead? I have been reluctant as an Open Watcom install has a (sort of) perfectly good assembler with it. But I've seen other open source projects use the combination of NASM + Watcom C. And pitfall advice?

The @@ prefix works for me. But I use WASM in IDEAL mode (-zcm=tasm).
 
Finally got back to this today.

I'm curious why this is a problem to begin with?
Because it's getting long and cumbersome to manually prefix the name of the function in front of (eg) _loop.

The @@ prefix works for me. But I use WASM in IDEAL mode (-zcm=tasm).
I still can't make this work. See this example:
Code:
_TEXT segment public use16 'CODE'

        assume cs:_TEXT, ds:nothing, es:nothing


_testa proc near public

@@loop: 
        jmp @@loop

_testa endp


_testb proc near public

@@loop: 
        jmp @@loop

_testb endp


_TEXT ends

end

And this:

Code:
bash> wasm -zq -ms -zcm=masm test.asm
test.asm(17): Error! E600: '@@loop' is already defined
 
If NASM is working, stick with NASM.

Generally I've always had a measure of disgust with MASM and its ilk -- hell there have been times I'd sooner be using the COCO ROM based EDTASM... and whilst I can't say I'm familiar with Watcom's assembler if it's anything like Watcom C... well there's a reason I don't use C unless I have to. STILL don't understand the raging hardon the programming community has for such a painfully uselessly cryptic language that's so bad that if you don't care about portability, you'd be better off writing flat assembly -- it's cleaner and less work!

Honestly, NASM has been the first 'proper' standalone assembler I've ever truly been happy with on x86.

There should be ZERO problems interfacing code written with it to any parent language so long as you know the stack size on entry and how parameters are passed... which is again pretty much a norm for C or Pascal the only real difference being the entry stack offset.

I've used it for years now with no problems... and would sure as shine-ola choose it over most of the alternatives; particularly when convoluted agonizing train wrecks like MASM leave me wanting to punch someone in the face.
 
Last edited:
Uh, what? If you think C is cryptic you should try Perl...
 
Part of overcoming usage of MASM is knowing how to use it. In general, versions 6.11 and later are pretty good.

Local labels? Just put them in private procedures:

Code:
Microsoft (R) Macro Assembler Version 6.11                  11/01/17 07:34:16
x.asm                                                        Page 1 - 1


                                        .model  tiny,c
 0000                                   .code

 0000                           Proc1   proc    private
 0000                           One:
 0000  C3                               ret
 0001                           Proc1   endp

 0001                           Proc2   proc    private
 0001                           One:
 0001  C3                               ret
 0002                           Proc2   endp

                                        end

The listing cross-reference show both labels "One" as local to their procedures.

Honestly, I don't understand that vitriol directed against MASM. Early versions (just about anything before 5.0) were pretty awful, but 6.x ones are not bad at all, if you know what you're doing.
 
Local labels? Just put them in private procedures:
Which looks JUST like a global label, so how the **** are you supposed to tell them apart at a glance if the 'procedure' is taller than a screen height?!?

That's why I like NASM using:

globalLabel:
.localLabel:

... and being done with it instead of dicking around with vagary.

For me a LOT of the stuff people praise in MASM is just crap that gets in my damned way -- admittedly I say the same thing about tabbed editing (restricting you to one window defeating the point of having windows or multiple displays), the illegible acid trip that is colour syntax highlighting that has never ONCE been a "aid" to me as a programmer, autocompletion, and a whole host of other garbage that other programmers mainline like heroin but just leave me scratching my head going "WHY?!?"

To me everything about MASM has been and remains needlessly convoluted and pointless compared to the ease and simplicity of NASM. The syntax makes more sense, it results it clearer cleaner code.

Which is why screwing around with any other assembler if my target is x86 is pretty much not even an option I look at anymore. I only put up with GAS for the simple fact I will occasionally write code for ARM and MIPS... and it's just as useless as MASM constantly aggravating the hell out of me over how outright obtuse it is.

It's like they were written to be INTENTIONALLY hard to use and to make everything harder to do... Kind of like C syntax. I mean, sometimes I wonder if that's the whole reason certain methodologies, compilers, assemblers, and programming languages thrive is people WANT to intentionally make it look harder than it is!
 
Thanks for the feedback. TASM IDEAL mode of WASM did work, but IDEAL mode requires a lot of formatting change. If I am to go down that route, I might as well switch to NASM. It's not as formal as many other assemblers, but it was designed that way (KISS). There are some things that I really like about NASM like 'offset' becomes a nop with their square bracket notation format for indirect references.... something I never understood about other assemblers (why they didn't). But part of my anal retentiveness will miss things like endp (sizes never make it into object formats anyway..).

I glanced through the WASM source code and didn't see local label support outside of TASM IDEAL.

My only real issue with NASM is in linker support - there really isn't one. Most of the x86 real-mode projects I'm working on involve Watcom C as well. Which means NASM adds a second tools package I have to support. And if I wanted to ditch the spectacularly horrible Watcom Linker in favor of something that can link multiple NASM and WCC objects together, I need to support a third build tool in the form of IA16 or i386 built GNU binutils.

I'm half tempted to write my own assembler... but time is the enemy.

-Alan
 
spectacularly horrible Watcom Linker in favor of something that can link multiple NASM and WCC objects together, I need to support a third build tool in the form of IA16 or i386 built GNU binutils

wlink is quite powerful. I've used it to link quite a lot of nasm + wcc objects in both 16 + 32bit modes without issues.

you just need to know if the C is ustiong cdecl/stdcall/fastcall to know how to prefix the nasm labels and if parameters are coming on stack or in watcom register convention.
 
..and nevermind. NASM is a disaster. Just trying to write a simple skeleton for a flat 16-bit BIOS is impossible. org - in NASM - appears to only specify the starting offset of the section in which it is included. It doesn't do what it does in other assemblers in advancing the encoding pointer to the org offset.

There really isn't a good solution except for tasm ideal :( :( :(
 
In MASM if you put a label in a private procedure and suffix it with two colons, it becomes a global label.

e.g. One:: is global.

After all, how often do you want to enter a private procedure through a "back door"? Not really good programming practice, is it?
 
It doesn't do what it does in other assemblers in advancing the encoding pointer to the org offset.
In NASM "org" is more of a fallback/compatibility declaration than what you are supposed to be using, which is SECTION with start and vstart.

Code:
BITS 16
CPU 8086
SECTION .main progbits start=0x0000 vstart=0x0100

section .main
; code goes here.

For example.

If you're making an offset rom, it's likely you'd have a virtual start of zero and a literal start of the offset.

Section gives you a much finer granularity of control than org, and can let you set up your own memory map. See the "in progress" fully ASM version of Paku Paku (tiny, .COM target) I'm working on that starts out:

Code:
BITS 16
CPU 8086
SECTION .main progbits start=0x0000 vstart=0x0100
SECTION .exit  progbits follows=.main vfollows=.main
SECTION .libs progbits follows=.end  vfollows=.end
SECTION .data progbits follows=.libs  vfollows=.libs
SECTION .bss nobits follows=.data
section .end
exit:

section .libs
LIBS_START:

section .data
DATA_START:

section .bss
BSS_START:
dsSeg   resw 1

section .main
mov  [dsSeg], ds

I put the data segment into the bss area so if I change DS I can recover it from ss:[dsSeg].. or cs:[dsSeg] for that matter.
 
Last edited:
I understand what you mean. I prefer to use a GNU linker script to do that - which I'm already forced into using since I have multiple component source files. While it's nice to be able to do that in-line, it's a bit cumbersome if I have dozens of fixed points in the code where I want things to be anchored. It really comes from the output of my disassembler that will hard anchor entry points it was told to start disassembly on and which match a procedure template. I've seen far to many ROM images where 'align' has placed an extra padding byte here or there. It was more of a convenience thing. I supposed I could just auto-add padding bytes out of the disassembler. But if I remove a block of code, it was nice to have things auto-fill and still align-up in the end so I can confirm my newly annotated disassembly is still byte-perfect with the original.

I've added a ticket to owc-v2's github page a) confirming local labels outside of tasm/ideal are not supported, and b) if there is anything to lookout for if I try to add the feature to WASM myself.

Thanks for all the feedback here. This has been a learning exercise for sure!
 
I prefer to use a GNU linker script to do that
Which rarely effects me, right now I'm writing code that compiles direct to a .COM file so there is no linking... and any of the languages I would link to (Turbo C, Turbo Pascal) have their own linkers.

... and yeah, keep in mind those word boundaries in 16 bit on SECTION. When I very FIRST started using NASM I completely spaced that expecting .main to drop through safely to .exit. DOH. Sometimes it worked, sometimes it didn't... OH....
 
I understand what you mean. I prefer to use a GNU linker script to do that - which I'm already forced into using since I have multiple component source files. While it's nice to be able to do that in-line, it's a bit cumbersome if I have dozens of fixed points in the code where I want things to be anchored. It really comes from the output of my disassembler that will hard anchor entry points it was told to start disassembly on and which match a procedure template. I've seen far to many ROM images where 'align' has placed an extra padding byte here or there. It was more of a convenience thing. I supposed I could just auto-add padding bytes out of the disassembler. But if I remove a block of code, it was nice to have things auto-fill and still align-up in the end so I can confirm my newly annotated disassembly is still byte-perfect with the original.

I've added a ticket to owc-v2's github page a) confirming local labels outside of tasm/ideal are not supported, and b) if there is anything to lookout for if I try to add the feature to WASM myself.

Thanks for all the feedback here. This has been a learning exercise for sure!

You may be interested in looking at my modified XT BIOS. It has many hard entry points as you might expect, although it is ideal mode. There's a script included to build it with wasm/wlink in Linux.
 
Applogies in advance for reving this thread, but just leaving this here if someone else in the future is trying to figure this out. With some googling I found this:


Which is basically saying:

... One MASM feature that wasm supports
(as far as I can tell) is anonymous labels, ie. labels called simply
'@@' that are referenced as '@f' (forward) and '@b' (backward).

You can do this:

xor cx,cx @@: loop @b @@: loop @b ret

You don't need masm compatibility mode for this to work (not sure what compatibility the -zcm=masm is provided to wasm anyway). To jump to an explict label (e.g. an exit label or something) you'd still need to use unique labels (probably proc_name_exit: or the like).

It is what it is I guess...
 
Back
Top