Page 1 of 1

Print Immediate String NASM

Posted: Thu Aug 21, 2008 10:02 am
by Troy Martin
Hey,

Is there any way I can print an immediate string in NASM assembly? Like this:

puts "Hello World!"

That assumes puts is a NASM macro that calls os_print_string. Also, can that same macro check for a \n newline code? Thanks!

Here's os_print_string:

Code: Select all

os_print_string:
	pusha

	mov ah, 0Eh		; int 10h teletype function
                                ; Some BIOS will change DX and/or BP

.repeat:
	lodsb			; Get char from string
	cmp al, 0
	je .done		; If char is zero, end of string

	int 10h			; Otherwise, print it
	jmp .repeat

.done:
	popa
	ret

Re: Print Immediate String NASM

Posted: Thu Aug 21, 2008 11:34 am
by Brendan
Hi,

Try something like:

Code: Select all

%macro puts 1+
    section .data
%%string:
    db %1,0
    section .text

    push si
    mov si,%%string
    call printString
    pop si
%endmacro

Cheers,

Brendan

Re: Print Immediate String NASM

Posted: Fri Aug 22, 2008 7:34 pm
by Troy Martin
Freakin' sweet.

Now all I need is it to be able to take a \n newline code... But I can work on that, either in the C compiler that it's used in or in the macro itself.

Re: Print Immediate String NASM

Posted: Fri Aug 22, 2008 8:00 pm
by xyjamepa
Hi,

I have a question,can we use macros when writing an os ?
sure we can use it when writing normal applications, but is it the same when
it comes to os development?


Thanx.

Re: Print Immediate String NASM

Posted: Fri Aug 22, 2008 8:19 pm
by Dex
Yes you can, but remember, a macro is placed where you use the macro name, so if you used the macro 20 time's, it will add 20 times the size of your macro to your code.
This is not the same with a proc.

You can also use it as a simple language eg: basic

Code: Select all

macro PRINT String{

        local .Printer
        local .Nextchar
        local .Done
        local .a

        .Printer:
                mov si, .a
                mov ah, 0Eh
                jmp .Nextchar

        .Nextchar:
                lodsb
                or al, al
                jz .Done
                int 10h
                jmp .Nextchar
                jmp .Done

        .a db String,10,13,0

        .Done:
}  

macro SCREEN mode
{
	push ax

	if mode = 0
		mov ah,0h		;SCREEN 0; Default DOS screen mode
		mov al,3h
		int 10h
	else if mode = 13
		mov ah,0h		;SCREEN 13; VGA
		mov al,13h
		int 10h
	end if

	pop ax
}

macro SLEEP
{
	;Output:
	;ah = BIOS scancode of key pressed
	;al = ASCII character of key pressed
	;Could have also used...
	;	mov ah,8h
	;	int 21h
	mov ah,0h
	int 16h
}

macro END
{
	mov ax,4Ch	;\END
	int 21h		;/
}

macro LOCATE row,col
{
	pusha

	mov ah,2		;Function 2
	mov bh,0		;Use page 0
	mov dh,row	;row
	mov dl,col		;col
	int 10h

	popa
}
And then you can do this:

Code: Select all

	SCREEN 0
	LOCATE 5,5
	PRINT "Hello World"
	SLEEP
	END

Re: Print Immediate String NASM

Posted: Sat Aug 23, 2008 10:43 am
by Troy Martin
Dex, before I reqested the macro, I had already known that it would increase the size, so I'm substituting the big fat loops with "call syscall".

Abu, yeah, you can use macros in your kernel. Even in a bootloader, but even I think that's not really worth it. Remember what Dex said (and I added on to) that if you use 20 copies of the macro, the code for 20 copies of the macro will be put in. It's best to just define a system call to do the grunt work, then a small macro to set up what's needed and call the syscall. Very efficient for things like printing strings, getting input, listing the root directory, etc.

As I said in the OP, I'm using this to write out the intermediate assembly code from my C compiler. It then links to flat binary WITH MikeOS system calls,

Re: Print Immediate String NASM

Posted: Sat Aug 23, 2008 11:15 am
by Brendan
Hi,
Troy Martin wrote:Dex, before I reqested the macro, I had already known that it would increase the size, so I'm substituting the big fat loops with "call syscall".
Even if you are using the macro to call another function it can increase code size. For an example, consider the "puts" macro I posted earlier - it always pushes and pops SI even when it isn't necessary, and if you're printing several strings you'll end up with something like:

Code: Select all

    push si
    mov si,first_string
    call printString
    pop si
    push si
    mov si,second_string
    call printString
    pop si
    push si
    mov si,third_string
    call printString
    pop si
Instead of:

Code: Select all

    push si
    mov si,first_string
    call printString
    mov si,second_string
    call printString
    mov si,third_string
    call printString
    pop si
However, there are some macros that never increase code size - here's some that I always use:

Code: Select all

%macro clr 1
	xor %1,%1
%endmacro


%macro pushes 1-*
%rep %0
          push %1
%rotate 1
%endrep
%endmacro


%macro pops 1-*
%rep %0
%rotate -1
          pop %1
%endrep
%endmacro
Also, (if you're still wondering) there is no way that I can think of to get NASM to support embedded newlines in strings (e.g. "foo\nbar" instead of "foo",0x13,"bar"). As an alternative your code to print strings could do it, but then "/n" would cost 2 bytes instead of one (because the language doesn't convert it into "db 0x13" at compile time).


Cheers,

Brendan

Re: Print Immediate String NASM

Posted: Sat Aug 23, 2008 12:27 pm
by Troy Martin
Hey,

I'm going to take out the push si & pop si, since the syscall does pusha & popa for me for me.

About the newlines, I've embedded some newline code into the compiler, so I can have a newline at the end of the string. Voila!