How to Ignore Line Breaks in Input Using Nasm Assembly

How to ignore enter-key NASM win32

I figured out

I just wrote the code that removes 0x0d and 0x0a from the string

    mov ecx,11; str len(and num of loop iterations)
mov eax,string
jmp ignore_enter
change_byte:
mov bl,0
mov byte[eax+ecx],bl;change byte to 0
ignore_enter:
cmp byte[eax+ecx], 0x0a; compare ecx byte of string with 0x0a
je change_byte; if equal change_byte
cmp byte[eax+ecx], 0x0D; compare ecx byte of string with 0x0d
je change_byte; if equal change_byte
loop ignore_enter

Remove Trailing Line-Breaking Characters from Read Input in Assembly

this isn't particulary elegant or efficient, but it might provide a starting point:

jcomeau@intrepid:/tmp$ cat test.nasm ; nasm -f elf -o test.o test.nasm; ld -o test test.o; ./test
section .bss
input: resb 255
.len: equ $ - input

section .text
global _start

_start:
;; Display message prompting for input, then...
mov edx, input.len
mov ecx, input
mov ebx, 0
mov eax, 3
int 0x80 ;read in from stdin
call rstrip
mov edx, eax ;count
mov ebx, 1 ;stdout
mov eax, 4
int 0x80 ;write out
mov eax, 1
xor ebx, ebx
int 0x80
rstrip:
dec eax ;convert 1-based length to 0-based pointer
.loop:
cmp byte [ecx + eax], 0xa
je .chop
cmp byte [ecx + eax], 0xc
je .chop
cmp byte [ecx + eax], 0xd
je .chop
.done:
inc eax ;convert pointer back to length
ret
.chop:
mov byte [ecx + eax], 0
dec eax
jns .loop
jmp .done
this is a test
this is a testjcomeau@intrepid:/tmp$

Change end of line character for user input in assembly

Assuming you're talking about Linux or OS X system calls for reading input from a Unix TTY, the normal way is to put the TTY in raw mode with ioctl so you see every character as its typed, no line-editing.

But you can also set the TTY's eol (end of line) character. e.g. from the command line,

stty eol =

You can test it with cat and see that = (as well as newline) submit your buffered text to the kernel so cat sees it and prints it.

Use strace to see what system calls stty uses to do that. It's ioctl(0, TCGETS, { stuf ...}) = 0

(The stty sane and/or reset shell commands will reset your terminal settings back to normal after playing with stuff.)

Nasm print to next line

You have all the info already, you just don't see it yet:

resMsg db "Result: ", 0xA, 0xD

Do you know what this means exactly? It defines a string made of the following characters:

Result: XY

...where X and Y are actually invisible characters (with numerical values 0xA=10 and 0xD=13, also known as line feed (LF) and carriage return (CR)) which cause the output to wrap to a new line. They are specified outside of the doublequotes because of their invisible nature - you can't just include them there so you have to write their numerical values instead.

But of course you can use them alone as well:

newLineMsg db 0xA, 0xD
newLineLen equ $-newLineMsg

(newLineLen will be 2 of course but I left it here to keep the system the same as you currently use, for easier understanding.)

So to just output a line break without any other text (what you want to do after the 5), you can then use:

mov edx, newLineLen
mov ecx, newLineMsg
mov ebx, 1
mov eax, 4
int 0x80

...just like with resMsg/resLen.


