Не работает ассемблерная вставка

Хочу найти математическое ожидание, используя ассемблер, но получаю ошибки (см. рисунок): Текст ошибки

#include <math.h>
#include <stdio.h>
#include <stdlib.h>

int main( void ) { // int должна возвращать main()
int i, n;
float  sum = 0, d = 0, ;

float *SUM = &sum; // указатель на мат ожидание
int *N = &n;     // указатель на размер массива
printf( "введите количество элементов ");
scanf( "%d", &n );
// сделать ошибку ввода
//float x[n], p[n];

float * x= (float*) malloc( n*sizeof(float) );
if (NULL == x) {
         printf("Память не выделилась для массива x\n");
         return 0;
    }
float * p= (float*) malloc( n*sizeof(float) );
if (NULL == x) {
         printf("Память не выделилась для массива p\n");
         return 0;
    }


if ( n <= 1 /*|| n > MAX_SIZE */) {
    printf( "Ошибка, некорректный параметр\n" );
    return EXIT_FAILURE;
}

puts( "Введите элементы массивов" );
for ( i = 0; i < n; i++ ){
    printf( "X[ %d ] ", i );
    scanf( "%lf", &x[ i ] );
    printf( "P[ %d ] ", i );
    scanf( "%lf", &p[ i ] );
}


// for ( i = 0; i < n; i++ )
//     sum += x[ i ] * p[ i ];

asm  // поиск мат ожидания
(
     ".intel_syntax noprefix\n" /*Синтаксис Intel, допускается опускать % перед именами 
 регистров*/   
      "\n\tmov rax, %0"              // заносим в  начало адреса x в памяти
      "\n\tmov rbx, %1"              // заносим в  начало адреса p в памяти
      "\n\tmov rdx, %2"              // заносим в регистр размер массивов
      "\n\tmovss xmm0, [%3]"           // заносим sum     //или обращаемся по ссылке
      "\n\tmov rcx, -1"              // заносим в счетчик -1, чтобы нулевой элемент 
 массива не пропустить
      "\n\tloop1:"                   // переход к след элементу 
      "\n\tinc rcx"                  // увеличиваем счетчик по элементам 
      "\n\tlea r8, [rax+4*rcx]"      // заносим в r8 адрес элемента из массива x, 
  учитывая его сдвиг по циклу
      "\n\tmovss xmm1, [rax+4*rcx]"         // в xmm1 заносим значение элемента массива
      "\n\tlea r8, [rbx+4*rcx]"      // заносим в r8 адрес элемента из массива p, 
  учитывая его сдвиг по циклу
      "\n\tmovss xmm2, [rbx+4*rcx]"         // в xmm2 заносим значение элемента массива
      "\n\tmulss xmm1, xmm2"         // умножаем  p*x, результат записывается в xmm1
      "\n\taddss xmm0, xmm1"         // складываем sum + p*x
      "\n\tcmp rcx, rdx"             // сравниваем счетчик с размером
      "\n\tjz loop1"                 // и если он  равен, переходим к loop3 т е 
 завершаем цикл
      "\n\tmovss [%4], xmm0 "
    :  /*выходные операнды отсутсвуют */
    :  "r"(x), "r"(p), "r" (N), "r" (SUM) /*входные операторы*/
    : "%rax", "%rbx", "%rdx", "%rcx", "%xmm0" , "%xmm1" , "%xmm2" , "%xmm3" ,"memory", 
 "cc"
    );


printf( "Мат ожидание= %f \n", sum );

return EXIT_SUCCESS;
}

Внёс правки. Теперь на выводе получаю нуль:

#include <math.h>
#include <stdio.h>
#include <stdlib.h>
#include <malloc.h>
#include <time.h>

