Error when try move element of array to eax NASM - nasm

I write assembly code
section .data
mas dd 1, 2, 3, 4, 5
section .text
global start
start:
xor eax, eax
xor si, si
xor ecx, 20
sum:
push mas[si]
add ax, mas[si]
add esi, 4
cmp ecx, esi
jne sum
But when i compile i got error
test.asm:12: error: comma, colon, decorator or end of line expected after operand
test.asm:13: error: comma, colon, decorator or end of line expected after operand
What's a problem? NASM v 2.13

Related

How do I print out two-digit integers in ASM, ( Linux NASM x86_64 )

This is how to print out a number, but how do I print out 2 digit numbers?
section .data
num: db 9,10
section .text
global _start
_start:
mov rax,[num]
add rax,48
mov [num],al
mov rax,1
mov rdi,1
mov rsi,num
mov rdx,2
syscall
mov rax,60
mov rdi,0
syscall
This simply prints out 9, but if I make num 12 it gives me a '<'.
I believe it is printing out the ascii character for 60, which is '<'.
mov rax,[num]
Because num just holds a byte, better not read this as a qword. Use the movzx eax, byte [num] instruction. You don't need the movzx rax, byte [num] instruction because all writing to a dword register already zeroes the high dword anyway.
but how do I print out 2 digit numbers?
Next code can do just that, printing numbers from the range [10,99].
Note that there's a placeholder right in front of the newline.
section .data
num: db 12, 0, 10
section .text
global _start
_start:
movzx eax, byte [num] ; Value LT 100
xor edx, edx
mov ebx, 10
div ebx ; Quotient in EAX, Remainder in EDX
mov ah, dl
add ax, '00' ; Convert to ASCII
mov [num], ax ; Stores 'tens' followed by 'ones'
mov rax, 1
mov rdi, 1
mov rsi, num
mov rdx, 3 ; 3 instead of 2
syscall
For a general approach you could first study Displaying numbers with DOS. It explains the methodology, but of course you'll need to adapt the code to 64-bit.
Even better info is at https://stackoverflow.com/a/46301894.

Error in a string reversal program in emu8086

I tried a string reversal program, but emu8086 is showing me an error message
(12)offset calculation error
What is wrong with the line LEA DI,STR2+LEN-1 ?
DATA SEGMENT
STR1 DB 'HELLO'
LEN EQU $-STR1
STR2 DB 20 DUP(0)
DATA ENDS
CODE SEGMENT
ASSUME CS:CODE, DS:DATA, ES:DATA
START: MOV AX,DATA
MOV DS,AX
MOV ES,AX
LEA SI,STR1
LEA DI,STR2+LEN-1
MOV CX,LEN
UP: CLD
LODSB
STD
STOSB
LOOP UP
MOV AH,4CH
INT 21H
CODE ENDS
END START
I'm not using emu8086, but the following will correct your line 12:
mov di, offset STR2 + LEN - 1
The shorter way to obtain an address is writing mov si, offset STR1 (uses 3 bytes) instead of lea si, STR1 (uses 4 bytes).
The loop ends with the direction flag still set!
It will always be a good idea to have the direction flag cleared before invoking any system function:
...
LOOP UP
CLD ; Add this to clear direction flag
MOV AH,4CH ; DOS.Terminate
INT 21H
...

Swapping first and last characters of string results in seg fault

