Как я могу быть уверен, что регистр общего назначения не используется другими перед входом в встроенную сборку? - PullRequest
0 голосов
/ 27 сентября 2018

Ниже приведен фрагмент встроенного кода сборки GCC.Это увеличивает вход *Value на единицу атомным способом.И вернуть увеличенное значение.

В коде сборки используется регистр EAX.Как я могу узнать, что EAX не используется другими до вызова этой функции?Если он используется, ассемблерный код что-то испортит.

UINT32
__cdecl
AtomicIncrement (
  IN      volatile UINT32    *Value
  )
{
  UINT32  Result;

  __asm__ __volatile__ (
    "movl    $1, %%eax  \n\t" ; <============== HERE, EAX is being modified.
    "lock               \n\t"
    "xadd    %%eax, %2  \n\t"
    "inc     %%eax          "
    : "=a" (Result),          // %0
      "=m" (*Value)           // %1
    : "m"  (*Value)           // %2
    : "memory",
      "cc"
    );

  return Result;
}

Я прочитал из здесь , что:

... Целочисленные значения и памятьадреса возвращаются в регистр EAX ... (соглашение о вызовах cdecl)

Значит ли это, что если я буду следовать соглашению о вызовах cdecl, компилятор убедится, что EAX может безопасно ли использовать при входе в функцию сборки?Если я использую какой-нибудь другой регистр общего назначения, скажем, EBX, я должен поместить его в секцию clobber ?Т.е. после последнего двоеточия?

1 Ответ

0 голосов
/ 27 сентября 2018

Вы используете выходной операнд "=a", поэтому компилятор знает, что ваш ассемблер записывает этот регистр.

Он будет планировать соответственно, используя другой регистр для всего, что он хочет сохранить после ассемблера.пробеги.Вы должны точно описать свой asm для компилятора с ограничениями, потому что в противном случае это черный ящик.

Соглашения о вызовах функций практически не имеют значения для встроенного asm.После того, как эта функция встроена, она будет в середине некоторой более крупной функции.


Нет смысла делать это со встроенным asm вместо встроенного в GNU C __atomic_add_fetch, который скомпилируется в lock xadd или lock add в зависимости от того, используется результат или нет.https://gcc.gnu.org/onlinedocs/gcc/_005f_005fatomic-Builtins.html.

Если вы настаиваете на использовании встроенного asm, используйте ограничения "+r" и "+m" для двух операндов ввода / вывода, а просто имеют lock xadd внутришаблон asm.Пусть компилятор сделает все остальное, поэтому напишите это в C (установив вход регистров в 1 перед asm и увеличив его после).Это позволяет компилятору оптимизировать ++ для более поздней операции, если он этого хочет.GCC знает, как поместить 1 в регистр, и как увеличить.

Конечно, gcc также знает, как использовать lock ed инструкции, поэтому вы должны позволить это делать с помощью встроенных команд.или C ++ 11 std :: atomic.

...