1

I'm having some trouble with this simple program that accepts a name from the user and prints "Hello, name here"

This is my code so far...

%define SYSCALL_WRITE 0x2000004
%define SYSCALL_EXIT  0x2000001
%define SYSCALL_READ  0x2000003

SECTION .data
  prompt db "Enter name "
  text2 db "Hello, "

SECTION .bss
  name resb 16

SECTION .text
  global _start

_start:
  call _printText1
  call _getInput
  call _printText2
  call _printName
  mov rax, SYSCALL_EXIT
  mov rdi, 0
  syscall

_printText1:
  mov rax, SYSCALL_WRITE
  mov rdi, 1
  mov rsi, prompt
  mov rdx, 11
  syscall
  ret

_getInput:
  mov rax, SYSCALL_READ
  mov rdi, 0
  mov rsi, name
  mov rdx, 1
  syscall
  ret

_printText2:
  mov rax, SYSCALL_WRITE
  mov rdi, 1
  mov rsi, text2
  mov rdx, 7  
  syscall
  ret

_printName:
  mov rax, SYSCALL_WRITE
  mov rdi, 1
  mov rsi, name
  mov rdx, 16
  syscall
  ret

When I execute it, the output doesn't print "Hello, ". The first letter of the name entered is printed before the next commandline...

nMy-MacBook:Assembly username$ ame

and the rest of the name is accepted as a command argument, for which the system replies

-bash: ame: command not found

What exactly am I doing wrong? I deleted the _getInput and _printName functions and it still only prints "Enter name " without printing "Hello, ".

Thank you.

srsrso
  • 111
  • 8
  • Are you using a debugger? – InfinitelyManic Dec 19 '17 at 15:26
  • @InfinitelyManic I am just using the Terminal on my mac. – srsrso Dec 19 '17 at 15:28
  • Yes - but are you actually using some debugger software to step through your assembly code as it executes? Using a debugger helps you to identify the failure points. For example, I use GDB; however, I use a Linux OS or OpenBSD from the command line. – InfinitelyManic Dec 19 '17 at 15:32
  • @InfinitelyManic No I haven't been using a debugger. For some reason, I just kind of assumed there wouldn't be one for assembly. I'll definitely look into debuggers for mac. – srsrso Dec 19 '17 at 15:36
  • From a 5 second look your code looks correct. May it be the I/O `sys_read/sys_write` are by default buffered for STDOUT, and you terminate your app too soon before the output is flushed? Try either call some kind of `fflush` service on STDOUT, or add newline output after your name (newline often enforces STDOUT flush). Or call some `delay` service for few milliseconds, before calling `sys_exit`. Or use+link against C runtime, and use `scanf/printf`inside `main`, then return from `main`, the setup/teardown code included by C compiler will handle the set up of I/O streams, including flush at end – Ped7g Dec 19 '17 at 15:36
  • any decent debugger can go down into disassembly level + display CPU state (registers, etc). And memory content. That's all you need for simple short asm programs, even without debug info in binary, they are easy to read w/o labels and symbols (if you wrote them and you have source in other window available for cross-check). – Ped7g Dec 19 '17 at 15:37
  • 1
    I just copied your code; but in a Linux OS; which (if you did not know) uses the same 64-bit System ABI, so it generally works with some tweaks like syscall numbers. Your _getInput syscall is only accepting one (1) byte. Start with that.... – InfinitelyManic Dec 19 '17 at 15:42
  • If you want to craft the binary executable totally from scratch without a linker (with custom Mach-O header) you can check my example here: https://stackoverflow.com/a/32659692/5329717 – Kamil.S Dec 21 '17 at 11:43

1 Answers1

2

In Assembly you have to account for every bit; especially when doing input and output.

Below is your partial code with edits for RDX wherein I chose some arbitrary length.

The last line shows the command line program execution, prompt, user input, then final output.

; reference:
; https://stackoverflow.com/questions/47889972/accepting-user-input-in-assembly-simple-program-on-macos

; lsb_release -a
; Distributor ID: Ubuntu
; Description:    Ubuntu 16.04.3 LTS
; Release:        16.04
; Codename:       xenial

; assemble and link
; nasm -f elf64 -g -F dwarf srsrso_001.s -o srsrso_001.o  && ld srsrso_001.o -o srsrso_001

;%define SYSCALL_WRITE 0x2000004
;%define SYSCALL_EXIT  0x2000001
;%define SYSCALL_READ  0x2000003

SECTION .data
  prompt db "Enter name "
  text2 db "Hello, ",0xa,0

        SYSCALL_WRITE equ       1
        SYSCALL_EXIT  equ       60
        SYSCALL_READ  equ       0

SECTION .bss
  name resb 0xff                ; some length

SECTION .text
  global _start

_start:
 call _printText1
 call _getInput
 call _printText2
 call _printName

  mov rax, 60
  mov rdi, 0
  syscall

_printText1:
  mov rax, SYSCALL_WRITE
  mov rdi, 1
  mov rsi, prompt
  mov rdx, 11
  syscall
  ret

_getInput:
  mov rax, SYSCALL_READ
  mov rdi, 0
  mov rsi, name
  mov rdx, 0xff ; some length
  syscall
  ret

_printText2:
  mov rax, SYSCALL_WRITE
  mov rdi, 1
  mov rsi, text2
  mov rdx, 7
  syscall
  ret

_printName:
  mov rax, SYSCALL_WRITE
  mov rdi, 1
  mov rsi, name
  mov rdx, 0xff ; some length
  syscall
  ret

Example output:

$ ./srsrso_001
Enter name David John Lewis Benjamen Kyle Smith-Wenson
Hello, David John Lewis Benjamen Kyle Smith-Wenson
InfinitelyManic
  • 760
  • 1
  • 6
  • 13
  • Upvoted for showing also example input/output, but then I realized you ask for 65535 bytes long input, but you didn't show the input buffer resize, i.e. with original `name resb 16` this is another bug, and longer than 16 chars input may crash the app now. Just like you wrote yourself: *"In Assembly you have to account for every bit"*, that's including the storage space. Please fix. (also often it's nice to include the build steps, but that's more like for question, than answers, still it makes easier to reproduce results by random reader). – Ped7g Dec 19 '17 at 19:11
  • 1
    +Peg7g - Hope my changes help. Thank you. – InfinitelyManic Dec 19 '17 at 19:39
  • It works like charm. This is how I tried it on my macbook 2019: nasm -fmacho64 input.asm && clang -Wl,-no_pie input.o && ./a.out – Golden Thumb Jan 07 '22 at 17:41