简体   繁体   中英

Print ARGC in NASM without printf

Any good NASM/Intel Assembly programmers out there? If so, I have a question for you!

Every tutorial I can find online, shows the usage of "printf" for printing the actual value of ARGC to the screen (fd:/dev/stdout). Is it not possible to simply print it with sys_write() for example:

SEGMENT .data ; nothing here

SEGMENT .text ; sauce
        global _start
        _start:
                pop ECX ; get ARGC value
                mov EAX, 4 ; sys_write()
                        mov EBX, 1 ; /dev/stdout
                        mov EDX, 1 ; a single byte
                int 0x80
                mov EAX, 1 ; sys_exit()
                        mov EBX, 0 ; return 0
                int 0x80
SEGMENT .bss ; nothing here

When I run this, I get no output at all. I have tried copying ESP into EBP and tried using byte[EBP+4], (i was told the brackets de-reference the memory address).

I can confirm that the value when compared to a constant, works. For instance, this code works:

pop ebp ; put the first argument on the stack
mov ebp, esp ; make a copy 
cmp byte[ebp+4],0x5 ; does it equal 5?
je _good ; goto _good, &good, good()
jne _bad ; goto _bad, &bad, bad()

When we "pop" the stack, we technically should get the full number of arguments, no? Oh, btw, I compile with:

nasm -f elf test.asm -o test.o
ld -o test test.o

not sure if that is relevant. Let me know if i need to provide more information, or format my code for readability.

At least 2 problems.

  1. You need to pass a pointer to the thing you want to print.
  2. You probably want to convert to text.

Something like this should work:

SEGMENT .text ; sauce
        global _start
        _start:
                mov ecx, esp        ; pointer to ARGC on stack
                add byte [esp], '0' ; convert to text assuming single digit
                mov EAX, 4 ; sys_write()
                mov EBX, 1 ; /dev/stdout
                mov EDX, 1 ; a single byte
                int 0x80
                mov EAX, 1 ; sys_exit()
                mov EBX, 0 ; return 0
                int 0x80

Everyone's comments where very helpful! I am honored that you all pitched in and helped! I have used @Jester's code,

SEGMENT .text ; sauce
        global _start
        _start:
                mov ecx, esp        ; pointer to ARGC on stack
                add byte [esp], '0' ; convert to text assuming single digit
                mov EAX, 4 ; sys_write()
                mov EBX, 1 ; /dev/stdout
                mov EDX, 1 ; a single byte
                int 0x80
                mov EAX, 1 ; sys_exit()
                mov EBX, 0 ; return 0
                int 0x80

Which works perfectly when compiled, linked and loaded. The sys_write() function requires a pointer, such like in the common "Hello World" example, the symbol "msg" is a pointer as seen in the code below.

SECTION .data ; initialized data
    msg: db "Hello World!",0xa
SECTION .text ; workflow
    global _start
    _start:
        mov EAX, 4
        mov EBX, 1
        mov ECX, msg ; a pointer!

So first, we move the stack pointer into the counter register, ECX , with the code,

mov ecx, esp ; ecx now contains a pointer!

and then convert it to a string by adding a '0' char to the value pointed to by ESP (which is ARGC), by de-referencing it with square brackets, as [ESP] like so,

add byte[esp], '0' ; update the value stored at "esp"

Again, thank you all for the great help! <3

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM