2013-04-19 3 views
2

Я довольно хорош в C, не столько с сборкой, но из интереса, я хотел получить некоторую работу внутри C, используя gcc. Проблема в том, что моя программа либо дает какое-то глупое число, либо сбои.Добавление в C с использованием сборки

unsigned sadd32(unsigned a, unsigned b) 
{ 
    unsigned c = 0; 

    __asm__("movl %%eax, %0" : "=a"(a)); 
    __asm__("addl %%eax, %0" : "=b"(b)); 
    __asm__("movl %edx, 0xffffffff"); 
    __asm__("cmovc %eax, %edx"); 

    __asm__("movl %0, %%eax" : "=c"(c)); 


    return c; 
} 

Я уверен, что я сделал что-то глупое, если это очевидно любому? ;)

+2

Похоже, у вас неправильный порядок операндов. Это должно быть 'source, dest' в синтаксисе AT & T. Плюс немедленные операнды (например, 0xffffffff) должны иметь префикс '$'. Могут быть и другие проблемы. – Michael

+2

Я думаю, что важным моментом является использование одного блока '__asm__', а не нескольких. Это гарантирует, что компилятор не вставляет код сборки между вашими линиями (он может добавить некоторые перед блоком, но это нормально). – ugoren

ответ

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

unsigned sadd32(unsigned a, unsigned b) 
{ 
    unsigned c = 0; 
    __asm__ ("movl %2, %%eax\n\t" 
        "addl %1, %%eax\n\t" 
        "movl %%eax, %0\n\t" 
        :"=r"(c) 
        :"r"(a),"r"(b) 
        :"%eax" 
      ); 
    return c; 
} 

int main() 
{ 
    unsigned int a=3,b=5; 
    printf("The sum of %u and %u is %u\n",a,b,sadd32(a,b)); 
    return 0; 
} 

Ссылаясь на: http://www.ibiblio.org/gferg/ldp/GCC-Inline-Assembly-HOWTO.html

Из того, что я вижу, что ваш код имеет некоторые недостатки ::

unsigned sadd32(unsigned a, unsigned b) 
{ 
    unsigned c = 0; 

    __asm__("movl %%eax, %0" : "=a"(a)); 
    __asm__("addl %%eax, %0" : "=b"(b)); 
    __asm__("movl %edx, 0xffffffff"); /* this here, you are specifying a manual location, may not be accessible or valid */ 
    __asm__("cmovc %eax, %edx"); /* resulting in its error */ 

    __asm__("movl %0, %%eax" : "=c"(c)); 


    return c; 
} 

Кроме того, я что вы не поняли концепцию «= $». Из того, что я вижу, вы просто пишете имя переменной там, но это не так, как это работает. С сайта, ограничение ограничения (как они известны), заключаются в следующем:

  1. «м»: операнд памяти разрешено, с любым видом адреса, что машина поддерживает в целом.
  2. «o»: операнд памяти разрешен, но , только если адрес смещен. т.е. добавление небольшого смещения к адресу дает действительный адрес.
  3. «V»: операнд памяти, который не является офсетным. Другими словами, все, что соответствует m’ constraint but not the o'constraint.
  4. «i»: Непосредственное целое число допускается операнд (один с постоянным значением). Это включает в себя символические константы , значения которых будут известны только во время сборки.
  5. "n": Допускается немедленный целочисленный операнд с известным числовым значением. Многие системы не могут поддерживать константы времени сборки для операндов менее одного слова. Ограничения для этих операндов должны использовать 'n' , а не 'i'.
  6. «g»: Любой регистр, память или мгновенное целое число допускается операнд, за исключением регистров, которые не являются общими регистрами.

Обратитесь к сайту за дополнительными примерами и другими ограничениями. Надеюсь, это помогло! :)

+0

Извините за поздний ответ. Спасибо за хорошие ответы, но почему-то всякий раз, когда я запускаю эти программы несколько раз, они работают, а потом вдруг я начинаю считать ошибку «эта программа перестала работать»! –

+0

@DraconianTimes: Я использую Codeblocks 12.11, с MinGW GCC 4.8.0, на Windows 7 64bit. У меня не было проблем с этим. Можете ли вы дать свои спецификации? –

+0

Проверьте это: http://ideone.com/DaK8Uc –

1

Edit: Код исправлен, так как Майкл заметил, что это насыщенный надстройку.

Основные моменты, о том, как использовать GCC ассемблерные:

  1. Поместите ассемблерные его в одном asm( ... ) блок.
  2. Определить входные, выходные и сбитые регистры в расширенной сборке.
  3. Для оптимального использования регистров пусть gcc принимает решения о том, какие регистры использовать, когда какой-либо общий регистр работает одинаково хорошо для вашего кода.
  4. Вам не нужно использовать mov для установки значений в начале встроенного сборочного блока, просто определите входы.
  5. Проверьте, пожалуйста, GCC-Inline-Assembly-HOWTO, особенно деталь на Extended Asm.

Вот код:

#include <stdio.h> 

unsigned my_sadd(unsigned a, unsigned b) 
{ 
    asm(
      "addl %2, %0;" 
      "cmovcl %3, %0;" 
      /* outputs */ 
      : "=r"(a) 
      /* inputs */ 
      : "0"(a), "r"(b), "r" (0xffffffff) 
     ); 
    return a; 
} 

int main(void) 
{ 
    unsigned a; 
    unsigned b; 
    unsigned c; 

    a = 123456; 
    b = 314159; 

    c = my_sadd(a, b); 
    printf("%u + %u = %u\n", a, b, c); 

    a = 0x80000000; 
    b = 0xF0000000; 
    c = my_sadd(a, b); 

    printf("%u + %u = %u\n", a, b, c); 
    return 0; 
} 
+0

Ну, код OP должен выполнять насыщенное добавление (т. Е. Если результаты будут обтекаться на 32-м бите, то он установлен в 0xFFFFFFFF). Отсюда все дополнительные инструкции. – Michael

+0

@Michael Спасибо, я понял код, но раньше не знал термин «насыщенный add». – nrz

+0

Даже если компилятор соглашается с этим, изменение или слияние регистра ввода-вывода всегда * неверно. –

1

Помимо рекомендации об использовании одного инструктора __asm__ и синтаксиса AT & T, возможно, лучше дать компилятору загрузить регистр с максимальным значением. В идеале:

/* static __inline__ */ unsigned sadd32 (unsigned a, unsigned b) 
{ 
    __asm__ ("addl %k1, %k0\n\t" 
      "cmovcl %k2, %k0\n\t" 
      : "+r" (a) : "r" (b), "r" (0xffffffff) : "cc"); 

    return (a); 
} 

Эта форма также хорошо работает на x86-64, где первые и вторые аргументы будут в %rdi (с использованием %edi) и %rsi (с использованием %esi) соответственно. Было бы еще лучше указать эту функцию с помощью классификатора inline: у компилятора может быть «max» уже загружен или может запланировать лучший способ его загрузки и т. Д. Также не нужно возвращать значение в %rax или %eax ,

Многие учебники для gcc inline asm устарели. Лучшее, что я нашел, это учебник Lockless Inc для x86 [-64].

Смежные вопросы