convert memcpy() code from x86 to x64 platform - performance

this code is memcpy() on x86 platforms . but I need to memcpy() on x64 platform .
_asm {
mov esi, src
mov edi, dest
mov ecx, nbytes
shr ecx, 6 // 64 bytes per iteration
loop1:
movq mm1, 0[ESI] // Read in source data
movq mm2, 8[ESI]
movq mm3, 16[ESI]
movq mm4, 24[ESI]
movq mm5, 32[ESI]
movq mm6, 40[ESI]
movq mm7, 48[ESI]
movq mm0, 56[ESI]
movq 0[EDI], mm1 // Write to destination
movq 8[EDI], mm2
movq 16[EDI], mm3
movq 24[EDI], mm4
movq 32[EDI], mm5
movq 40[EDI], mm6
movq 48[EDI], mm7
movq 56[EDI], mm0
add esi, 64
add edi, 64
dec ecx
jnz loop1
emms
}
I have no knowledge of x64 assembly language .
how convert this code from x86 to x64 ?

I suppose replacing esi and edi with rsi and rdi should do the trick. Although it will not become faster (or fast).
Other than pointers, x64 is backwards compatible with x86.
In general better make a C loop or use the default memcpy. It will generate much better code.

Related

Finding the effective address of a label in GAS [duplicate]

