problem with a code "initializer magnitude too large for specified size" on assembler - messagebox

code works in the following way:it solves the following problem "2d/a-21bd". then it should open a message box, where the result is shown. here is the code:
;include \masm64\include64\masm64rt.inc
.data ;data for the code
a dq 1 ;operand a
b dq 0 ;operand b
c dq 21 ;number 21
d dq 5 ;operand d
q dq 2 ;number 2
res dq 0 ;result
title1 db "Решение уравнения. masm64",0 ;title for the message box
txt1 db "Уравнение 2d/a-21bd",10,
"Результат: %d",10,"Адрес переменной в памяти: %ph",10,10,
"Автор:Тарадай Святослав",0 ;text for the message box
buf1 dq 3 dup(0),0 ;sorry, i don't know what does this code do. if you can say, i'll be happy
.code ;code area. solving a problem 2d/a-21bd
entry_point proc
mov rax ,b ;moving operand b to rax to make a second part of a problem
mul c ;multiplying on 21
mul d ;multiplying on d, or 5
mov rsi, rax ;moving the result to rsi
mov rax,d ;moving operand d, or 5 to rax, making a first part of the problem
mul q ;multiplying on 2
xor rdx,rdx ;preparing rdx to division
div a ;division on a, or 1
sub rax,rsi ;substraction of rsi(21bd) from rax(2d/a)
mov res,rax ;moving result on res
invoke wsprintf,ADDR buf1,ADDR txt1,res, ADDR res1 ;transform function
invoke MessageBox,0,ADDR buf1,ADDR title1,MB_ICONINFORMATION ;output function
invoke ExitProcess,0
entry_point endp
end
but i've got following errors with the invoke thing:
Assembling: C:\masm64\bin64\a1.asm
C:\masm64\bin64\a1.asm(27) : error A2071:initializer magnitude too large for specified size
C:\masm64\bin64\a1.asm(27) : error A2008:syntax error : invokeC:\masm64\bin64\a1.asm(28) : error A2071:initializer magnitude too large for specified size
C:\masm64\bin64\a1.asm(28) : error A2008:syntax error : invokeC:\masm64\bin64\a1.asm(29) : error A2071:initializer magnitude too large for specified size
C:\masm64\bin64\a1.asm(29) : error A2008:syntax error : invokeLINK : fatal error LNK1181: cannot open input file 'C:\masm64\bin64\a1.obj'
if you can help me with this one, because i'm a new one in assembler, i'll be very happy

The problem was with the compilation.i used the makeit.bat wit RC. just changing it to simple makeit.bat solves the problem

Related

Cannot find segmentation fault in insertion sort code for arm-v8 assembly

