Assembly - inline asm - copying from one array to another?

Context:

Linux 64. AT & T.

GCC 4.8.2 (with -O3 -march = native)

x86_64 abi under the left hand, open on page 21.

Estimated C code:

To understand the goal, here is the idea:

int32_t res[] = {0,0,0,0}; int32_t primo[] = {5,8,50,150}; for (int32_t x = 0; x < 4; ++x) { res[x] = primo[x]; } printf("%d %d %d %d\n", res[0], res[1], res[2], res[3]); 

Bad C code:

Error found:

 Error: `(%rsp,%esi,4)' is not a valid base/index expression 

The code:

 int32_t res[] = {0,0,0,0}; int32_t primo[] = {5,8,50,150}; int32_t counter = 0; __asm__ volatile( "start_loop:\n\t" "movl (%1,%2,4), (%0,%2,4)\n\t" "addl $1, %2\n\t" "cmp $4, %2\n\t" "jne start_loop" : "=&r"(res) : "r"(primo),"r"(counter) :"cc" ); printf("%d %d %d %d\n", res[0], res[1], res[2], res[3]); 

Assembly code (lines underlying the problem):

 ... start_loop: movl (%rsp,%edx,4), (%si,%edx,4) addl $1, %edx cmp $4, %edx jne start_loop ... 

Question:

How can I express the correct code? Where am I wrong?

thanks

Update:

when changing the conveyor to

movl (%rsp,%rdx,4), (%rsi,%rdx,4)

I get

Error: too many memory references for 'mov'

What??

Update 2

For readers, it seems that my system is pretty special because it will not fit the correct instruction size.

I need to manually enter my variables with int64_t as an example to make the r * x thing happen. If c11 / C ++ 11 uses the uintptr_t type.

Otherwise, gcc adheres to the 32-bit version, which causes an invalid base / index error.

He bit me several times. I hope now it will not be for you.

+5
source share
1 answer

Now close the ABI document and, of course, open the intel manual, basic architecture and a link to a set of instructions: →

First of all, mov does not accept two memory operands, you need to go through the register or use the specialized movs line movs . Secondly, in the effective address you cannot mix 16, 32 and 64-bit registers. Given the types in your code snippet, it is very suspicious that the compiler has replaced 16-bit registers for you. In addition, it should not even compile due to impossible restrictions, res is an array that you cannot use as output. In addition, you change the counter variable, but you do not tell the compiler that.

The gcc build build is a very complicated thing. Better avoid it if possible, especially if you are a beginner, otherwise you will struggle with the compiler and not learn the assembly.

The fixed version may look like this:

 #include <stdint.h> #include <stdio.h> int main() { int32_t res[] = {0,0,0,0}; int32_t primo[] = {5,8,50,150}; int32_t counter = 0; int32_t tmp; __asm__ volatile( "start_loop:\n\t" "movl (%3, %q1, 4), %0\n\t" "movl %0, (%2, %q1, 4)\n\t" "addl $1, %1\n\t" "cmp $4, %1\n\t" "jne start_loop" : "=&r" (tmp), "+r" (counter) : "r" (res), "r"(primo) : "cc", "memory" ); printf("%d %d %d %d\n", res[0], res[1], res[2], res[3]); return 0; } 
+5
source

Source: https://habr.com/ru/post/1213856/


All Articles