This question already has answers here:
How to load address of function or label into register
(1 answer)
32-bit absolute addresses no longer allowed in x86-64 Linux?
(1 answer)
Closed 4 months ago.
I'm completing the final assignment for a compilers course and right now the deal is to translate some intermediate representation into x86_64 assembly source code and then build an executable through gcc by running
gcc output.s -o output
This executable should work properly. The issue is that I just can't get my code past GCC when it comes to (at least) one particular instruction. This is it:
mov L0, %rbx
Where L0 is a label.
The whole test file is as follows:
.text
.section .rodata
.text
.globl main
main:
// rbss for now
add $0, %rsp
mov %rsp, %rsi
// register spill area
add $0, %rsp
mov %rsp, %rdi
// store rax => rsp
mov %rax, %rcx
mov %rcx, ( %rsp )
// subI rsp, 4 => rsp
mov %rsp, %rcx
sub $4, %rcx
mov %rcx, %rsp
// lea L0 => rbx
mov L0, %rbx
// store rbp => rsp
mov %rbp, %rcx
mov %rcx, ( %rsp )
// subI rsp, 4 => rsp
mov %rsp, %rcx
sub $4, %rcx
mov %rcx, %rsp
// store rbx => rsp
mov %rbx, %rcx
mov %rcx, ( %rsp )
// subI rsp, 4 => rsp
mov %rsp, %rcx
sub $4, %rcx
mov %rcx, %rsp
// jumpI => Lmain
jmp Lmain
// L0 : halt
L0:
hlt
// Lmain : nop
Lmain:
// addI rsp, 0 => rbp
mov %rsp, %rcx
add $0, %rcx
mov %rcx, %rbp
// subI rsp, 0 => rsp
mov %rsp, %rcx
sub $0, %rcx
mov %rcx, %rsp
// addI rbp, 8 => rsp
mov %rbp, %rcx
add $8, %rcx
mov %rcx, %rsp
// loadAI rbp, 4 => rbp
mov %rdi, %rbx
add %rbp, %rbx
add $4, %rbx
mov ( %rbx ), %rcx
mov %rcx, %rbp
// jump => rbp
mov %rbp, %rbx
jmp *%rbx
Is there anything inherently mistaken about using mov this way? I'm not using call/ret semantics since the translation must be carried out directly from ILOC (a toy/education purpose) intermediate code.
When I try to run the aforementioned command I get some variation of:
/usr/bin/ld: /tmp/cccAoFmz.o: relocation R_X86_64_32S against `.text' can not be used when making a PIE object; recompile with -fPIE
collect2: error: ld returned 1 exit status
Could you guys help me to get a grasp of what's actually going on? I'm quite new to x86 programming and that's my first time with this kind of application. The whole assignment is done, my only issue is getting it to a working state (So no, huahuahua, I'm not getting you guys to do my homework :D).
Is there another way to get what I'm trying to achieve? Is my approach incorrect? I'm out of ideas right now.
Thank you so much :)
Best,

Correct usage of the RIP related addressing

I found example of code on assembly, which finds the maximum number in array named data_items but that example was for x86 and I tried to adapt it for x64 because 32 bit absolute addressing is not supported by 64 bit system.
To be short there are three actions:
lea data_items(%rip), %rdi #(1) Obtaining data_items address
add $4, %rdi #(2) Incrementing the pointer to 4 to read a next item
movl (%rdi), %eax #(3) Reading data at %rdi to %eax
The main questions:
Is it correct way to pointing? Can it produce error after code relocation?
If the %rip register constantly grows, why lea data_items(%rip), %rdi loads correct memory address? May be getting an offset by %rip have special meaning rather than "dataItems + %rip"?
Full adapted code here:
.section __DATA,__data
data_items:
.long 3,67,34,222,45,75,54,34,44,33,22,11,66,0
.section __TEXT,__text
.globl _main
_main:
lea data_items(%rip), %rdi #(1)
movl (%rdi), %eax
movl %eax, %ebx
start_loop:
cmpl $0, %eax
je loop_exit
add $4, %rdi #(2)
movl (%rdi), %eax #(3)
cmpl %ebx, %eax
jle start_loop
movl %eax, %ebx
jmp start_loop
loop_exit:
mov $0x2000001, %rax
mov $0, %rdi
syscall

Y86 Architecture Immediate VS Register Arithmetic Efficiency Question

I am working with a team in a Computer Architecture class on a Y86 program to implement multiplication function imul. We have a block of code that works, but we are trying to make it as execution-time efficient as we can. Currently our block looks like this for imul:
imul:
# push all used registers to stack for preservation
pushq %rdi
pushq %rsi
pushq %r8
pushq %r9
pushq %r10
irmovq 0, %r9 # set 0 into r9
rrmovq %rdi, %r10 # preserve rdi in r10
subq %rsi, %rdi # compare rdi and rsi
rrmovq %r10, %rdi # restore rdi
jl continue # if rdi (looping value/count) less than rsi, don't swap
swap:
# swap rsi and rdi to make rdi smaller value of the two
rrmovq %rsi, %rdi
rrmovq %r10, %rsi
continue:
subq %r9, %rdi # check if rdi is zero
cmove %r9, %rax # if rdi = 0, rax = 0
je imulDone # if rdi = 0, jump to end
irmovq 1, %r8 # set 1 into r8
rrmovq %rsi, %rax # set rax equal to initial value from rsi
imulLoop:
subq %r8, %rdi # count - 1
je imulDone # if count = 0, jump to end
addq %rsi, %rax # add another instance of rsi into rax, looped adition
jmp imulLoop # restart loop
imulDone:
# pop all used registers from stack to original values and return
popq %r10
popq %r9
popq %r8
popq %rsi
popq %rdi
ret
Right now our best idea is using immediate arithmetic instructions (isubq, etc) instead of normal OPq instructions with settings constants into registers and using those registers. Would this method be meaningfully more efficient in this particular instance? Thanks so much!

What is wrong with my implementation of the Lisp "cons" function?

I am trying to make the Lisp function cons in x86_84 assembly on MacOS. Below I am trying to make a pair of 2 and 3, but it is not working; I am getting a segmentation fault.
.global _main
.extern _malloc
.text
.macro make_node register
mov rdi, 8 # 64-bit number
call _malloc # failed on malloc
mov [rax], \register # contents of register in address of rax
mov \register, [rax]
.endm
cons:
push rbp
mov rbp, rsp
mov r8, [rbp + 16]
make_node r8
mov r9, [rbp + 24]
make_node r9
mov rsp, rbp
pop rbp
ret
_main:
push 3
push 2
call cons
add rsp, 16
# I should now be able to do whatever I want with r8 (2) and r9 (3)
mov rdi, 0
mov rax, 0x2000001
syscall
I stepped through it with GDB and I see that it failed on calling malloc, but to me, there doesn't seem to be a problem since malloc only takes one argument (the number of bytes to allocate) in the rdi register.
Dump of assembler code for function cons:
0x0000000100003f48 <+0>: push %rbp
0x0000000100003f49 <+1>: mov %rsp,%rbp
0x0000000100003f4c <+4>: mov 0x10(%rbp),%r8
0x0000000100003f50 <+8>: mov $0x8,%rdi
=> 0x0000000100003f57 <+15>: callq 0x100003f96
0x0000000100003f5c <+20>: mov %r8,(%rax)
0x0000000100003f5f <+23>: mov (%rax),%r8
0x0000000100003f62 <+26>: mov 0x18(%rbp),%r9
0x0000000100003f66 <+30>: mov $0x8,%rdi
0x0000000100003f6d <+37>: callq 0x100003f96
0x0000000100003f72 <+42>: mov %r9,(%rax)
0x0000000100003f75 <+45>: mov (%rax),%r9
0x0000000100003f78 <+48>: mov %rbp,%rsp
0x0000000100003f7b <+51>: pop %rbp
0x0000000100003f7c <+52>: retq
End of assembler dump.
(gdb) ni
Thread 2 received signal SIGSEGV, Segmentation fault.
I am assembling on a Mac like this: clang -masm=intel cell.asm.
Does anyone familiar with x86 assembly know the source of my error?
(Also, in case anyone asks, I know that it's important to call free after malloc but this code is the only code necessary to demonstrate my problem.)

Storing keyboard Input in x64 assembly (Mac OS/X)

I have been trying for some time now to get a number from a keyboard and comparing it with a value on the stack. If it is correct it will print "Hello World!" and if incorrect, it should print out "Nope!". However, what happens now is no matter the input "jne" is called, nope is printed, and segfault. Perhaps one of you could lend a hand.
.section __DATA,__data
str:
.asciz "Hello world!\n"
sto:
.asciz "Nope!\n"
.section __TEXT,__text
.globl _main
_main:
push %rbp
mov %rsp,%rbp
sub $0x20, %rsp
movl $0x0, -0x4(%rbp)
movl $0x2, -0x8(%rbp)
movl $0x2000003, %eax
mov $0, %edi
subq $0x4, %rsi
movq %rsi, %rcx
syscall
cmp -0x8(%rbp), %edx
je L1
jne L2
xor %rbx, %rbx
xor %rax, %rax
movl $0x2000001, %eax
syscall
L1:
xor %rax, %rax
movl $0x2000004, %eax
movl $1, %edi
movq str#GOTPCREL(%rip), %rsi
movq $14, %rdx
syscall
ret
L2:
xor %eax, %eax
movl $0x2000004, %eax
movl $1, %edi
movq sto#GOTPCREL(%rip), %rsi
movq $6, %rdx
syscall
ret
I would start with this OS/X Syscall tutorial (The 64-bit part in your case). It is written for NASM syntax but the important information is the text and links for the SYSCALL calling convention. The SYSCALL table is found on this Apple webpage. Additional information on the standard calling convention for 64-bit OS/X can be found in the System V 64-bit ABI.
Of importance for SYSCALL convention:
arguments are passed in order via these registers rdi, rsi, rdx, r10, r8 and r9
syscall number in the rax register
the call is done via the syscall instruction
what OS X contributes to the mix is that you have to add 0x20000000 to the syscall number (still have to figure out why)
You have many issues with with your sys_read system call. The SYSCALL table says this:
3 AUE_NULL ALL { user_ssize_t read(int fd, user_addr_t cbuf, user_size_t nbyte); }
So given the calling convention, int fd is in RDI, user_addr_t cbuf (pointer to character buffer to hold return data) is in RSI, and user_size_t nbyte (maximum bytes buffer can contain) is in RDX.
Your program seg faulted on the ret because you didn't have proper function epilogue to match the function prologue at the top:
push %rbp #
mov %rsp,%rbp # Function prologue
You need to do the reverse at the bottom, set the result code in RAX and then do the ret. Something like:
mov %rbp,%rsp # \ Function epilogue
pop %rbp # /
xor %eax, %eax # Return value = 0
ret # Return to C runtime which will exit
# gracefully and return to OS
I did other minor cleanup, but tried to keep the structure of the code similar. You will have to learn more assembly to better understand the code that sets up RSI with the address for sys_read SYSCALL . You should try to find a good tutorial/book on x86-64 assembly language programming in general. Writing a primer on that subject is beyond the scope of this answer.
Code that might be closer to what you were looking for that takes the above into account:
.section __DATA,__data
str:
.asciz "Hello world!\n"
sto:
.asciz "Nope!\n"
.section __TEXT,__text
.globl _main
_main:
push %rbp #
mov %rsp,%rbp # Function prologue
sub $0x20, %rsp # Allocate 32 bytes of space on stack
# for temp local variables
movl $0x2, -4(%rbp) # Number for comparison
# 16-bytes from -20(%rbp) to -5(%rbp)
# for char input buffer
movl $0x2000003, %eax
mov $0, %edi # 0 for STDIN
lea -20(%rbp), %rsi # Address of temporary buffer on stack
mov $16, %edx # Read 16 character maximum
syscall
movb (%rsi), %r10b # RSI = pointer to buffer on stack
# get first byte
subb $48, %r10b # Convert first character to number 0-9
cmpb -4(%rbp), %r10b # Did we find magic number (2)?
jne L2 # If No exit with error message
L1: # If the magic number matched print
# Hello World
xor %rax, %rax
movl $0x2000004, %eax
movl $1, %edi
movq str#GOTPCREL(%rip), %rsi
movq $14, %rdx
syscall
jmp L0 # Jump to exit code
L2: # Print "Nope"
xor %eax, %eax
movl $0x2000004, %eax
movl $1, %edi
movq sto#GOTPCREL(%rip), %rsi
movq $6, %rdx
syscall
L0: # Code to exit main
mov %rbp,%rsp # \ Function epilogue
pop %rbp # /
xor %eax, %eax # Return value = 0
ret # Return to C runtime which will exit
# gracefully and return to OS

Resources