I have generated an array of random integers between 0 and 256 and I tried to sort them using an insertion sort however at some point along the line I messed up and got an error "segmentation fault (core dumped)
I have no idea exactly why I am getting this but I believe the problem has something to do with the macro j representing a loop counter. I have been working away at this for a few hours and I have been stuck on this for a while.
EDIT: After using the debugger I have isolated the problem to be the line:
bl printf
right at the very end when it tries to print the second sorted value.
I have tried to allocate more ram up to 416 bytes, I have tried moving the top2 loop label around (which is the loop that uses j as it's counter) and the farthest i have gotten is for the program to print the first element of the sorted array and then give the error
ALLOC =-(16+400*1)&-16
.equ DEALLOC, -ALLOC
size = 50
define(arraybase, x19)
i .req x20
define(j, x21)
define(temp, w22)
define(sort1, w23)
print1: .asciz "Array[%d]: %d\n"
print2: .string "\nSorted Array: \n"
print3: .asciz "top value equals %d \n"
...
mov i, 0
top1: add i, i, 1
ldrb temp, [arraybase, i ]
mov j, i
top2: mov x25, j
sub x25, x25, 1
ldrb sort1, [arraybase, x25 ]
cmp temp, sort1
b.ge skip1
strb sort1, [arraybase, j]
skip1: sub j, j, 1
cmp j, 0
b.gt top2
strb temp, [arraybase, j]
cmp i, size-1
b.lt top1
printing:
ldr x0, =print2
bl printf
mov i, 0
ldr x0, =print1
tprint: mov x1, i
ldrb w2, [arraybase, i]
bl printf
add i, i, 1
cmp i, size-1
b.le tprint
mov x0, 0
ldp x29, x30, [sp], DEALLOC
ret
The array should be printed in the random order it was initialized in, then it should print the value at the top of the array, then it is meant to print the sorted array in increasing order.
The exact error message I got was:
Segmentation fault (core dumped)
This appears after it prints the first value of the sorted array

Two digit string number Assembly

So I have to strings s1 and s2 and I have two obtain the string d that contains the maximum numbers for each of the positions of s1 and s2.
For example:
S1: 1, 3, 6, 2, 3, 10
S2: 6, 3, 11, 1, 2, 5
D: 6, 3, 11, 2, 3, 10
So this is the code
bits 32
global start
extern exit,printf
import exit msvcrt.dll
import printf msvcrt.dll
segment data use32 class=data
format db "%s",0
s1 db "1","3","6","2","3","10"
l equ $-s1
s2 db "6","3" ,"11","1","2", "5"
d times l db 0
segment code use32 class=code
start:
mov esi,0
mov edi,0
cld
Repeta:
mov al,[s1+esi]
mov bl,[s2+esi]
cmp al,bl
jg et1
mov[d+edi],bl
inc edi
inc esi
jmp et2
et1:
mov[d+edi],al
inc edi
inc esi
et2:
cmp esi,l
jne Repeta
push d
push format
call[printf]
add esp,4*2
push dword 0
call [exit]
The problem is that when it reaches a double digit element(10 or 11) it takes only the first digit(1) and compares it with the number from the other string on the same position and after that it takes the second digit and compares it with the next number from the other string.
How can I solve this?
it says that it should be a string of bytes
The phrase "of bytes" very strongly implies array to me. Ask your instructor for clarification, but I think s1: db 1, 3, 6, 2, 3, 10 is what you're supposed to be working with, so the elements are fixed width single byte integers. (And not ASCII strings at all).
This means you can use a simple pairwise max like SSE2 pmaxub (for unsigned bytes) or SSE4.1 pmaxsb (for signed bytes).
segment data use32 class=data
format db "%s",0
s1 db 1, 3, 6, 2, 3, 10
l equ $-s1
s2 db 6, 3, 11, 1, 2, 5
d times l db 0
start:
movq xmm1, [s1] ; load all 6 elements, plus 2 bytes past the end but that's ok. We ignore those bytes
movq xmm2, [s2]
pmaxub xmm1, xmm2 ; element-wise vertical max
;but avoid storing outside of 6-byte d
movd [d], xmm1 ; store first 4 bytes of the result
pextrw [d+4], xmm1, 2 ; store bytes 4 and 5 (word 2 of xmm1 = 3rd word)
... ; the result isn't a string, you can't print it with printf.
For byte counts that aren't a multiple of 2, e.g. if l was 7, you could use this instead of pextrw:
psrldq xmm1, 3 ; bring the data you want to store down into the low 4 bytes of the register
movd [d+4], xmm1 ; 4-byte store that overlaps by 1
BTW, I realize that you're intended to loop over the elements 1 byte at a time. Maybe use cmp cl, al / cmovg eax, ecx / mov [edi], al to store what was originally in cl if cl > al (signed), otherwise store what was originally in al.
I think your loop structure is a bit broken, because you have one path that doesn't store to d. You always need to store to d, regardless of which source was greater.

Compare user-inputted string/character to another string/character

So I'm a bit of a beginner to ARM Assembly (assembly in general, too). Right now I'm writing a program and one of the biggest parts of it is that the user will need to type in a letter, and then I will compare that letter to some other pre-inputted letter to see if the user typed the same thing.
For instance, in my code I have
.balign 4 /* Forces the next data declaration to be on a 4 byte segment */
dime: .asciz "D\n"
at the top of the file and
addr_dime : .word dime
at the bottom of the file.
Also, based on what I've been reading online I put
.balign 4
inputChoice: .asciz "%d"
at the top of the file, and put
inputVal : .word 0
at the bottom of the file.
Near the middle of the file (just trust me that there is something wrong with this standalone code, and the rest of the file doesn't matter in this context) I have this block of code:
ldr r3, addr_dime
ldr r2, addr_inputChoice
cmp r2, r3 /*See if the user entered D*/
addeq r5, r5, #10 /*add 10 to the total if so*/
Which I THINK should load "D" into r3, load whatever String or character the user inputted into r2, and then add 10 to r5 if they are the same.
For some reason this doesn't work, and the r5, r5, #10 code only works if addne comes before it.
addr_dime : .word dime is poitlessly over-complicated. The address is already a link-time constant. Storing the address in memory (at another location which has its own address) doesn't help you at all, it just adds another layer of indirection. (Which is actually the source of your problem.)
Anyway, cmp doesn't dereference its register operands, so you're comparing pointers. If you single-step with a debugger, you'll see that the values in registers are pointers.
To load the single byte at dime, zero-extended into r3, do
ldrb r3, dime
Using ldr to do a 32-bit load would also get the \n byte, and a 32-bit comparison would have to match that too for eq to be true.
But this can only work if dime is close enough for a PC-relative addressing mode to fit; like most RISC machines, ARM can't use arbitrary absolute addresses because the instruction-width is fixed.
For the constant, the easiest way to avoid that is not to store it in memory in the first place. Use .equ dime, 'D' to define a numeric constant, then you can use
cmp r2, dime # compare with immediate operand
Or ldr r3, =dime to ask the assembler to get the constant into a register for you. You can do this with addresses, so you could do
ldr r2, =inputVal # r2 = &inputVal
ldrb r2, [r2] # load first byte of inputVal
This is the generic way to handle loading from static data that might be too far away for a PC-relative addressing mode.
You could avoid that by using a stack address (sub sp, #16 / mov r5, sp or something). Then you already have the address in a register.
This is exactly what a C compiler does:
char dime[4] = "D\n";
char input[4] = "xyz";
int foo(int start) {
if (dime[0] == input[0])
start += 10;
return start;
}
From ARM32 gcc6.3 on the Godbolt compiler explorer:
foo:
ldr r3, .L4 # load a pointer to the data section at dime / input
ldrb r2, [r3]
ldrb r3, [r3, #4]
cmp r2, r3
addeq r0, r0, #10
bx lr
.L4:
# gcc greated this "literal pool" next to the code
# holding a pointer it can use to access the data section,
# wherever the linker ends up putting it.
.word .LANCHOR0
.section .data
.p2align 2
### These are in a different section, near each other.
### On Godbolt, click the .text button to see full assembler directives.
.LANCHOR0: # actually defined with a .set directive, but same difference.
dime:
.ascii "D\012\000"
input:
.ascii "xyz\000"
Try changing the C to compare with a literal character instead of a global the compiler can't optimize into a constant, and see what you get.

Trouble With Reading In A String With A Subroutine In LC3

So I believe that the way I store the string works. I am just having some issues passing the String out of the subroutine. I heard that in order to pass something out of a subroutine you need to store it in R1 but I can't get it to store into my WORD array
.orig x3000
AND R1,R1,0
LEA R0,PROMPT
PUTS
JSR GETS
ST R1,WORD
LEA R0,WORD
PUTS
halt
; ---------Data Area-------------
WORD .blkw 20
PROMPT .stringz "Enter String: "
; -------------------------------
GETS LEA R1,MEMORYBLOCK ; saves the address of the storage memory block
loop GETC ; input character -> r0
PUTC ; r0 -> console
; always points at the next available block
LD R2,EMPTY ; check for
ADD R2,R2,R0 ; end of line
BRz finish
LD R2,COUNTDOWN
ADD R2,R2,#-1
BRz finish
ST R2,COUNTDOWN
STR R0,R1,#0 ; r0 -> ( memory address stored in r1 + 0 )
ADD R1,R1,#1 ; increments the memory pointer so that it
BR loop
finish LEA R1,MEMORYBLOCK
RET
; ----Subroutine Data Area-------
EMPTY .fill xfff6
COUNTDOWN .fill #10
MEMORYBLOCK .BLKW 20
; -------------------------------
.end
The biggest problem here is the concept of "returning a string". What you're actually doing at the end of GETS is returning the memory address at which the string starts. When you then store this into WORD in the calling function, you are storing the memory address of the first byte of the string that was input (i.e. the memory address of MEMORYBLOCK) into the first byte of WORD. You aren't copying the entire string from MEMORYBLOCK into WORD.
The easiest "fix" for what you're trying to do would be to change
LEA R0,WORD
to
LD R0,WORD
and then for good measure:
WORD .blkw 20
to
WORD .fill 0
as now you're just using it to store a single value (i.e. the memory address of MEMORYBLOCK).
However, at this point you haven't made a copy of the string. If you want to do this, then you will need to make a loop whereby you walk through MEMORYBLOCK and copy each byte to WORD instead.
The final, cheaper, way to do this is to just use MEMORYBLOCK directly from the calling function. It's not really any less valid in a program of this size, unless there's project requirements that ask otherwise.

Using relative values in array sorting ( asm )

I need to sort through an array and sort each individual row in array to be in ascending order. I doesn't seem to going so well (surprise!) as I keep getting hit with two errors:
a2101: cannot add two relocatable labels
and
a2026: constant expected
Here's my sort, it makes sense to me, but I think I'm still trying to implement high-lvl language techniqes into assembly. Is there a way to get around not being able to use relative values? (the array is 7 rows by 9 columns, btw).
mov cx, 7; cx = number of rows
outer: ; outer loop walk through the rows
push cx
mov cx, 9
mov row, cx ;rows
middle: ; middle-loop walk through the columns
push cx
sub cx, 1 ;cx = cx-1
mov column, cx ;columns
inner: ;inner loop - compare and exchange column values
cmp mArray[row*9 + column], mArray[row*9 + column+1]
xchg mArray[row*9 + column+1], mArray[row*9 + column]
; compare and exchange values from mArray table
inc column
loop inner
pop cx
loop middle ;end middle loop
pop cx
loop outer ; end outer loop
ret
Thanks for any help.
The following lines are problematic:
cmp mArray[row*9 + column], mArray[row*9 + column+1]
xchg mArray[row*9 + column+1], mArray[row*9 + column]
Unlike HLL, assembly does NOT allow for arbitrary expressions in place of constants or variables. That's why HLL's were invented in the first place. Calculate the offset in the registers before using:
mov ax, row
mov bx, ax
shr bx, 3 ; bx = row*8 now
add bx, ax ; bx = row*9 now
add bx, column ; bx = row*8+column now
mov dx, [bx] ;first comparand
inc bx
cmd dx, [bx] ; that's your compare!
Also, you don't use any branching; the cmp instruction is utterly pointless; you waste its result, and xcng is not executed conditionally. Read up on conditional jump commands (jz/jnz etc.).
Also, I seriously hope this is an exercise, not a real project. If it's for real, please reconsider using assembly. For something as trivial as this, assembly is a wrong, wrong choice. Espec. considering how bad you are at it.

Resources