NASM - The Netwide Assembler
NASM Forum => Using NASM => Topic started by: dreamCoder on January 07, 2014, 08:21:42 AM
-
Hi newbies :D
Attached is a macro file named lib16.inc that you can use and learn from so that you don't have to start from nothing. It provides many useful utilities like printing string, converting numbers, checking the registers and so on. It also provides simple I/O mostly from the keyboard. This macro file should enable you to learn ASM fast and get to program in NASM in a short time. It consists of 25 macros (+ 2 sub macros).
For example, below is a sample program demonstrating the use of various macros, with their possible switches;
org 100h
%include 'lib16.inc'
section .text
prts "Enter your name: ",-line ;print message with no line
gets nm ;get string from kboard
prts "Hello, Welcome to NASM ",-line ;print welcome and name on the sam line
prts nm
mov ax,100h ;Put something in AX
prtr ax ;confirm it VISUALLY
prtr ax,-b ;AX with binary switch. Prints binary equivalence
prtr ax,-o,-n ;prints AX, with octal, but not the name
shl ax,1 ;do something to AX.
prtr ax,-b ;confirm what you just did VISUALLY
prts "Enter an integer: ",-line ;Prompt user for an integer
geti x ;Get integer string from keyboard
add word[x],10 ;add 10 to it
prts "The value you entered + 10 is: ",-line
prti [x]
prts "x in binary is: ",-line
prtb [x],-t
prts "x in octal is: ",-line
prto [x]
prts "Evaluating integral expression -34*5/2 (signed)"
prti -34*5/2,-s ;prti with -s switch (signed)
prts "Evaluating integral expression -34*5/2 (unsigned)"
prti -34*5/2
prts "Converting 56h to Base 32... answer is: ",-line
bconv 56h,32 ;convert 56h to base 32
prts "Register CX in multiple bases..."
prts "In octal: ",-line
prto cx
prts "In decimal: ",-line
prti cx
prts "In binary: ",-line
prtb cx
exit ;must include this every time
section .data
nm: times 30 db '0',0
x dw 0
This is the output:
Enter your name: Frank
Hello, Welcome to NASM Frank
AX:0100
AX:0100 [00000001 00000000b]
0100 [400o]
AX:0200 [00000010 00000000b]
Enter an integer: 34
The value you entered + 10 is: 44
x in binary is: 101100
x in octal is: 54
Evaluating integral expression -34*5/2 (signed)
-85
Evaluating integral expression -34*5/2 (unsigned)
65451
Converting 56h to Base 32... answer is: 2M
Register CX in multiple bases...
In octal: 377
In decimal: 255
In binary: 00000000 11111111
No restrictions on the usage. Use it until you can come up with your own macros. Some of these macros here are readily convertible to 32-bit.
Read the internal descriptions on how to use the macros and the switches.
Thanks to Frank and Bryant for helping me out with the conversions to NASM.
Hope you can benefit from it.
Regards
Soffian
UPDATE: 13th Feb 2014
I attached another macro file named lib16x.inc which is functionally equivalent to lib16.inc but this time I changed some of the macro files names to more descriptive names such as prtstr (prts), prtreg(prtr), prtchar, getstr, getoct etc. Plus, I also added a few macros (such as getnum, convert etc), removed some hidden bug and did a little optimization. Therefore lib16x.inc is not compatible with lib16.inc. Read the description at the end of the macro file (lib16x.inc). I strongly recommend you use lib16x.inc
Regards.
-
This is the list of the macros in lib16.inc
;================== LIST OF MACROS ======================;
;prtr - Display 16-bit register
;dumpreg - Dump register
;flags - Display Flags register
;geti - Get and save decimal from kboard
;prti - Display Decimal string
;geto - Get and save Octal string from kboard.
;prto - Display Oct string
;getb - Get and save Bin string from kboard.
;prtb - Display Bin string (formatted)
;pbin - Display Bin string (raw format)
;geth - Get and save Hex string from kboard.
;prth - Display Hex string
;getc - Get a character from kboard and put in var
;getch - Get character from kboard and put in AL
;prtc - Display a character to screen
;gets - Get string from keyboard
;prts - Print string using 2 sub macros
;lines - Print line(s)
;line - Alternative to line - Print single line
;exit - Pause and quit to OS
;pause - Pause the screen
;bitf - Extract bit field from a word, with copy
;bconv - Base converter (16-bit) to any base up to 36
;pow - 16-bit power function
;cls - Clear 80x25 console screen
;TOTAL 25 macros + 2 sub macros(prtCStr/prtStr)
;
;============================
;Recommended Skeleton for COM
;============================
; org 100h
; %include 'lib16.inc'
; section .text
; <your codes here>
; exit
; section .data
; <your data here>
;================= GUIDES ON USAGE ======================;
;-Save this file in the same dir as your source file. ;
;-To use lib16 in your source, use %include directive. ;
;-Use a macro by typing the name of the macro and ;
; supply parameters if necessary. Read descriptions. ;
;-Strictly 16-bit. For COM. ;
;-Macro names,switches and parameters are lower-cased ;
;-Distribute freely for educational purposes only. ;
;-Use at own risk. NOT for critical systems. Unoptimized.;
;-Use for small tasks only. Tends to get larger easily ;
;-Use exit at the end of source to exit properly. ;
;PARAMETERS: ;
;- [db],[dw] = mem variable in square bracket ;
;- db,dw = Variable without bracket ;
;- imm16/8 = Size of immediate (word/byte) ;
;- r16/r8 = 16-bit register / 8-bit register ;
;- (opt) = Optional ;
;ERROR CODES: '#','!' ;
;--------------------------------------------------------;
-
Sorry if it is not perfect though. My knowledge of NASM is very limited at this time. And if you found a bug or have a way of redefining the macros, please modify it and share with us your modifications in this thread. But try to keep it simple and descriptive (simple instructions etc). Optimization may not be the main purpose of this macro file. I developed this solely for newbies seeking speedy entry to NASM/ASM programming particularly those starting up from 16-bit COM environment. That may be old, but the educational values provided by 16-bit programming will never grow old.
-
A slight modification to macro geti. Reason: to get rid of the macro's local data and replace it with dx as the signess marker.
;GET DECIMAL STRING FROM KBOARD
;And convert to its true value
;Five digits only. Max: 65535
;Don't supply suffix 'd'
;Valid digits from '0' to '9' only
;%1 = dw
;============
%macro geti 1
;============
pusha
mov word[ds:%1],0 ;initialize variable
xor si,si ;si=0 or mov si,0. For the loop
xor di,di ;di=0 or mov di,0. For the exponent
xor dx,dx ;**
%%get:
getch ;get character from kboard (in AL)
cmp al,'-' ;if negative sign
je %%sign
cmp al,0dh ;if <ENTER>
je %%line
cmp al,39h ;if bigger than '9'
jg %%inv
sub al,30h ;convert chars to digits
xor ah,ah ;clear AH. We want AL only
push ax ;now save AX (AL=digit. AH cleared)
inc si ;Loop up
cmp si,6 ;5 digits only (for 16-bit)
je %%inv
jmp %%get ;get next char from kboard
%%sign:
test si,si ;if invalid negative form
jnz %%inv ;equals cmp si,0/je %%inv
mov dx,1 ;**
push dx ;**
jmp %%get ;get next chars
%%inv:
prtc '!'
jmp %%exit
%%line:
line ;after ENTERed
%%first:
pop ax ;Restore digit off the stack,save in AX
add word[ds:%1],ax ;add first digit, to sent var
cmp si,1 ;if single digit input
je %%done ;done
%%second: ;Second digit
inc di ;Power up
mov ax,10 ;10^1 = 10
pop bx ;restore digit off the stack,save in BX
mul bx ;AX=AX(10)* BX(digit). Answer in AX
add word[ds:%1],ax ;add up second digit, to sent var
cmp si,2 ;if two digits input
je %%done ;done
sub si,2 ;next loop is to ignore two digits
%%next:
inc di ;power up (exponent)
push di ;save exponent onto stack
mov ax,10 ;for MUL
mov bx,10 ;for MUL
%%pow:
mul bx ;Generate pow, final answer in AX
cmp di,2 ;off-by-one adjustment. If power is completed
je %%ok
dec di ;else, exponent down
jmp %%pow ;next pow for the same digit
%%ok:
pop di ;restore exponent
pop bx ;restore the digit
mul bx ;AX=AX(from pow) * BX (digit)
add word[ds:%1],ax ;add up to sent var
dec si ;loop down
test si,si ;loop check if si=0
jz %%done
jmp %%next ;process next digit
%%done:
pop dx ;**
cmp dx,1 ;**
je %%signs
jmp %%exit
%%signs:
neg word[ds:%1] ;negate it
%%exit:
popa ;restore general registers
%endmacro
Just replace the entire macro with this one above. Usage:
geti x ;get a 16-bit decimal from keyboard. Sign or unsigned
prti [x],-s ;Display sign integer (-s switch)
...
...
x dw 0
-
Hi again Frank and Bryant
This time it's a 32-bit macro that's giving me problem. I wrote this macro that converts to integer:
extern _printf
extern _scanf
extern _putchar
extern _getchar
extern _exit
%macro prtint 1-3
pushad
mov eax,%1
xor esi,esi
mov ecx,10
xor edx,edx
test eax,80000000h
js %%sign
jmp %%start
%%sign:
%ifidn %2,-s
prtchar '-'
neg eax
%endif
%%start:
div ecx
push edx
xor edx,edx
inc esi
test eax,eax
jz %%prt
jmp %%start
%%prt:
dec esi
pop eax
add al,30h
prtchar eax
test esi,esi
jz %%done
jmp %%prt
%%done:
%ifnidn %3,-line
line
%endif
popad
%endmacro
%macro prtchar 1
pushad
push dword %1
call _putchar
popad
%endmacro
%macro line 0
prtchar 0dh
prtchar 0ah
%endmacro
And can be called from like:
%include 'lib32.mac'
global _main
section .text
_main:
prtint [x] ;problem buddy?
push 0
call _exit
section .data
x: dd 35h
The macro works but it prints garbage endlessly. Just like the 16-bit version, this is translated from another ASM language. Is there anything that I missed? Thanks for your replies.
-
As a wild guess...
%macro prtchar 1
pushad
push dword %1
call _putchar
add esp, 4 ; <- clean up stack!
popad
%endmacro
Best,
Frank
-
Thanks Frank. It works now. Question: Do I have to clean up the stack after calling printf as well?
-
ok I get it. Its all about different calling conventions. Oh one more question Frank, do these macros work in Linux as well? Because I have no access to Linux-based computers, just wondering if this could work without int 80h calls. Thanks.
-
Well... yeah, it should work in Linux. It won't work on my machine at the moment because I (still!) haven't got the 32-bit C libraries installed. You'd think they would be installed by default, but nooo. I've pretty much decided that this distro's broken and I'm going to have to install something else, but I haven't gotten around to doing it yet.
One difference is that Linux doesn't use underscores on "main", "printf", etc. The way I like to deal with this is to spell 'em without underscores and tell Nasm "--prefix _" if it's to be assembled as "-f win32". ("--postfix _" for OpenWatcom C - yeah, they use a trailing underscore) If you've got code with underscores in it, and you want to assemble it for Linux, you can do:
%define _main main
%define _printf printf
; etc...
or similar.
There are some differences (strnicmp vs strncasecmp for example) but 32-bit code that depends on the C libraries should "mostly" work on Windows or Linux. Dr. Carter's tutorial depends on it.
When it comes to 64-bit code, even "just call printf" is completely different. IMO they've screwed things up completely, but I suppose they have reasons... I do not envy the NASMX crew having to deal with this! Fortunately, I like int 80h... :)
Best,
Frank
-
Thanks Frank. I am still working on the 32-bit file. Btw I also added lib16x.inc to the attachment (refer to first post). Hope this can help somebody out there.