However, as Jester pointed out, on Linux you should also be able to output just a single line feed (0xA) (and also remove the existing 0xD's from your code).

NASM x86_64 Remove new line character and add 0 at the end of string

read returns the number of characters, so you can index into the buffer and check if the last one read is a newline. Or just unconditionally overwrite it with 0 with this:

...
syscall ; rax = sys_read(0, buf, max_len)
mov byte [rsi + rax - 1], 0

That assumes no error and that the input string was submitted with a newline instead of EOF.

(Linux syscalls preserve all regs except RAX (return value), and RCX/R11, so RSI still holds name.)

x86 NASM Assembly - Problems with Input

Apart from what @Joshua is pointing out, you're not comparing your strings correctly.

checker:
mov ebx, check ; Moves the *address* of check into ebx
mov ecx, input ; Similarly for input
cmp ebx, ecx ; Checks if the addresses are the same (they never are)

Firstly, when you have e.g. label dd 1234 in your data segment mov eax, label will move the address of label to eax while mov eax, [label] will move the contents stored at label (in this case 1234) into eax.

Note that in the above example I deliberately used a 32-bit variable so that it would fit neatly into eax. If you're using byte sized variables (like ascii characters) e.g. mybyte db 0xfe you'll either have to use byte sized register (al, ah, dh etc.) or use the move with zero/sign extend opcodes: movzx eax, byte [mybyte] will set eax to 254, while movsx eax, byte [mybyte] will set eax to -2 (0xfffffffe).

You also need to do a character by character comparison of the strings. Assuming you save the read string length (you really should be checking for negative return values - meaning errors) in input_len and check_len it could look something like:

    mov eax, [input_len]
cmp eax, [check_len]
jne loop ; Strings of different length, do loop again
mov ebx, check
mov ecx, input
.checkloop:
mov dl, [ebx] ; Read a character from check
cmp dl, [ecx] ; Equal to the character from input?
jne loop ; Nope, jump to `loop`
inc ebx ; Move ebx to point at next character in check
inc ecx ; and ecx to next character in input
dec eax ; one less character to check
jnz .checkloop ; done?

; the strings are equal if we reach this point in the code
jmp done

If you're interested in another way of doing this in fewer instructions look up rep cmpsb.

There are a few other problems in the code immediately following your checker code. The pop edx instruction (and the code following, down to the loop label) will not be execute as you're always jumping either to loop or done.

jne loop    ;if not the same go to input again
je done ;else go to the end
pop edx ; Will never be reached!

The reason you're getting funny characters is from newlineL: db $-newline This should be equ instead of db or you should replace mov edx, newlineL with movzx edx, byte [newlineL]. Since newlineL unlike the other *L names refers to a variable and not a constant equ mov edx, newlineL will use the address of the newlineL variable as the number of bytes to write, when you wanted it to be 1.

Nasm interrupt calls getting skipped and outputting multiple lines

I think what you've run into is the fact that sys_read (from stdin) doesn't return until it sees a linefeed (the "enter" key). Only the one character you're looking for goes into your buffer (Choice), the linefeed stays in the OS's buffer (call it the "keyboard buffer"). When the next sys_read comes along, it reads that linefeed into your next buffer (FirstOperand)... and carries on... Hilarity ensues!

The easy way to fix it would be to make those buffers resb 2 and make edx 2, and trust the user to enter only one key and then "enter"... each time... Then studiously ignore the second byte in each buffer.

A better way might be to "flush the buffer" - the OS's keyboard buffer, not the buffer you've just read into. When sys_read returns, the number read is in eax. If it's less than edx, you should be good (it won't be, in this case). If it's equal (it shouldn't be greater), check to see if the last character is that linefeed. If it is, you're good. If not, there's more cruft in the OS's buffer (which will screw up your next sys_read!). Read into a "dummy" buffer (in .bss or on the stack), a byte at a time, until you find that linefeed - cmp byte [dummybuf], 0Ah or so. Then you're ready to continue...

Such are the joys of raw sys_call programming. :)

You don't ask, but mov [Answer], eax could be asking for trouble. This will write to your one-byte buffer... and the three bytes after it! There's nothing after it, and it isn't butted up against memory you don't "own", so it won't cause a problem right now, but it's a "bug waiting to happen". Either use al (should work here), or make Answer resd so it'll fit all of eax

This isn't going to give you the answer you expect. You need to subtract '0' (or 30h or 48) from each operand before you do arithmetic on 'em, and then add '0' back to the answer before you print it. With nore than one digit, it's even worse! Get the interrupts working as intended first.

Assembly x86 NASM - Avoid read return key

One option is to flush the stdin buffer:

section .data
opA: db 0
opB: db 0
LF: db 10

section .text
global _start
_start:

inputA:
mov EAX, 3
mov EBX, 0
mov ECX, opA
mov EDX, 1
int 80h

mov eax,54 ; kernel function SYS_IOCTL
mov ebx,0 ; EBX=0: STDIN
mov ecx,0x540B ; ECX=0x540B: TCFLSH
xor edx, edx ; EDX=0: TCIFLUSH
int 0x80 ; sys_call

inputB:
mov EAX, 3
mov EBX, 0
mov ECX, opB
mov EDX, 1
int 80h

mov eax,54 ; kernel function SYS_IOCTL
mov ebx,0 ; EBX=0: STDIN
mov ecx,0x540B ; ECX=0x540B: TCFLSH
xor edx, edx ; EDX=0: TCIFLUSH
int 0x80 ; sys_call

print:
mov edx,3
mov ecx,opA
mov ebx,1
mov eax,4
int 0x80

exit:
mov eax, 1
mov ebx, 0
int 0x80

Another option - which works with pipes - is to read stdin until EOF or LF:

section .data
opA: db 0
opB: db 0
LF: db 10
dummy: db 0

section .text
global _start

reads:
.1: ; Loop
mov eax,3 ; kernel function SYS_READ
mov ebx, 0 ; EBX=0: STDIN
mov ecx, dummy ; dummy buffer
mov edx, 1 ; number of bytes to read
int 0x80 ; sys_call
test eax, eax ; EOF?
jz .2 ; yes: ok
mov al,[dummy] ; no: fetched character
cmp al, 10 ; character == LF ?
jne .1 ; no -> loop (i.e. fetch next character)
.2
ret

_start:

inputA:
mov EAX, 3
mov EBX, 0
mov ECX, opA
mov EDX, 1
int 80h

call reads

inputB:
mov EAX, 3
mov EBX, 0
mov ECX, opB
mov EDX, 1
int 80h

call reads

print:
mov edx,3
mov ecx,opA
mov ebx,1
mov eax,4
int 0x80

exit:
mov eax, 1
mov ebx, 0
int 0x80


Related Topics



Leave a reply



Submit