Linux – lost in assembly NASM ELF64 world

64-bitassemblylinuxnasm

So as part of my Computer Architecture class I need to get comfortable with Assembly, or at least comfortable enough, I'm trying to read the input to the user and then reprint it (for the time being), this is my how I tried to laid this out in pseudo code:

  1. Declare msg variable (this will be printed on screen)
  2. Declare length variable (to be used by the sys_write function) with long enough value
  3. Pop the stack once to get the program name
  4. Pop the stack again to get the first argument
  5. Move the current value of the stack into the msg variable
  6. Move msg to ECX (sys_write argument)
  7. Mov length to EDX (sys_write argument)
  8. Call sys_write using standard output
  9. Kernel call
  10. Call sys_exit and leave

This is my code so far

section .data
  msg:    db 'placeholder text',0xa;
  length: dw 0x123;

section .text
  global _start 

    _start: 
      pop rbx;
      pop rbx;
      ; this is not working when I leave it in I get this error:
      ; invalid combination of opcode and operands                                                                                            
      ;mov msg, rbx;
      mov ecx, msg;
      mov edx, length;

      mov eax, 4;
      mov ebx, 1;
      int 0x80;
      mov ebx, 0;
      mov eax, 1;
      int 0x80;

When I leave it out (not moving the argument into msg), I get this output

placeholder text
#.shstrtab.text.data
                     �@�$�`��

We really just begun with NASM so ANY help will be greatly appreciated, I've been looking at this http://www.cin.ufpe.br/~if817/arquivos/asmtut/index.html#stack and http://syscalls.kernelgrok.com/ adapting the examples adapting the registry names to the best of my understanding to match http://www.nasm.us/doc/nasmdo11.html

I'm running Ubuntu 12.04, 64bit compiling (not even sure if this is the right word) NASM under ELF64, I'm sorry to ask such a silly question but I have been unable to find an easy enough tutorial for NASM that uses 64bits.

Best Answer

When the program is called the stack should looks like this:

+----------------+
| ...            | <--- rsp + 24
+----------------+
| argument 2     | <--- rsp + 16
+----------------+
| argument 1     | <--- rsp + 8
+----------------+
| argument count | <--- rsp
+----------------+

The first argument is the name of your program and the second is the user input (if the user typed anything as an argument). So the count of the arguments is at least 1.

The arguments for system calls in 64-mode are stored in the following registers:

  • rax (system call number)
  • rdi (1st argument)
  • rsi (2nd argument)
  • rdx (3rd argument)
  • rcx (4th argument)
  • r8 (5th argument)
  • r9 (6th argument)

And the system call is called with syscall. The numbers of all the system calls can be found here here (yes they are different from the numbers in 32 bit mode).

This is the program which should do your stuff:

section .data
    msg:    db 'Requesting 1 argument!', 10  ; message + newline

section .text
    global  _start

_start:
    cmp     qword [rsp], 2    ; check if argument count is 2
    jne     fail              ; if not jump to the fail lable

    mov     rax, 1            ; sys_write
    mov     rdi, 1            ; stdout
    mov     rsi, [rsp+16]     ; get the address of the argument 
    mov     rdx, 1            ; one character (length 1)

loop:
    cmp     byte [rsi], 0     ; check if current character is 0
    je      exit              ; if 0 then jump to the exit lable
    syscall
    inc     rsi               ; jump to the next character
    jmp     loop              ; repeat

fail:
    mov     rax, 1            ; sys_write
    mov     rdi, 1            ; stdout
    lea     rsi, [rel msg]    ; move the address of the lable msg in rsi
    mov     rdx, 23           ; length = 23
    syscall

exit:
    mov     rax, 60           ; sys_exit
    mov     rdi, 0            ; with code 0
    syscall

Since the code isn't prefect in many ways you may want to modify it.

Related Topic