简体   繁体   中英

Printing Range Of ASCII Characters From Registers in x86 Assembly

I'm trying to print a range of ascii characters with this assembly program. I'm trying to do it using only the registers, but haven't been having much luck. Everything looks fine to me, but I'm a novice at assembly programming and might have missed something obvious. Any insight will be appreciated. Thanks:)

emphasized text .text.global _start

_start:
 movl $1, %edx

movl $65, %ebx
start_loop:
 addl $1, %ebx 
 movl $0x04, %eax
 int $0x80
 cmpl $126, %ebx
 jle start_loop 
 jmp start_loop 

 exit
 movl $0, %ebx
 movl $1, %eax
 int $0x80

You are invoking the sys_write system call. sys_write() takes three arguments, file descriptor of the output device(it should be 1 for stdout),address of the buffer where you stored the value to be printed, and the size of the data to be printed. So you have to store file descriptor in %ebx, and store address of the buffer in %ecx and size of the data in %edx. To store the file descriptor you can use the following instruction.

          movl $1, %ebx        // store 1 (stdout) in ebx)

To store the size of the data you can use:

          movl $1, %edx        // size is 1 byte

Now, you have to store the address of the buffer, you need to put your data in the memory some where and need to store the address of the memory in %ecx. Assume that you want store the data in the stack it self, then you can do like this:

          subl $4, %esp     // get 4 bytes of memory in the stack
          movl $65, (%esp)  // store data in the memory where esp points to
          movl %esp, %ecx   // store address of the data in the ecx

Now you can issue the int 0x80.

         movl $04, %eax    // store syscall number in eax    
         int  $0x80       // issue the trap interrupt

As a whole you can write the following code:

    movl $1, %ebx
    subl $0x4, %esp
    movl $64, (%esp)
    start_loop:
    movl (%esp), %eax
    addl $1, %eax
    movl %eax, (%esp)
    movl %esp, %ecx
    movl $1, %edx
    movl $0x04, %eax
    int $0x80
    movl (%esp), %eax
    cmpl $126, %eax
    jle start_loop
    addl $0x4, %esp

See Linux System Calls Part2 at http://www.rulingminds.com/syscallspart2 to know more about registers and system calls usage.

"Thank you very much for the informative answer, but is there a way to store and retrieve the value to be printed in a register without pointing to it?" -- this should probably have been edited into the question.

If you insist on using only syscalls ( int $0x80 ) to interface with the system then the answer is no. You have to somehow pass a buffer to write and rullingminds answer applies.

Using the libc putchar(3) it's straight forward. I use %ebx to keep the ascii code as this register is on linux preserved between function calls. Simply assemble using gcc filename.S (remembering to use -m32 if you are on x86_64).

.text

.extern putchar

.global main
main:  
    # make room for argument to putchar on the stack
    sub $4, %esp

    # initialize ebx with first value to print
    mov $'A', %ebx
1:
    # give character to print as argument
    mov %ebx, (%esp)
    call putchar

    # move to next character
    inc %ebx

    # are we done?
    cmp $'~', %ebx
    jle 1b

    # print newline
    movl $10, (%esp) 
    call putchar

    # adjust stack back to normal
    add $4, %esp

    # return 0 from main
    mov $0, %eax
    ret

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