int main( void ) { // int должна возвращать main() !!!!!! убрать VOID
  int i, n;
  float  sum = 0, d = 0, z, r;

  float *SUM = &sum; // указатель на мат ожидание
 int *N = &n;       // указатель на размер массива
  printf( "введите количество элементов ");
  scanf( "%d", &n );
  //if (!scanf("%d", &n)){  printf("Ошибка! вы вводите некорректные данные\n"); return 0;};
  // сделать ошибку ввода
 //float x[n], p[n];
 if (n<1) { printf("Ошибка! Некорректный размер"); return 0;};
 
 float * x= (float*) malloc( n*sizeof(float) );
 if (NULL == x) {
          printf("Память не выделилась для массива x\n");
          return 0;
     }
 float * p= (float*) malloc( n*sizeof(float) );
 if (NULL == x) {
          printf("Память не выделилась для массива p\n");
           return 0;
      }
  
  
  if ( n <= 1 /*|| n > MAX_SIZE */) {
      printf( "Ошибка, некорректный параметр\n" );
      return EXIT_FAILURE;
  }

  puts( "Введите элементы массивов" );
  for ( i = 0; i < n; i++ ){
      printf( "X[ %d ] ", i );
      //scanf( "%lf", &x[ i ] );
      if (!scanf("%lf", &x[i])){  printf("Ошибка! вы вводите некорректные данные\n"); return 0;}
      printf( "P[ %d ] ", i );
      //scanf( "%lf", &p[ i ] );
      if (!scanf("%lf", &p)){  printf("Ошибка! вы вводите некорректные данные\n"); return 0;}
  }

  printf( "Мат ожидание до асм= %f \n", SUM );
 // for ( i = 0; i < n; i++ )
 //     sum += x[ i ] * p[ i ];

  asm  // поиск мат ожидания
  (
       ".intel_syntax noprefix\n" /*Синтаксис Intel, допускается опускать % перед именами регистров*/   
        "\n\tmov rax, %1"              // заносим в  начало адреса x в памяти
        "\n\tmov rbx, %2"              // заносим в  начало адреса p в памяти
        "\n\tmov rdx, %3"              // заносим в регистр размер массивов
   //     "\n\tmovss xmm0, [%0]"           // заносим sum     //или обращаемся по ссылке
        "\n\tmov rcx, -1"              // заносим в счетчик -1, чтобы нулевой элемент массива не пропустить
        "\n\tloop1:"                   // переход к след элементу 
        "\n\tinc rcx"                  // увеличиваем счетчик по элементам 
        "\n\tlea r8, [rax+4*rcx]"      // заносим в r8 адрес элемента из массива x, учитывая его сдвиг по циклу
        "\n\tmovss xmm1, [rax+4*rcx]"  // в xmm1 заносим значение элемента массива
        "\n\tlea r8, [rbx+4*rcx]"      // заносим в r8 адрес элемента из массива p, учитывая его сдвиг по циклу
        "\n\tmovss xmm2, [rbx+4*rcx]"  // в xmm2 заносим значение элемента массива
        "\n\tmulss xmm1, xmm2"         // умножаем  p*x, результат записывается в xmm1
        "\n\taddss xmm0, xmm1"         // складываем sum + p*x
        "\n\tcmp rcx, rdx"             // сравниваем счетчик с размером
        "\n\tjz loop1"                 // и если он равен, переходим к loop3, т.е. завершаем цикл
        "\n\tmovss [%0], xmm0 "
        
        : "=r"(SUM) /*выходные операнды, нумеруются с нуля (r: для выбора регистра компилятором, иначе указывается конкретный регистр)*/
      : "r"(x) , "r"(p) , "r" (N) /*входные операторы, нумерация продолжается, указание аналогично*/
      : "%rax", "%rbx", "%rdx", "%rcx", "%xmm0", "%xmm1", "%xmm2" , "%xmm3" ,"memory", "cc"  /*разрушаемые регистры (в формате: %имя)*/
  );
        
       
 //     :  "=r" (SUM) /*выходные операнды отсутствуют */ 
 //     :  "r"(x), "r"(p), "r" (N), /*входные операторы*/
 //     : "%rax", "%rbx", "%rdx", "%rcx", "%xmm0" , "%xmm1" , "%xmm2" , "%xmm3" ,"memory", "cc"
 //     );
  

  printf( "Мат ожидание = %f \n", sum );


return EXIT_SUCCESS;
}```

Ответы (1 шт):

Автор решения: Laukhin Andrey

Ошибка operand number out of range - номер операнда вне диапазона.
Согласно коду, есть четыре входных операнда, а их нумерация от 0 до 3.
Поэтому команда movss [%4], xmm0 и приводит к ошибке.

По логике, sum должен быть выходным операндом, a x, p, N - входными. При этом надо учесть, что нумерация будет сквозной через оба списка, т.е.

0   sum
1   x
2   p
3   N

UPD
Что касается работоспособности кода, то у Вас проблемы начинаются до ассемблерной вставки. В scanf не следует использовать %lf, а ввод в массив p не работает. Нужно заменить scanf("%lf", &p) на scanf("%f", &p[i]).

Ассемблерный код избыточен, цикл нерабочий, операнды переданы некорректно.
Мне проще привести рабочий код, чем комментировать, разбирайтесь:

asm (
    ".intel_syntax noprefix\n" 
    "\n\tmov eax, %1"               // адрес x в памяти
    "\n\tmov ebx, %2"               // адрес p в памяти
    "\n\tmov ecx, %3"               // размер массивов
    "\n\tmov edx, 0"                // индекс 0
    "\n\tloop1:"
    "\n\tmovss xmm0, [eax+4*edx]"   // x[индекс] в xmm0
    "\n\tmovss xmm1, [ebx+4*edx]"   // p[индекс] в xmm1
    "\n\tmulss xmm0, xmm1"          // p*x в xmm0
    "\n\taddss xmm2, xmm0"          // sum + p*x
    "\n\tinc edx"                   // индекс++
    "\n\tloop loop1"                // цикл
    "\n\tmovss [%0], xmm2"
    : "=g"(sum) 
    : "g"(x) , "g"(p) , "g" (n) 
    : "%eax", "%ebx", "%edx", "%ecx", "memory", "cc"
);

Я использовал 32-битные регистры, такой gcc установлен.
Результат:
введите сюда описание изображения

→ Ссылка