NASM Error Parsing, Instruction Expected
assembly, nasm, x86
Solution
That assembly language is MASM, not NASM.
For starters, NASM segments are defined differently.
Instead of
Code segment word public 'CODE'
we write
section .text
And that "ASSUME" declaration... You must have an ancient book. That is old, old MASM code. Brings back memories from the early 1980s for me!
There are many differences between NASM and MASM, and your code needs quite a bit of work to port. If you want to port that MASM code to NASM, see MASM/NASM Differences or the NASM documentation or google "NASM vs MASM"
TL;DR: you are writing MASM code, not NASM.
Problem
I asked a similar question here but I changed assemblers and the question almost entirely changed, so in an effort to avoid question clutter I'm posting an entirely new question. Anyways, long story short, I'm on Windows 7 and I just installed NASM, and I'm trying to assemble a code listing from a book called Zen of Assembly by Michael Abrash. Here's the code for the listing: ``` ; ; *** Listing 2-1 *** ; ; The precision Zen timer (PZTIMER.ASM) ; ; Uses the 8253 timer to time the performance of code that takes ; less than about 54 milliseconds to execute, with a resolution ; of better than 10 microseconds. ; ; By Michael Abrash 4/26/89 ; ; Externally callable routines: ; ; ZTimerOn: Starts the Zen timer, with interrupts disabled. ; ; ZTimerOff: Stops the Zen timer, saves the timer count, ; times the overhead code, and restores interrupts to the ; state they were in when ZTimerOn was called. ; ; ZTimerReport: Prints the net time that passed between starting ; and stopping the timer. ; ; Note: If longer than about 54 ms passes between ZTimerOn and ; ZTimerOff calls, the timer turns over and the count is ; inaccurate. When this happens, an error message is displayed ; instead of a count. The long-period Zen timer should be used ; in such cases. ; ; Note: Interrupts *MUST* be left off between calls to ZTimerOn ; and ZTimerOff for accurate timing and for detection of ; timer overflow. ; ; Note: These routines can introduce slight inaccuracies into the ; system clock count for each code section timed even if ; timer 0 doesn't overflow. If timer 0 does overflow, the ; system clock can become slow by virtually any amount of ; time, since the system clock can't advance while the ; precison timer is timing. Consequently, it's a good idea ; to reboot at the end of each timing session. (The ; battery-backed clock, if any, is not affected by the Zen ; timer.) ; ; All registers, and all flags except the interrupt flag, are ; preserved by all routines. Interrupts are enabled and then disabled ; by ZTimerOn, and are restored by ZTimerOff to the state they were ; in when ZTimerOn was called. ; Code segment word public 'CODE' assume cs:Code, ds:nothing public ZTimerOn, ZTimerOff, ZTimerReport ; ; Base address of the 8253 timer chip. ; BASE_8253 equ 40h ; ; The address of the timer 0 count registers in the 8253. ; TIMER_0_8253 equ BASE_8253 + 0 ; ; The address of the mode register in the 8253. ; MODE_8253 equ BASE_8253 + 3 ; ; The address of Operation Command Word 3 in the 8259 Programmable ; Interrupt Controller (PIC) (write only, and writable only when ; bit 4 of the byte written to this address is 0 and bit 3 is 1). ; OCW3 equ 20h ; ; The address of the Interrupt Request register in the 8259 PIC ; (read only, and readable only when bit 1 of OCW3 = 1 and bit 0 ; of OCW3 = 0). ; IRR equ 20h ; ; Macro to emulate a POPF instruction in order to fix the bug in some ; 80286 chips which allows interrupts to occur during a POPF even when ; interrupts remain disabled. ; MPOPF macro local p1, p2 jmp short p2 p1: iret ;jump to pushed address & pop flags p2: push cs ;construct far return address to call p1 ; the next instruction endm ; ; Macro to delay briefly to ensure that enough time has elapsed ; between successive I/O accesses so that the device being accessed ; can respond to both accesses even on a very fast PC. ; DELAY macro jmp $+2 jmp $+2 jmp $+2 endm OriginalFlags db ? ;storage for upper byte of ; FLAGS register when ; ZTimerOn called TimedCount dw ? ;timer 0 count when the timer ; is stopped ReferenceCount dw ? ;number of counts required to ; execute timer overhead code OverflowFlag db ? ;used to indicate whether the ; timer overflowed during the ; timing interval ; ; String printed to report results. ; OutputStr label byte db 0dh, 0ah, 'Timed count: ', 5 dup (?) ASCIICountEnd label byte db ' microseconds', 0dh, 0ah db '$' ; ; String printed to report timer overflow. ; OverflowStr label byte db 0dh, 0ah db '****************************************************' db 0dh, 0ah db '* The timer overflowed, so the interval timed was *' db 0dh, 0ah db '* too long for the precision timer to measure. *' db 0dh, 0ah db '* Please perform the timing test again with the *' db 0dh, 0ah db '* long-period timer. *' db 0dh, 0ah db '****************************************************' db 0dh, 0ah db '$' ;******************************************************************** ;* Routine called to start timing. * ;******************************************************************** ZTimerOn proc near ; ; Save the context of the program being timed. ; push ax pushf pop ax ;get flags so we can keep ; interrupts off when leaving ; this routine mov cs:[OriginalFlags],ah ;remember the state of the ; Interrupt flag and ah,0fdh ;set pushed interrupt flag ; to 0 push ax ; ; Turn on interrupts, so the timer interrupt can occur if it's ; pending. ; sti ; ; Set timer 0 of the 8253 to mode 2 (divide-by-N), to cause ; linear counting rather than count-by-two counting. Also ; leaves the 8253 waiting for the initial timer 0 count to ; be loaded. ; mov al,00110100b ;mode 2 out MODE_8253,al ; ; Set the timer count to 0, so we know we won't get another ; timer interrupt right away. ; Note: this introduces an inaccuracy of up to 54 ms in the system ; clock count each time it is executed. ; DELAY sub al,al out TIMER_0_8253,al ;lsb DELAY out TIMER_0_8253,al ;msb ; ; Wait before clearing interrupts to allow the interrupt generated ; when switching from mode 3 to mode 2 to be recognized. The delay ; must be at least 210 ns long to allow time for that interrupt to ; occur. Here, 10 jumps are used for the delay to ensure that the ; delay time will be more than long enough even on a very fast PC. ; rept 10 jmp $+2 endm ; ; Disable interrupts to get an accurate count. ; cli ; ; Set the timer count to 0 again to start the timing interval. ; mov al,00110100b ;set up to load initial out MODE_8253,al ; timer count DELAY sub al,al out TIMER_0_8253,al ;load count lsb DELAY out TIMER_0_8253,al ;load count msb ; ; Restore the context and return. ; MPOPF ;keeps interrupts off pop ax ret ZTimerOn endp ;******************************************************************** ;* Routine called to stop timing and get count. * ;******************************************************************** ZTimerOff proc near ; ; Save the context of the program being timed. ; push ax push cx pushf ; ; Latch the count. ; mov al,00000000b ;latch timer 0 out MODE_8253,al ; ; See if the timer has overflowed by checking the 8259 for a pending ; timer interrupt. ; mov al,00001010b ;OCW3, set up to read out OCW3,al ; Interrupt Request register DELAY in al,IRR ;read Interrupt Request ; register and al,1 ;set AL to 1 if IRQ0 (the ; timer interrupt) is pending mov cs:[OverflowFlag],al ;store the timer overflow ; status ; ; Allow interrupts to happen again. ; sti ; ; Read out the count we latched earlier. ; in al,TIMER_0_8253 ;least significant byte DELAY mov ah,al in al,TIMER_0_8253 ;most significant byte xchg ah,al neg ax ;convert from countdown ; remaining to elapsed ; count mov cs:[TimedCount],ax ; Time a zero-length code fragment, to get a reference for how ; much overhead this routine has. Time it 16 times and average it, ; for accuracy, rounding the result. ; mov cs:[ReferenceCount],0 mov cx,16 cli ;interrupts off to allow a ; precise reference count RefLoop: call ReferenceZTimerOn call ReferenceZTimerOff loop RefLoop sti add cs:[ReferenceCount],8 ;total + (0.5 * 16) mov cl,4 shr cs:[ReferenceCount],cl ;(total) / 16 + 0.5 ; ; Restore original interrupt state. ; pop ax ;retrieve flags when called mov ch,cs:[OriginalFlags] ;get back the original upper ; byte of the FLAGS register and ch,not 0fdh ;only care about original ; interrupt flag... and ah,0fdh ;...keep all other flags in ; their current condition or ah,ch ;make flags word with original ; interrupt flag push ax ;prepare flags to be popped ; ; Restore the context of the program being timed and return to it. ; MPOPF ;restore the flags with the ; original interrupt state pop cx pop ax ret ZTimerOff endp ; ; Called by ZTimerOff to start timer for overhead measurements. ; ReferenceZTimerOn proc near ; ; Save the context of the program being timed. ; push ax pushf ;interrupts are already off ; ; Set timer 0 of the 8253 to mode 2 (divide-by-N), to cause ; linear counting rather than count-by-two counting. ; mov al,00110100b ;set up to load out MODE_8253,al ; initial timer count DELAY ; ; Set the timer count to 0. ; sub al,al out TIMER_0_8253,al ;load count lsb DELAY out TIMER_0_8253,al ;load count msb ; ; Restore the context of the program being timed and return to it. ; MPOPF pop ax ret ReferenceZTimerOn endp ; ; Called by ZTimerOff to stop timer and add result to ReferenceCount ; for overhead measurements. ; ReferenceZTimerOff proc near ; ; Save the context of the program being timed. ; push ax push cx pushf ; ; Latch the count and read it. ; mov al,00000000b ;latch timer 0 out MODE_8253,al DELAY in al,TIMER_0_8253 ;lsb DELAY mov ah,al in al,TIMER_0_8253 ;msb xchg ah,al neg ax ;convert from countdown ; remaining to amount ; counted down add cs:[ReferenceCount],ax ; ; Restore the context of the program being timed and return to it. ; MPOPF pop cx pop ax ret ReferenceZTimerOff endp ;******************************************************************** ;* Routine called to report timing results. * ;******************************************************************** ZTimerReport proc near pushf push ax push bx push cx push dx push si push ds ; push cs ;DOS functions require that DS point pop ds ; to text to be displayed on the screen assume ds:Code ; ; Check for timer 0 overflow. ; cmp [OverflowFlag],0 jz PrintGoodCount mov dx,offset OverflowStr mov ah,9 int 21h jmp short EndZTimerReport ; ; Convert net count to decimal ASCII in microseconds. ; PrintGoodCount: mov ax,[TimedCount] sub ax,[ReferenceCount] mov si,offset ASCIICountEnd - 1 ; ; Convert count to microseconds by multiplying by .8381. ; mov dx,8381 mul dx mov bx,10000 div bx ;* .8381 = * 8381 / 10000 ; ; Convert time in microseconds to 5 decimal ASCII digits. ; mov bx,10 mov cx,5 CTSLoop: sub dx,dx div bx add dl,'0' mov [si],dl dec si loop CTSLoop ; ; Print the results. ; mov ah,9 mov dx,offset OutputStr int 21h ; EndZTimerReport: pop ds pop si pop dx pop cx pop bx pop ax MPOPF ret ZTimerReport endp Code ends end ``` I added nasm.exe to my path, saved this file as listing1.asm, and tried to use the following CMD command to assemble it: ``` nasm -f win32 listing1.asm ``` However, it didn't assemble, and instead gave me the following errors: ``` listing1.asm:50: error: parser: instruction expected listing1.asm:51: error: parser: instruction expected listing1.asm:82: error: parser: instruction expected listing1.asm:83: error: parser: instruction expected listing1.asm:95: error: parser: instruction expected listing1.asm:99: error: symbol `endm' redefined listing1.asm:114: error: parser: instruction expected listing1.asm:115: error: comma expected after operand 4 listing1.asm:116: error: parser: instruction expected listing1.asm:122: error: parser: instruction expected listing1.asm:142: error: parser: instruction expected listing1.asm:176: error: symbol `DELAY' redefined listing1.asm:179: error: symbol `DELAY' redefined listing1.asm:188: error: parser: instruction expected listing1.asm:190: error: symbol `endm' redefined listing1.asm:200: error: symbol `DELAY' redefined listing1.asm:203: error: symbol `DELAY' redefined listing1.asm:208: error: symbol `MPOPF' redefined listing1.asm:212: error: symbol `ZTimerOn' redefined listing1.asm:212: error: parser: instruction expected listing1.asm:218: error: parser: instruction expected listing1.asm:237: error: symbol `DELAY' redefined listing1.asm:252: error: symbol `DELAY' redefined listing1.asm:282: error: comma, colon or end of line expected listing1.asm:292: error: symbol `MPOPF' redefined listing1.asm:298: error: symbol `ZTimerOff' redefined listing1.asm:298: error: parser: instruction expected listing1.asm:304: error: parser: instruction expected listing1.asm:316: error: symbol `DELAY' redefined listing1.asm:322: error: symbol `DELAY' redefined listing1.asm:327: error: symbol `MPOPF' redefined listing1.asm:331: error: symbol `ReferenceZTimerOn' redefined listing1.asm:331: error: parser: instruction expected listing1.asm:338: error: parser: instruction expected listing1.asm:350: error: symbol `DELAY' redefined listing1.asm:352: error: symbol `DELAY' redefined listing1.asm:363: error: symbol `MPOPF' redefined listing1.asm:368: error: symbol `ReferenceZTimerOff' redefined listing1.asm:368: error: parser: instruction expected listing1.asm:374: error: parser: instruction expected listing1.asm:386: error: symbol `assume' redefined listing1.asm:386: error: parser: instruction expected listing1.asm:392: error: comma, colon or end of line expected listing1.asm:402: error: comma, colon or end of line expected listing1.asm:426: error: comma, colon or end of line expected listing1.asm:436: error: symbol `MPOPF' redefined listing1.asm:439: error: symbol `ZTimerReport' redefined listing1.asm:439: error: parser: instruction expected listing1.asm:441: error: symbol `Code' redefined listing1.asm:441: error: parser: instruction expected ``` Not sure what I should do here; I've tried googling around a little bit but haven't come up with anything. Anyone recognize these errors?