No memory source operand for crc32 in Delphi 11? [duplicate] - delphi

I am trying to assemble the code below using yasm. I have put 'here' comments where yasm reports the error "error: invalid size for operand 2". Why is this error happening ?
segment .data
a db 25
b dw 0xffff
c dd 3456
d dq -14
segment .bss
res resq 1
segment .text
global _start
_start:
movsx rax, [a] ; here
movsx rbx, [b] ; here
movsxd rcx, [c] ; here
mov rdx, [d]
add rcx, rdx
add rbx, rcx
add rax, rbx
mov [res], rax
ret

For most instructions, the width of the register operand implies the width of the memory operand, because both operands have to be the same size. e.g. mov rdx, [d] implies mov rdx, qword [d] because you used a 64-bit register.
But the same movsx / movzx mnemonics are used for the byte-source and word-source opcodes, so it's ambiguous unless the source is a register (like movzx eax, cl). Another example is crc32 r32, r/m8 vs. r/m16 vs. r/m32. (Unlike movsx/zx, its source size can be as wide as the operand-size.)
movsx / movzx with a memory source always need the width of the memory operand specified explicitly.
The movsxd mnemonic is supposed to imply a 32-bit source size. movsxd rcx, [c] assembles with NASM, but apparently not with YASM. YASM requires you to write dword, even though it doesn't accept byte, word, or qword there, and it doesn't accept movsx rcx, dword [c] either (i.e. it requires the movsxd mnemonic for 32-bit source operands).
In NASM, movsx rcx, dword [c] assembles to movsxd, but movsxd rcx, word [c] is still rejected. i.e. in NASM, plain movsx is fully flexible, but movsxd is still rigid. I'd still recommend using dword to make the width of the load explicit, for the benefit of humans.
movsx rax, byte [a]
movsx rbx, word [b]
movsxd rcx, dword [c]
Note that the "operand size" of the instruction (as determined by the operand-size prefix to make it 16-bit, or REX.W=1 to make it 64-bit) is the destination width for movsx / movzx. Different source sizes use different opcodes.
In case it's not obvious, there's no movzxd because 32-bit mov already zero-extends to 64-bit implicitly. movsxd eax, ecx is encodeable, but not recommended (use mov instead).
In AT&T syntax, you need to explicitly specify both the source and destination width in the mnemonic, like movsbq (%rsi), %rax. GAS won't let you write movsb (%rsi), %eax to infer a destination width (operand-size) because movsb/movsw/etc are the mnemonics for string-move instructions with implicit (%rsi), (%rdi) operands.
Fun fact: GAS and clang do allow it for things like movzb (%rsi), %eax as movzbl, but GAS only has extra logic to allow disambiguation (not just inferring size) based on operands when it's necessary, like movsd (%rsi), %xmm0 vs. movsd. (Clang12.0.1 actually does accept movsb (%rcx), %eax as movsbl, but GAS 2.36.1 doesn't, so for portability it's best to be explicit with sign-extension, and not a bad idea for zero-extension too.)
Other stuff about your source code:
NASM/YASM allow you to use the segment keyword instead of section, but really you're giving ELF section names, not executable segment names. Also, you can put read-only data in section .rodata (which is linked as part of the text segment). What's the difference of section and segment in ELF file format.
You can't ret from _start. It's not a function, it's your ELF entry point. The first thing on the stack is argc, not a valid return address. Use this to exit cleanly:
xor edi,edi
mov eax, 231
syscall ; sys_exit_group(0)
See the x86 tag wiki for links to more useful guides (and debugging tips at the bottom).

Related

Inline asm (32) emulation of move (copy memory) command

