0
%macro read 1
Mov ax,3
mov bx,0
mov rcx,%1
mov dx,20
Int 80h
%endmacro

%macro print 2
Mov ax,4
mov bx,1
mov rcx,%1
mov dx,%2
Int 80h
%endmacro  

 section .Data
           len : db 0
   section .bss
       Str1 resb 20
       Str2 resb 20
   section .text
     global _start: 
          read str1 ;using macro
      mov [len],al
      lea rsi,[str1]
      lea rdi,[str2]
      mov rcx,rax
      dec rcx
      Add rsi,rcx
 loop1:
       Dec rsi
       Mov al,[rsi]
       Mov [rdi],al
       Inc rdi
       loop loop1
       print str2,[len]

     Exit: 
        mov ax,1
        Mov bx,0
        int 80h


With the above asm code i can find the reverse of a string. But Here after reading the String register Al is moved to len But Register Al is not initialized and what data is holded by rcx,rax?

Can some one simply explain above code?

Aashiq Otp
  • 85
  • 1
  • 10
  • That ok... macro read just put ax 4 bx1 and read that string..But i wonder will the the length of string we read is saved in ax register? Whats the concept behind mov [len],al – Aashiq Otp Nov 10 '19 at 11:51
  • Then `read` is buggy and only works if the high bytes of RAX are already non-zero. And only works for addresses that fit in 32 bits if it's using `int 0x80` as well. – Peter Cordes Nov 10 '19 at 11:57

1 Answers1

0

Pretty obviously read returns a length in RAX. This is totally normal for functions, and makes sense for a macro, too.

In this case, yes, it's just a (buggy) wrapper around the 32-bit int 0x80 ABI for read() which as the man page explains returns a length. Linux system calls do return in RAX. It also strangely hard-codes the max length as 20.

(It's buggy because it only works if EAX, EBX, and EDX are already zero. It only writes the low 16 bits of those registers before invoking the 32-bit ABI. Writing the full RCX with an address is useless; int 0x80 only uses the low 32 bits. What happens if you use the 32-bit int 0x80 Linux ABI in 64-bit code?)

AL is the low byte of RAX, and this code only saves the low byte of the length for printing. IDK why they save it in memory instead of another register like a normal person. Especially when they copy the whole 64-bit length to RCX instead of a normal mov ecx, eax to zero-extend a 32-bit value into RCX.


Also note that the later mov ax,1 (32-bit __NR_exit) is risky and a bad idea; it potentially leaves garbage in the high bytes of RAX leading to -ENOSYS instead of _exit(0),

With the small buffer size read will fault (or return -EFAULT before it can return more than 4096, so replacing only the low 16 bits of RAX is safe in this case.

Unless read returns a negative error code; then this program will crash instead of exiting when the last int 0x80 returns -ENOSYS instead of exiting.

Try running it with ./a.out <&- to close stdin, leading to -EBADF for a read from stdin, then a crash.

Also, this is 64-bit code so using the 32-bit int 0x80 Linux system-call ABI is not a good idea. A few Linux systems (including WSL) don't have CONFIG_IA32_EMULATION and will just fault on that like they would for int 0x81 or any other software interrupt. What happens if you use the 32-bit int 0x80 Linux ABI in 64-bit code?

Peter Cordes
  • 328,167
  • 45
  • 605
  • 847
  • I added tge macro section – Aashiq Otp Nov 10 '19 at 11:56
  • So you are saying that when we read a string its length will automatically assigned to Accumulator Register?Isnt it Sir? – Aashiq Otp Nov 10 '19 at 11:59
  • @AashiqOtp: that's how the `read` system call works, yes. http://man7.org/linux/man-pages/man2/read.2.html Or RAX = -errno on error. – Peter Cordes Nov 10 '19 at 12:00
  • Ok thank your sir...Read is a user defined fuction..I mean a macro defined by me.I added that section to my question.And i Am trying to just point you out that am not using a built in read function.? However thank you sir – Aashiq Otp Nov 10 '19 at 12:02