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

#include <math.h>
#include <stdio.h>
#include <stdlib.h>
int main( void ) { // int должна возвращать main()
int i, n;
float sum = 0, d = 0, ;
float *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 = ∑ // указатель на мат ожидание
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 шт):
Ошибка 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 установлен.
Результат:
