1

I'm currently trying to write a small program in ASM, and I have the following issue. I take input from the user as a string which I store in a variable I've declared in the .bss section of my code; I then re-prompt and overwrite the previously stored answer and do this multiple times. My issue is if someone has entered an answer that was shorter than the last (i.e. "James" then "Jim") I get the following output:

"Hi, James" "What's your name?" "Jim" "Hi, Jimes"

What's happening here is the characters that weren't overwritten remain and get printed, as expected. What I'm wondering is how I may go about wiping the data in the .bss db between prompts?

Here is the code so far:

section .data
 question: db "What's your name?", 10
 answer: db "Hello, "
 ln db 10



section .bss
 name resb 16

section .text
global start
start:
    call prompt
    call getName
    mov rsi, answer
    mov rdx, 7
    call print
    mov rsi, name
    mov rdx, 10
    call print
    mov rsi, ln
    mov rdx, 1
    call print
    call loop_name

    mov rax, 0x02000001
    mov rdi, 0
    syscall

reset_name:

loop_name:
    mov cx, 3
    startloop:
        cmp cx, 0
        jz endofloop
        push cx
    loopy:
        call getName
        mov rsi, answer
        mov rdx, 7
        call print
        mov rsi, name
        mov rdx, 10
        call print

        pop cx
        dec cx
        jmp startloop
    endofloop:
   ; Loop ended
   ; Do what ever you have to do here
        ret

prompt:
    mov rax, 0x02000004
    mov rdi, 1
    mov rsi, question
    mov rdx, 18
    syscall

print:
    mov rax, 0x02000004
    mov rdi, 1
    syscall
    ret

getName:
    mov rax, 0x02000003 ; read
    mov rdi, 0
    mov rsi, name
    mov rdx, 37
    syscall
 ret

Any ideas? (Variable in question is name)

Jenna
  • 97
  • 7
  • You need to actually remember how long the strings are and pass that length to `print`. – fuz Oct 17 '20 at 10:44
  • Right, so is there a nice way of calculating the size of an input from a read sys call so I can pass that to my print call? – Jenna Oct 17 '20 at 10:45
  • The `read` system call tells you how much bytes it read. The last byte should be a line break, so subtract one from the count to get the input length. This gives you the length of the input. Technically, this may be incorrect if input is piped from somewhere else instead of coming from the terminal, but it's a good way to get started. – fuz Oct 17 '20 at 10:56
  • Thanks fuz, so I can grab the value stored in rax after the sys call to figure out how long the string was? Cool :D – Jenna Oct 17 '20 at 10:57
  • Exactly! Just remember to account for the line feed character at the end. – fuz Oct 17 '20 at 11:14

1 Answers1

2

While I don't know the system calls you're using, we can do one of three things:

  • clear the entire variable before reusing it.
  • use and share an explicit length value to indicate how many bytes of it are valid
  • null terminate the string right after it is input

Using an explicit length value may involve someone placing a null terminator at the right point in time (e.g. just before printing).

The read operation should return to you a length that you can pass to someone else (e.g. as a pair pointer & length), or otherwise use immediately to null terminate the string.  If it doesn't, then use the first approach of clearing the entire variable before reusing it.

Typically, syscalls have return values, that indicate length on success or else negative values for failure.  In such case, you are ignoring both.

Erik Eidt
  • 23,049
  • 2
  • 29
  • 53
  • Specific sys calls are just read/write/exit (but for MacOS). How would I go about clearing the entire variable in ASM? – Jenna Oct 17 '20 at 10:44
  • You should not ignore the return value from the read calls. Use it to check for errors, and also on success, use it to null terminate the input, if you're going for null terminated strings (if you're not going for null terminated strings, then maintain the pointer & length as a pair to pass to other callers). Clearing the variable is a matter of writing zeros to every byte, and it is the worst of the three possible solutions, since the real problem is ignoring the return values from syscalls. – Erik Eidt Oct 17 '20 at 10:45
  • I'm super new to ASM, but where would the return value be stored after the sys call? Only ever really done Atmel Assembly which has specific registers for this kind of stuff – Jenna Oct 17 '20 at 10:47
  • Try `rax` for return values, that's pretty standard. – Erik Eidt Oct 17 '20 at 10:47
  • Cheers, I'll give it a go – Jenna Oct 17 '20 at 10:52
  • 1
    x86-64 MacOS call numbers happen to be mostly(?) the same as i386 Linux (*not* x86-64 Linux), ORed with `0x02000000` (for these kinds of system calls; apparently there are other categories with different high bits). Args passed as per x86-64 System V like x86-64 Linux, but with error return status in CF, to tell you whether RAX is a normal return value or an errno code. @Jenna. Also note that while you can directly use `syscall`, they're not actually *guaranteed* stable by Apple: [Where are the OSX (XNU) syscalls actually documented?](https://stackoverflow.com/q/53107045) – Peter Cordes Oct 17 '20 at 11:57
  • @Jenna: Also [basic assembly not working on Mac (x86\_64+Lion)?](https://stackoverflow.com/q/11179400) – Peter Cordes Oct 17 '20 at 11:59
  • 1
    @Erik: BTW, these are POSIX read / [write](https://man7.org/linux/man-pages/man3/write.3p.html) system calls, so explicit length. – Peter Cordes Oct 17 '20 at 12:00