0

I am trying to print multiple strings on a different line in Assembly but with my code, it keeps printing only the last string. I am very new to assembly language so, please bear with me

 section .text             
                           
 global _start             
 _start:                    
  mov edx, len              
  mov edx, len1             
  mov edx, len2             
  mov edx, len3             
  mov ecx, msg              
  mov ecx, str1             
  mov ecx, str2             
  mov ecx, str3             
  mov ebx, 1                
  mov eax, 4                
  int 0x80                  
  mov eax, 1                
  int 0x80                  

   
  section .data             


 msg  db 'Hello, world!',0xa                       
 str1 db 'Learning is fun!',0xa 
 str2 db 'I love beacon!',0xa         
 str3 db 'I love programming',0xa                      
 len1 equ $ - str1           
 len2 equ $ - str2           
 len3 equ $ - str3           
 len  equ $ - msg            

It only prints out I love programming.

It suppose to print

 Hello World!
 Learning is fun!
 I love beacon!
 I love programming
Peter Cordes
  • 245,674
  • 35
  • 423
  • 606
B.Daddy
  • 21
  • 5
  • 1
    `int 0x80` calls into the kernel, at which point it figures out *which* system call you wanted from EAX, and uses the args in other regs. You only make on `write` system call, and waste a bunch of instruction overwriting registers with different values before that. Use a debugger to single-step and look at register values change, and use `strace ./my_program` to trace system calls. – Peter Cordes Jul 15 '20 at 05:54
  • 1
    Also, all your lengths are wrong except for `len3`, which happens to be the one you actually used. ([How does $ work in NASM, exactly?](https://stackoverflow.com/q/47494744) / [In NASM labels next to each other in memory are causing printing issues](https://stackoverflow.com/q/26897633)) e.g. `len` is the whole length of all the strings combined, so you could of course print that whole block of ASCII text with one write syscall. – Peter Cordes Jul 15 '20 at 05:55
  • @PeterCordes I don't understand what to do here – B.Daddy Jul 15 '20 at 06:00
  • Possibly a duplicate of [What does "int 0x80" mean in assembly code?](https://stackoverflow.com/q/1817577) or maybe [What is the explanation of this x86 Hello World using 32-bit int 0x80 Linux system calls from \_start?](https://stackoverflow.com/q/45052162) Or [Hello, world in assembly language with Linux system calls?](https://stackoverflow.com/q/61519222) – Peter Cordes Jul 15 '20 at 06:01
  • 1
    Either make multiple `write` system calls with multiple `int 0x80` instructions, or pass a pointer to `msg` and the length of the whole block of text to one `write` system call. The kernel can only see the values in registers when `int 0x80` runs, not the history of overwriting that register 4 times before calling into the kernel. – Peter Cordes Jul 15 '20 at 06:02
  • @PeterCordes could you provide code examples – B.Daddy Jul 15 '20 at 06:22
  • There is a code example in [Hello, world in assembly language with Linux system calls?](https://stackoverflow.com/q/61519222). Make the string as long as you want, including multiple `0xa` newlines if you want. – Peter Cordes Jul 15 '20 at 06:30

1 Answers1

1
mov edx, len              
mov edx, len1             

What do you expect?

You are overwriting the register edx.

This is just like the following code in other programming languages:

variableEdx = len;
variableEdx = len1;

The second line will overwrite the variable variableEdx and the effect of the first line will be gone!

how to print multiple strings

Function eax=4 writes some data in memory beginning at some address and ending at some address to some device.

If the second string immediately follows the first one in memory, you can send the memory consisting of both strings to the device.

Example:

...
mov edx, str1
mov ecx, 32
...

This will send 32 bytes of the content of the memory starting at str1 to the device. And 32 bytes starting at str1 are the strings str1 and str2.

If you want to send multiple blocks of memory to a device, you could use the writev() system call, which is function eax=146, instead. (See this link).

Example:

.text
.globl _start

_start:
    mov edx, 3
    mov ecx, offset list
    mov ebx, 1
    mov eax, 146
    int 0x80
    mov eax, 1
    int 0x80

.data

list:
    .long msg
    .long 7
    .long str1
    .long 8
    .long str3
    .long 19

    ...

Unfortunately, the assembler I use has a slightly different syntax than yours; however, in your assembly the list part would probably look like this:

list dd msg
     dd 7
     dd str1
     ...

writev (function 146) takes a pointer to some "list" in the ecx register and the number of entries in the list in the edx register.

Each entry in the list consists of two 32-bit words. The first word is the address of the memory to be written to the device; the second word is the number of bytes to be written.

The example above writes "Hello, Learing I love programming":

The first 7 bytes of "msg", then the first 8 bytes of "str1" and then all 19 bytes of "str3".

Martin Rosenau
  • 14,832
  • 2
  • 13
  • 30
  • 1
    EAX=146 is a `writev` system call; you should name it and link to the man page: https://www.man7.org/linux/man-pages/man2/writev.2.html – Peter Cordes Jul 15 '20 at 07:20