I want to write an input validation, users can input name with whitespace, if it is null or exceed the maximum array length, it will jmp to the beginning. However, when the input is too long, \n would be left over the second turn, which means scanf_s would receive the value automatically in the second turn. So I imagine is there a method like Java fflush in the inline assembly language to clear keyboard input every turn? This is my code:
char inputName[] = "%20[^\n]";
char name[20];
int validNum;
_asm{
startInput:
lea eax, name
push eax
call scanf_s //this is the problem part
add esp, 8
computeLength:
lea ebx, name
...
inc validNum
cmp [ebx], '\0'
je validate
validate:
cmp validNum, 20
jg startInput
}
Related
I'm trying to write a function in x86 NASM assembly which reverses order of characters in a string passed as argument. I tried implementing it using stack but ended up getting error message
*** stack smashing detected ***: <unknown> terminated
Aborted (core dumped)
Code below:
section .text
global reverse
reverse:
push ebp ; epilogue
mov ebp, esp
mov eax, [ebp+8]
xor ecx, ecx ; ecx = 0
push ebx ; saved register
push_eax:
mov edx, [eax] ; edx = char at eax
test edx, edx
jz inc_eax ; if edx == 0, move eax pointer back and pop eax
push edx
inc eax
inc ecx ; counter + 1
jmp push_eax
inc_eax:
sub eax, ecx ; move eax back to beginning of string
mov ebx, ecx ; to move eax back at the end of function
pop_eax:
test ecx, ecx ; loop counter == 0
jz end
pop edx
mov [eax], edx ; char at eax = edx
inc eax ; eax++
dec ecx ; ecx--
jmp pop_eax
end:
sub eax, ebx
pop ebx ; saved register
mov esp, ebp
pop ebp
ret
C declaration:
extern char* reverse(char*);
I've read somewhere that you get this error when trying to for instance write something in an array that is longer than allocated but i don't see how would that function do it? Also when instead of using ebx at the end I manually move the pointer in eax back (string in C of length 9 -> sub eax, 9) I get the reversed string at the output followed by 2nd, 3rd and 4th char. (No matter the length of the string I declare in C). So for instanceinput: "123456789"
output: "987654321234" but that only happens when I move eax manually, using ebx like in the code above outputs some trash.
Peter's answer is the answer you are looking for. However, may I comment on the technique? Must you use the stack? Do you already know the length of the string, or must you calculate/find that yourself?
For example, if you already know the length of the string, can you place a pointer at the first and another at the end and simply exchange the characters, moving each pointer toward the center until they meet? This has the advantage of not assuming there is enough room on the stack for the string. In fact, you don't even touch the stack except for the prologue and epilogue. (Please note you comment that the epilogue is at the top, when it is an 'ending' term.)
If you do not know the length of the string, to use the above technique, you must find the null char first. By doing this, you have touched each character in the string already, before you even start. Advantage, it is now loaded in to the cache. Disadvantage, you must touch each character again, in essence, reading the string twice. However, since you are using assembly, a repeated scasb instruction is fairly fast and has the added advantage of auto-magically placing a pointer near the end of the string for you.
I am not expecting an answer by asking these questions. I am simply suggesting a different technique based on certain criteria of the task. When I read the question, the following instantly came to mind:
p[i] <-> p[n-1]
i++, n--
loop until n <= i
Please note that you will want to check that 'n' is actually greater than 'i' before you make the first move. i.e.: it isn't a zero length string.
If this is a string of 1-byte characters, you want movzx edx, byte [eax] byte loads and mov [eax], dl byte stores.
You're doing 4-byte stores, which potentially steps on bytes past the end of the array. You also probably overread until you find a whole dword on the stack that's all zero. test edx, edx is fine if you correctly zero-extended a byte into EDX, but loading a whole word probably resulted in overread.
Use a debugger to see what you're doing to memory around the input arg.
(i.e. make sure you aren't writing past the end of the array, which is probably what happened here, stepping on the buffer-overflow detection cookie.)
I'm having a bit of trouble reading to and from arrays in assembly.
It's a fairly simple program (albeit at this point, far from finished). All I'm trying to do at this point is read a string of (what we're assuming is numbers), converting it to a decimal number, and printing it. Here's what I've got so far. As of now, it prints str1. After you enter a number and hit enter, it prints str1 again and freezes. Can anyone offer some insight as to what all I'm doing wrong?
INCLUDE Irvine32.inc
.data
buffersize equ 80
buffer DWORD buffersize DUP (0)
str1 BYTE "Enter numbers to be added together. Press (Q) to Quit.", 0dh, 0ah,0;
str2 BYTE "The numbers entered were: ", 0dh, 0ah, 0
str3 BYTE "The total of numbers entered is: ", 0dh, 0ah, 0
error BYTE "Invalid Entry. Please try again.", 0dh, 0ah,0
value DWORD 0
.code
main PROC
mov edx, OFFSET str1
call Writestring
Input:
call readstring
mov buffer[edi], eax
cmp buffer[edi], 0
JL NOTDIGIT
cmp buffer[edi], 9
JG NOTDIGIT
call cvtDec
mov edx, buffer[edi]
call WriteString
jmp endloop
Notdigit:
mov edx, OFFSET error
call writestring
exit
cvtDec:
mov eax, buffer[edi]
AND eax,0Fh
mov buffer[edi],edx
ret
endloop:
main ENDP
END MAIN
First off, Mr. Irvine created the function called WriteString, but you use 2 variations - writestring and Writestring; you do use the correct case of the function in one place. Get into the habit of using the correct names of functions now, and it will cut down on bugs later.
Second, you created a label called Notdigit but yet you use JL NOTDIGIT and JG NOTDIGIT in your code. Again, use the correct spelling. MASM should of given you an A2006 error "undefined symbol"
You also declared your entry point as main, but you close your code section with END MAIN instead of END main.
If you have MASM set up properly (by adding option casemap:none at the top of your source. Or just open irvine32.inc and uncomment the line that says OPTION CASEMAP:NONE)
Let's look at the ReadString procedure comment in irvine32.asm:
; Reads a string from the keyboard and places the characters
; in a buffer.
; Receives: EDX offset of the input buffer
; ECX = maximum characters to input (including terminal null)
; Returns: EAX = size of the input string.
; Comments: Stops when Enter key (0Dh,0Ah) is pressed. If the user
; types more characters than (ECX-1), the excess characters
; are ignored.
ReadString takes an address of the buffer to hold the inputed string in edx, you are using the address of your prompt str1, maybe you meant to use buffer? You also did not put the size of the buffer into ecx
Your using edi as an index into your buffer, what value does edi contain? Your trying to put the value of eax into it, what does eax contain??? Both edi and eax probably contain garbage; not what you want.
Look at this carefully:
cvtDec:
mov eax, buffer[edi]
AND eax,0Fh
mov buffer[edi],edx
Your putting a value (That you think is an ASCII value of a number) into eax then converting to a decimal value... ok... Next, you are putting whatever is in edx back into your buffer. Is that what you want?
I am trying to write a program that will allow me to print multiple characters (strings of characters or integers). The problem that I am having is that my code only prints one of the characters, and then newlines and stays in an infinite loop. Here is my code:
SECTION .data
len EQU 32
SECTION .bss
num resb len
output resb len
SECTION .text
GLOBAL _start
_start:
Read:
mov eax, 3
mov ebx, 1
mov ecx, num
mov edx, len
int 80h
Point:
mov ecx, num
Print:
mov al, [ecx]
inc ecx
mov [output], al
mov eax, 4
mov ebx, 1
mov ecx, output
mov edx, len
int 80h
cmp al, 0
jz Exit
Clear:
mov eax, 0
mov [output], eax
jmp Print
Exit:
mov eax, 1
mov ebx, 0
int 80h
Could someone point out what I am doing wrong?
Thanks,
Rileyh
In the first time you enter the Print section, ecx is pointing to the start of the string and you use it to copy a single character to the start of the output string. But a few more instructions down, you overwrite ecx with the pointer to the output string, and never restore it, therefore you never manage to copy and print the rest of the string.
Also, why are you calling write() with a single character string with the aim to loop over it to print the entire string? Why not just pass num directly in instead of copying a single character to output and passing that?
In your last question, you showed message as a zero-terminated string, so cmp al, 0 would indicate the end of the string. sys_read does NOT create a zero-terminated string! (we can stuff a zero in there if we need it - e.g. as a filename for sys_open) sys_read will read a maximum of edx characters. sys_read from stdin returns when, and only when, the "enter" key is hit. If fewer than edx characters were entered, the string is terminated with a linefeed character (10 decimal or 0xA or 0Ah hex) - you could look for that... But, if the pesky user types more than edx characters, only edx characters go into your buffer, the "excess" remains in the OS's buffer (and can cause trouble later!). In this case your string is NOT terminated with a linefeed, so looking for it will fail. sys_read returns the number of characters actually read - up to edx - including the linefeed - in eax. If you don't want to include the linefeed in the length, you can decrement eax.
As an experiment, do a sys_read with some small number (say 4) in edx, then exit the program. Type "abcdls"(enter) and watch the "ls" be executed. If some joker typed "abcdrm -rf ."... well, don't!!!
Safest thing is to flush the OS's input buffer.
mov ecx, num
mov edx, len
mov ebx, 1
mov eax, 3
int 80h
cmp byte [ecx + eax - 1], 10 ; got linefeed?
push eax ; save read length - doesn't alter flags
je good
flush:
mov ecx, dummy_buf
mov edx, 1
mov ebx, 1
mov eax, 3
int 80h
cmp byte [ecx], 10
jne flush
good:
pop eax ; restore length from first sys_read
Instead of defining dummy_buf in .bss (or .data), we could put it on the stack - trying to keep it simple here. This is imperfect - we don't know if our string is linefeed-terminated or not, and we don't check for error (unlikely reading from stdin). You'll find you're writing much more code dealing with errors and "idiot user" input than "doing the work". Inevitable! (it's a low-level language - we've gotta tell the CPU Every Single Thing!)
sys_write doesn't know about zero-terminated strings, either! It'll print edx characters, regardless of how much garbage that might be. You want to figure out how many characters you actually want to print, and put that in edx (that's why I saved/restored the original length above).
You mention "integers" and use num as a variable name. Neither of these functions know about "numbers" except as ascii codes. You're reading and writing characters. Converting a single-digit number to and from a character is easy - add or subtract '0' (48 decimal or 30h). Multiple digits are more complicated - look around for an example, if that's what you need.
Best,
Frank
If I had a string declared like this:
message db "ABCDEFGHIJ",0
how could I create a pointer that would allow me to point to a specific character in this string, such as the 'A' character. And also, how could I create a loop that would allow me to increment the pointer and as a result, cycle through the entire string?
mov ecx, message ; Masm would use "offset"
top:
mov al, [ecx] ; get a character
inc ecx ; get ready for next one
cmp al, 0 ; end of string?
jz done
; do something intelligent with al
jmp top
done:
I'm trying to make a program using NASM that takes input from command line arguments. Since string length is not provided, I'm trying to make a function to compute my own. Here is my attempt, which takes a pointer to a string in the ebx register, and returns the length of the string in ecx:
len:
push ebx
mov ecx,0
dec ebx
count:
inc ecx
inc ebx
cmp ebx,0
jnz count
dec ecx
pop ebx
ret
My method is to go through the string, character by character, and check if it's null. If it's not, I increment ecx and go to the next character. I believe the problem is that cmp ebx,0 is incorrect for what I'm trying to do. How would I properly go about checking whether the character is null? Also, are there other things that I could be doing better?
You are comparing the value in ebx with 0 which is not what you want. The value in ebx is the address of a character in memory so it should be dereferenced like this:
cmp byte[ebx], 0
Also, the last push ebx should be pop ebx.
Here is how I do it in a 64-bit Linux executable that checks argv[1]. The kernel starts a new process with argc and argv[] on the stack, as documented in the x86-64 System V ABI.
_start:
pop rsi ; number of arguments (argc)
pop rsi ; argv[0] the command itself (or program name)
pop rsi ; rsi = argv[1], a pointer to a string
mov ecx, 0 ; counter
.repeat:
lodsb ; byte in AL
test al,al ; check if zero
jz .done ; if zero then we're done
inc ecx ; increment counter
jmp .repeat ; repeat until zero
.done:
; string is unchanged, ecx contains the length of the string
; unused, we look at command line args instead
section .rodata
asciiz: db "This is a string with 36 characters.", 0
This is slow and inefficient, but easy to understand.
For efficiency, you'd want
only 1 branch in the loop (Why are loops always compiled into "do...while" style (tail jump)?)
avoid a false dependency by loading with movzx instead of merging into the previous RAX value (Why doesn't GCC use partial registers?).
subtract pointers after the loop instead of incrementing a counter inside.
And of course SSE2 is always available in x86-64, so we should use that to check in chunks of 16 bytes (after reaching an alignment boundary). See optimized hand-written strlen implementations like in glibc. (https://code.woboq.org/userspace/glibc/sysdeps/x86_64/strlen.S.html).
Here how I would have coded it
len:
push ebx
mov eax, ebx
lp:
cmp byte [eax], 0
jz lpend
inc eax
jmp lp
lpend:
sub eax, ebx
pop ebx
ret
(The result is in eax). Likely there are better ways.