My goal is to swap the first character with the last character of the string some_str in x86-assembly.
Here is my attempt:
; assemble and link with:
; nasm -f elf32 -g test.asm && ld -melf_i386 test.asm.o -o test
section .text
global _start
extern printf
_start:
mov eax, some_str
_loop:
mov di, [eax + 4] ; ptr to end char
mov si, [eax] ; ptr to start char
mov dl, [di] ; DL = end char
mov al, [si] ; AL = start char
mov [si], dl ; start char = end char
mov [di], al ; end char = char 1
mov edx, len
mov ecx, eax
mov ebx, 1
mov eax, 4
int 0x80
ret
mov eax, 1
int 0x80
section .data
some_str db `abcd`, 0xa
len equ $ - some_str
For some reason I am oblivious to the lines:
mov dl, [di] ; DL = end char
mov al, [si] ; AL = start char
Causes the program to result in a segmentation fault.
The expected stdout is:
dbca
Actual stdout:
Segmentation fault (core dumped)`
Is there something I am missing? How do I correct this code to correctly swap the first and last character of some_str.
Your code seems to be doing something much more complicated than necessary. After mov eax, some_str, we have that eax points to one of the bytes that wants to be swapped, and eax+4 points to the other. So just load them into two 8-bit registers and then store them back the other way around.
mov eax, some_str
mov cl, [eax]
mov dl, [eax + 4]
mov [eax + 4], cl
mov [eax], dl
And you're done and can proceed to write out the result.
Note it isn't necessary to load the pointer into eax first; you could also do
mov cl, [some_str]
mov dl, [some_str + 4]
mov [some_str + 4], cl
mov [some_str], dl
If you really wanted to have two different registers to point to the two different bytes: first of all, they need to be 32-bit registers. Trying to address memory in 32-bit mode using 16-bit registers si, di is practically never going to work. Second, mov edi, [eax] would load edi with the contents of the memory at location eax, which is some bytes of your string, not a pointer. You'd want simply mov edi, eax. For the second one, you can use lea to do the arithmetic of an effective address calculation but keep the resulting pointer instead of doing a load. So I think the way to turn your code into something in the original (inefficient) spirit, but correct, would be
mov edi, eax
lea esi, [eax+4]
mov dl, [edi]
mov al, [esi]
mov [esi], dl
mov [edi], al

Strange Characters when printing a string in x86 assembly language?

My code is required to have a string that will be printed to the console, alongside a string length counting program that will count it instead of manually putting length of string in edx register. But i am getting strange characters printed right after the string is printed.
global _start
section .text
_start:
mov edi, message
call _strlen
mov edx, eax
mov eax, 4
mov ebx, 1
mov ecx, message
int 80h
mov eax, 1
mov ebx, 5
int 80h
section .data
message: db "My name is Stanley Hudson", 0Ah
_strlen:
push ebx
push ecx
mov ebx, edi
xor al, al
mov ecx, 0xffffffff
repne scasb ; REPeat while Not Equal [edi] != al
sub edi, ebx ; length = offset of (edi – ebx)
mov eax, edi
pop ebx
pop ecx
ret
Here is the output
strlen searches for a 0 byte terminating the string, but your string doesn't have one, so it goes until it does find a zero byte and returns a value that's too large.
You want to write
message: db "My name is Stanley Hudson", 0Ah, 0
; ^^^
Another bug is that your _strlen function is apparently in the .data section, because you didn't go back to section .text after your string. x86-32 doesn't have the NX bit so the .data section is executable and everything still works, but it's surely not what you intend.
To get rid of the special characters write the strlen function before the start process and create a new register for the newline character

Split string in assembly

I'm using a code for split a string with a delimiter, but it save me the "right side" and I need the "left side" of the word.
For example, if the input is 15,20,x, then the outputs should be:
15
20
x
But it show me:
15,20,x
20,x
x
This is the code that I'm using
split:
mov esi,edi
mov ecx, 0
not ecx
mov al, ','
cld
repne scasb
not ecx
lea eax, [ecx-1]
;push eax
mov eax, edi
call println ;Here is where I want to print the "left side"
;pop eax
xchg esi, edi
mov eax, esi
call length
mov edi, esi
mov ecx, eax
cmp ecx, 1
je fin
jg split
ret
fin:
ret
After repne scasb the contents of ECX has changed from -1 to -4, you need to NOT ECX and then DEC ECX to obtain ECX=2 (size of the member "15"). Then println ECX bytes of the text at ESI and repeat split: There is a rub: as the last member "x" is not terminated with comma, repne scasb will crash. You should limit ECX to the total size of input text prior to scan. I tried this variant with EuroAssembler:
; Assembled on Ubuntu with
; wine euroasm.exe split.asm
; Linked with
; ld split.obj -o split -e Main -m elf_i386
; Run with
; ./split
EUROASM
split PROGRAM Format=COFF, Entry=Main:
INCLUDE linapi.htm,cpuext32.htm ; Library which defines StdInput,StdOutput.
[.text]
Main: StdOutput ="Enter comma-separated members: "
StdInput aString ; Read aString from console, return number of bytes in ECX.
MOV EDI,aString ; Pointer to the beginning of text.
LEA EBX,[EDI+ECX] ; Pointer to the end of text.
split: MOV ESI,EDI ; Position of the 1st byte.
MOV ECX,EBX
SUB ECX,EDI ; How many bytes is left in unparsed substring.
JNA fin:
MOV AL,','
REPNE SCASB
MOV ECX,EDI
DEC ECX ; Omit the delimiter.
SUB ECX,ESI
StdOutput ESI, Size=ECX, Eol=Yes
JMP split:
fin: TerminateProgram
[.bss]
aString DB 256 * BYTE
ENDPROGRAM split
And it worked well:
./split
Enter comma-separated members: 15,20,x
15
20
x

Resources