I have two two-dimensional arrays with dynamic sizes (guess that's the proper wording). I copy the content of first one into the other using:
dest:=copy(src,0,4*x*y);
// src,dest:array of array of longint; x,y:longint;
// setlength(both arrays,x,y); //x and y are max 15 bit positive!
It works. However I'm unable to reproduce this in asm. I tried the following variations to no avail... Could someone enlighten me...
MOV ESI,src; MOV EDI,dest; MOV EBX,y; MOV EAX,x; MUL EBX;
PUSH DS; POP ES; MOV ECX,EAX; CLD; REP MOVSD;
Also tried with LEA (didn't expect that to work since it should fetch the pointer address not the array address), no workie, and tried with:
p1:=#src[0,0]; p2:=#dest[0,0]; //being no-type pointers
MOV ESI,p1; MOV EDI,p2... (the same asm)
Hints pls? Btw it's delphi 6. The error is, of course, access violation.
This is really a two-fold three-fold question.
What's the structure of a dynamic array.
Which instructions in asm will copy the array.
I'm throwing random assembler at the CPU, why doesn't it work?
Structure of a dynamic array
See: http://docwiki.embarcadero.com/RADStudio/Seattle/en/Internal_Data_Formats
To quote:
Dynamic Array Types
On the 32-bit platform, a dynamic-array variable occupies 4 bytes of memory (and 8 bytes on 64-bit) that contain a pointer to the dynamically allocated array. When the variable is empty (uninitialized) or holds a zero-length array, the pointer is nil and no dynamic memory is associated with the variable. For a nonempty array, the variable points to a dynamically allocated block of memory that contains the array in addition to a 32-bit (64-bit on Win64) length indicator and a 32-bit reference count. The table below shows the layout of a dynamic-array memory block.
Dynamic array memory layout (32-bit and 64-bit)
Offset 32-bit -8 -4 0
Offset 64-bit -12 -8 0
contents refcount count start of data
So the dynamic array variable is a pointer to the middle of the above structure.
How do I access this in asm
Let's assume the array holds records of type TMyRec
you'll need to run this code for every inner array in the outer array to do the deep copy. I leave this as an exercise for the reader. (you can do the other part in pascal).
type
TDynArr: array of TMyRec;
procedure SlowButBasicMove(const Source: TDynArr; var dest);
asm
//insert register pushes, see below.
mov esi,Source //esi = pointer to source data
mov edi,Dest //edi = pointer to dest
sub esi,8
mov ebx,[esi] //ebx = refcount (just in case)
mov ecx,[esi+4] //ecx = element count
mov edx,SizeOf(TMyRec) //anywhere from 1 to zillions
mul ecx,edx //==ecx=number of bytes in array.
//// now we can start moving
xor ebx,ebx //ebx =0
add eax,8 //eax = #data
#loop:
mov eax,[esi+ebx] //Get data from source
mov [edi+ebx],esi //copy it to dest
add ebx,4 //4 bytes at a time
cmp ebx,ecx //is ebx> number of bytes?
jle loop
//Done copying.
//insert register pops, see below
end;
That's the copy done, however in order for the system not to crash, you need to save and restore the non volatile registers (all but EAX, ECX, EDX), see: http://docwiki.embarcadero.com/RADStudio/Seattle/en/Program_Control
push ebx
push esi
push edi
--- insert code shown above
//restore non-volatile registers
pop edi
pop esi
pop ebx //note the restoring must happen in the reverse order of the push.
See the Jeff Dunteman's book assembly step by step if you're completely new to asm.
You will get access violations if:
you try to read from a wrong address.
you try to write to a wrong adress.
you read past the end of the array.
you write to memory you haven't claimed before using GetMem or whatever means.
if you write past the end of your buffer.
if you do not restore all non-volatile registers
Remember you're directly dealing with the CPU. Delphi will not assist you in any way.
Really fast code will use some form of SSE to move 16bytes per instruction in an unrolled loop, see the above mentioned fastcode for examples of optimized assembler.
Random assembler
In assembler you need to know exactly what you're what to do, how and what the CPU does.
Set a breakpoint and run your code. Press ctrl + alt + C and behold the CPU-debug window.
This will allow you to see the code Delphi generates.
You can single step through the code to see what the CPU does.
see: http://www.plantation-productions.com/Webster/index.html
For more reading.
Dynamic Arrays differ from Static Arrays, especially when it comes to multi-dimensionality.
Refer to this reference for internal formats.
The point is that an Array Of Array Of LongInt of dimensions X and Y (in this order!) is a pointer to an array of X pointers that point to an array of Y LongInts.
Since it seems, from your comments, that you have already allocated the space for all elements in Dest, I assume you want to do a Deep Copy.
Here a sample program, where the assembly as been made as simple as possible for the sake of clarity.
Program Test;
Var Src, Dest: Array Of Array Of LongInt;
X, Y, I, J: Integer;
Begin
X := 4;
Y := 2;
setLength(Src, X, Y);
setLength(Dest, X, Y);
For I := 0 To X-1 Do
For J := 0 To Y-1 Do
Src[I,J] := I*Y + J;
{$ASMMODE intel}
Asm
cld ;Be sure movsd increments the registers
mov esi, DWORD PTR [Src] ;Src pointer
mov edi, DWORD PTR [Dest] ;Dest pointer
mov ecx, DWORD PTR [X] ;Repeat for X times
;The number of elements in Src
#_copy:
push esi ;Save these for later
push edi
push ecx
mov ecx, DWORD PTR [Y] ;Repeat for Y times
;The number of element in a Src[i] array
mov edi, DWORD PTR [edi] ;Get the pointer to the Dest[i] array
mov esi, DWORD PTR [esi] ;Get the pointer to the Src[i] array
rep movsd ;Copy sub array
pop ecx ;Restore
pop edi
pop esi
add esi, 04h ;Go from Src[i] to Src[i+1]
add edi, 04h ;Go from Dest[i] to Dest[i+1]
loop #_copy
End;
For I := 0 To X-1 Do
Begin
WriteLn();
For J := 0 To Y-1 Do
Begin
Write(' ');
Write(Dest[I,J]);
End;
End;
End.
Note 1 This source code is intended to be compile with freepascal.
Donation of Spare Time(TM) for downloading and installing Delphi are welcome!
Note 2 This source code is for illustration purpose only, it is pretty obvious, it has already been stated above, but somehow not everybody got it.
If the OP wanted a fast way to copy the array, they should have stated so.
Note 3 I don't save the clobbered registers, this is bad practice, my bad; I forgot, as there are no subroutines, no optimizations and no reason for the compiler to pass data in the registers between the two fors.
This is left as an exercise to the reader.

assign memory location to register assembly

Let's say for example I have four specific memory addresses that each hold a 32-bit integer. How would you use assembly language to take the address and assign it register %eax?
Would it be movl 0x12AED567, %eax?
Yes, it is that simple. If you already have the addresses, just assign them to eax, I corrected your code a little :
mov 12AED567h, eax
But, if you want to get the addresses dynamically, you have to use lea instruction, next little program shows how :
.stack 100h
.data
my_number dd A01Ch
.code
;INITIALIZE DATA SEGMENT.
mov ax,#data
mov ds,ax
;GET THE MEMORY ADDRESS OF MY_NUMBER, NOT THE NUMBER ITSELF.
lea eax, my_number
;FINISH THE PROGRAM PROPERLY.
mov ax,4c00h
int 21h
Is this what you were looking for?
By the way, this is 8086 assembler with Intel's syntax.

FLD instruction x64 bit

I have a little problem with FLD instruction in x64 bit ...
want to load Double value to the stack pointer FPU in st0 register, but it seem to be impossible.
In Delphi x32, I can use this code :
function DoSomething(X:Double):Double;
asm
FLD X
// Do Something ..
FST Result
end;
Unfortunately, in x64, the same code does not work.
Delphi inherite Microsoft x64 Calling Convention.
So if arguments of function/procedure are float/double, they are passed in XMM0L, XMM1L, XMM2L, and XMM3L registers.
But you can use var before parameter as workaround like:
function DoSomething(var X:Double):Double;
asm
FLD qword ptr [X]
// Do Something ..
FST Result
end;
In x64 mode floating point parameters are passed in xmm-registers. So when Delphi tries to compile FLD X, it becomes FLD xmm0 but there is no such instruction. You first need to move it to memory.
The same goes with the result, it should be passed back in xmm0.
Try this (not tested):
function DoSomething(X:Double):Double;
var
Temp : double;
asm
MOVQ qword ptr Temp,X
FLD Temp
//do something
FST Temp
MOVQ xmm0,qword ptr Temp
end;
You don't need to use legacy x87 stack registers in x86-64 code, because SSE2 is baseline, a required part of the x86-64 ISA. You can and should do your scalar FP math using addsd, mulsd, sqrtsd and so on, on XMM registers. (Or addss for float)
The Windows x64 calling convention passes float/double FP args in XMM0..3, if they're one of the first four args to the function. (i.e. the 3rd total arg goes in xmm2 if it's FP, rather than the 3rd FP arg going in xmm2.) It returns FP values in XMM0.
Only use x87 if you actually need 80-bit precision inside your function. (Instructions like fsin and fyl2x are not fast, and can usually be done just as well by normal math libraries using SSE/SSE2 instructions.
function times2(X:Double):Double;
asm
addsd xmm0, xmm0 // upper 8 bytes of XMM0 are ignored
ret
end
Storing to memory and reloading into an x87 register costs you about 10 cycles of latency for no benefit. SSE/SSE2 scalar instructions are just as fast, or faster, than their x87 equivalents, and easier to program for and optimize because you never need fxch; it's a flat register design instead of stack-based. (https://agner.org/optimize/). Also, you have 15 XMM registers.
Of course, you usually don't need inline asm at all. It could be useful for manually-vectorizing if the compiler doesn't do that for you.

x86 labels and LEA in GDB

I"m learning to code in x86 assembly (32-bit at the moment) and I'm struggling to understand the memory model completely. Particularly confusing is the semantics for labels, and the LEA instruction, and the layout of the executable. I wrote this sample program so i could inspect it running in gdb.
; mem.s
SECTION .data
msg: db "labeled string\n"
db "unlabeled-string\n"
nls: db 10,10,10,10,10,10,10,10
SECTION .text
global _start
_start:
; inspect msg label, LEA instruction
mov eax, msg
mov eax, &msg
mov eax, [msg]
; lea eax, msg (invalid instruction)
lea eax, &msg
lea eax, [msg]
; populate array in BSS section
mov [arr], DWORD 1
mov [arr+4], DWORD 2
mov [arr+8], DWORD 3
mov [arr+12], DWORD 4
; trying to print the unlabeled string
mov eax, 4
mov ebx, 1
lea ecx, [msg+15]
int 80H
mov eax, 1 ; exit syscall
mov ebx, 0 ; return value
int 80H
SECTION .bss
arr: resw 16
I've assembled and linked with:
nasm -f elf -g -F stabs mem.s
ld -m elf_i386 -o mem mem.o
GDB session:
(gdb) disas *_start
Dump of assembler code for function _start:
0x08048080 <+0>: mov $0x80490e4,%eax
0x08048085 <+5>: mov 0x80490e4,%eax
0x0804808a <+10>: mov 0x80490e4,%eax
0x0804808f <+15>: lea 0x80490e4,%eax
0x08048095 <+21>: lea 0x80490e4,%eax
0x0804809b <+27>: movl $0x1,0x8049110
0x080480a5 <+37>: movl $0x2,0x8049114
0x080480af <+47>: movl $0x3,0x8049118
0x080480b9 <+57>: movl $0x4,0x804911c
0x080480c3 <+67>: mov $0x4,%eax
0x080480c8 <+72>: mov $0x1,%ebx
0x080480cd <+77>: lea 0x80490f3,%ecx
0x080480d3 <+83>: int $0x80
0x080480d5 <+85>: mov $0x1,%eax
0x080480da <+90>: mov $0x0,%ebx
0x080480df <+95>: int $0x80
inspecting "msg" value:
(gdb) b _start
Breakpoint 1 at 0x8048080
(gdb) run
Starting program: /home/jh/workspace/x86/mem_addr/mem
(gdb) p msg
# what does this value represent?
$1 = 1700946284
(gdb) p &msg
$2 = (<data variable, no debug info> *) 0x80490e4
# this is the address where "labeled string" is stored
(gdb) p *0x80490e4
# same value as above (eg: p msg)
$3 = 1700946284
(gdb) p *msg
Cannot access memory at address 0x6562616c
# NOTE: 0x6562616c is ASCII values of 'e','b','a','l'
# the first 4 bytes from msg: db "labeled string"... little-endian
(gdb) x msg
0x6562616c: Cannot access memory at address 0x6562616c
(gdb) x &msg
0x80490e4 <msg>: 0x6562616c
(gdb) x *msg
Cannot access memory at address 0x6562616c
Stepping through one instruction at a time:
(gdb) p $eax
$4 = 0
(gdb) stepi
0x08048085 in _start ()
(gdb) p $eax
$5 = 134516964
0x0804808a in _start ()
(gdb) p $eax
$6 = 1700946284
(gdb) stepi
0x0804808f in _start ()
(gdb) p $eax
$7 = 1700946284
(gdb) stepi
0x08048095 in _start ()
(gdb) p $eax
$8 = 134516964
The array was populated with the values 1,2,3,4 as expected:
# before program execution:
(gdb) x/16w &arr
0x8049104 <arr>: 0 0 0 0
0x8049114: 0 0 0 0
0x8049124: 0 0 0 0
0x8049134: 0 0 0 0
# after program execution
(gdb) x/16w &arr
0x8049104 <arr>: 1 2 3 4
0x8049114: 0 0 0 0
0x8049124: 0 0 0 0
0x8049134: 0 0 0 0
I don't understand why printing a label in gdb results in those two values. Also, how can I print the unlabeled string.
Thanks in advance
Its somewhat confusing because gdb doesn't understand the concept of labels, really -- its designed to debug a program written in higher-level language (C or C++, generally) and compiled by a compiler. So it tries to map what it sees in the binary to high-level language concepts -- variables and types -- based on its best guess as to what is going on (in the absence of debug info from the compiler that tells it what is going on).
what nasm does
To the assembler, a label is value that hasn't been set yet -- it actually gets its final value when the linker runs. Generally, labels are used to refer to addresses in sections of memory -- the actual address will get defined when the linker lays out the final executable image. The assembler generates relocation records so that uses of the label can be set properly by the linker.
So when the assembler sees
mov eax, msg
it knows that msg is a label corresponding to an address in the data segment, so it generates an instruction to load that address into eax. When it sees
mov eax, [msg]
it generates an instruction to load 32-bits (the size of register eax) from memory at address of msg. In both cases, there will be a relocation generated so that the linker can plug in the final address msg ends up with.
(aside -- I have no idea what & means to nasm -- it doesn't appear anywhere in the documentation I can see, so I'm suprised it doesn't give an error. But it looks like it treats it as an alias for [])
Now LEA is a funny instruction -- it has basically the same format as a move from memory, but instead of reading memory, it stores the address it would have read from into the destination register. So
lea eax, msg
makes no sense -- the source is the label (address) msg, which is a (link time) constant and is not in memory anywhere.
lea eax, [msg]
works, as the source is in memory, so it sticks the address of the source into eax. This is the same effect as mov eax, msg. Most commonly, you only see lea used with more complex addressing modes, so that you can leverage the x86 AGU to do useful work other than just computing addresses. Eg:
lea eax, [ebx+4*ecx+32]
which does a shift and two adds in the AGU and puts the result into eax rather than loading from that address.
what gdb does
In gdb, when you type p <expression> it tries to evaluate <expression> to the best of its understanding of what the C/C++ compiler means for that expression. So when you say
(gdb) p msg
it looks at msg and says "that looks like a variable, so lets get the current value of that variable and print that". Now it knows that compilers like to put global variables into the .data segment, and that they create symbols for those variables with the same name as the varible. Since it sees msg in the symbol table as a symbol in the .data segment, it assumes that is what is going on, and fetches the memory at that symbol and prints it. Now it has no idea what TYPE that variable is (no debug info), so it guesses that it is a 32-bit int and prints it as that.
So the output
$1 = 1700946284
is the first 4 bytes of msg, treated as an integer.
For p &msg it understands you want to take the address of the variable msg, so it give the address from the symbol directly. When printing addresses, gdb prints the type information it has about those addresses, thus the "data variable, no debug info" that comes out with it.
If you want, you can use a cast to specify the type of something to gdb, and it will use that type instead of what it has guessed:
(gdb) p (char)msg
$6 = 108 'l'
(gdb) p (char [10])msg
$7 = "labeled st"
(gdb) p (char *)&msg
$8 = 0x80490e4 "labeled string\\nunlabeled-string\\n\n\n\n\n\n\n\n\n" <Address 0x804910e out of bounds>
Note in the latter case here, there's no NUL terminator on the string, so it prints out the entire data segment...
To print the unlabelled string with sys_write, you need to figure out the address
and length of string, which you almost have. For completeness you should also check the return value:
mov ebx, 1 ; fd 1 (stdout)
lea ecx, [msg+15] ; address
mov edx, 17 ; length
write_more:
mov eax, 4 ; sys_write
int 80H ; write(1, &msg[15], 17)
test eax, eax ; check for error
js error ; error, eax = -ERRNO
add ecx, eax
sub edx, eax
jg write_more ; only part of the string was written
Chris Dodd sez...
(aside -- I have no idea what & means to nasm -- it doesn't appear anywhere in the documentation I can see, so I'm suprised it doesn't give an error. But it looks like it treats it as an alias for [])
Oh, oh! You've discovered the secret syntax! "&" was added to Nasm (as an alias for "[]") per user request, a long time ago. It was never documented. Never removed, either. I'd stick with "[]". Being "undocumented", it might just disappear. Note that the meaning is almost "opposite" from what it means to gdb!
Might try "-F dwarf" instead of "-F stabs". It's supposed to be the "native" debugging info format used by gdb. (never noticed much difference, myself)
Best,
Frank
http://www.nasm.us

Create a pointer to a specific location

I need a pointer to location which is always the same. So, how can I create a pointer to.. lets say memory address 0x20 and store it in some way to be able to access it later.
Note:
I do NOT want to store the result, but the actual pointer to the memory address (since I want to point to the beginning of an array).
Thanks in advance.
--
I think I have fixed it now. I use bios interrupt 0x15 to get a memory map. Every interrupt returns 1 entry and you provide a pointer in es:di to a place where the bios can store it. I let the bios build it up from 050h:0h. I needed a pointer to 0x50:0x0 (0x500 linear) to use the map later. I still have to test, but I did the following:
mov ax, 0x50
mov es, ax
xor di, di
shl ax, 4
add ax, di
mov [mmr], ax
And mmr is declared this way:
mmr:
dw 0 ; pointer to the first entry
db 0 ;entry count
db 24 ; entry size
A pointer is just a memory address and a memory address is just a number. Assembly is not a typed language so there is no difference.
Also assembly doesn't really have variables. It has registers and memory locations, both of which can be used for storing values, including addresses/pointers.
So basically there are many variants of the x86 MOV instruction that can store a pointer such as 0x20 in an address or a register. You certainly want to think about whether you're doing 32-bit or 64-bit x86 assembly though (or 16-bit or even 8-bit for that matter).
x86:
suppose you have an array called list
mov bx, offset list
now, in the bx register you will have a pointer to the first memory location of list
to refer to the data in the memory location you would use [bx]
here's an brief example using intel syntax:
;declare list in .data
list dw 0123h
;move 01h from memory to ax register (16-bit)
mov bx, offset list
mov al, [bx] ; al = 23h
If you want to use the pointer later you can do this:
push bx then pop bx when you want to use it
or
mov point, bx ; declared in mmr

Resources