Ассмемблер вставками

Тема в разделе "WASM.BEGINNERS", создана пользователем dcc0, 22 дек 2022.

  1. dcc0

    dcc0 Member

    Публикаций:
    2
    Регистрация:
    22 дек 2022
    Сообщения:
    60
    Спасибо всем за развёрнутые ответы. В общем для себя некоторые выводы сделал. Пока понял, более или менее, механизм занесения переменных в стек. Если я верно понял, это происходит последовательно, каждая следующая переменная смещает стек, на 4 позиции, в данном случае (видимо, смещение в байтах). Получается, что смещение для переменной вычисляется легко в небольших программах.
     
    Последнее редактирование: 23 дек 2022
  2. ormoulu

    ormoulu Well-Known Member

    Публикаций:
    0
    Регистрация:
    24 янв 2011
    Сообщения:
    1.208
    В общем случае, не совсем так. Как правило, пролог функции (т.е. инструкции в начале) поднимает стек сразу на необходимое количество байт, чтобы поместились все локальные переменные, после чего уже им присваиваются начальные значения. Но это не всегда так, может быть и такое что если переменная больше не используется или потеряла видимость, стек опустится. Все зависит от компилятора и его опций.

    Если речь об аргументах функции, то (опять же - в общем случае) те, что передаются на стеке, будут помещены последовательно перед вызовом.
     
  3. Rel

    Rel Well-Known Member

    Публикаций:
    2
    Регистрация:
    11 дек 2008
    Сообщения:
    5.251
    Ассемблер в гцц умеет в интеловский синтаксис (параметр -masm=intel или как-то так).

    Ты главную свою ошибку про инлайн асм понял? Тебе не надо ничего высчитывать никаких смещений на стеке, тебе надо передать переменные через списки инпутов и/или аутпутов. Переменной в коде вообще может не быть на стеке, если функция достаточно простая, чтобы держать переменную в только регистре, оптимизатор это сделает.
     
  4. ormoulu

    ormoulu Well-Known Member

    Публикаций:
    0
    Регистрация:
    24 янв 2011
    Сообщения:
    1.208
    Ага, а еще к переменным в примере можно обращаться по rbp потому, что компилятор сформировал так называемый "bp-based stack frame". Это опять же необязательно, оптимизирующие компиляторы чаще формируют "sp-based frame", с обращением к локальным переменным по указателю стека.
     
  5. dcc0

    dcc0 Member

    Публикаций:
    2
    Регистрация:
    22 дек 2022
    Сообщения:
    60
    "В общем случае, не совсем так. Как правило, пролог функции (т.е. инструкции в начале) поднимает стек сразу на необходимое количество байт, чтобы поместились все локальные переменные".
    Примерно так и понял. И помещается они, как я понял, в порядке следования друг за другом.
    --- Сообщение объединено, 23 дек 2022 ---
    То есть, допустим, переменная 1 единственная и она не попадет в стек, соответственно в коде не будет доступна для изменения через регистр rbp?! Примерно понял, о чем речь.
    Спасибо ещё раз, видимо, надо было ковырнуть код, чтобы понять, сколько есть в асме нюансов, и сколько всего я не знаю.
    --- Сообщение объединено, 23 дек 2022 ---
    Нашёл. Искал по ключевым словам: variable C in Assembler.
    Тема на stack Overflow: "manipulating c variable via inline assembly".
    --- Сообщение объединено, 23 дек 2022 ---
    В итоге получилось что-то вроде такого:

    Код (Text):
    1. /*Порождение перестановок*/
    2. #include <stdio.h>
    3. int main(){
    4.         char a[] = "4321";  /*array*/
    5.            int i, j, f;
    6.            asm("movl   $24, %0;"
    7.            :"=r"(f)) ; /*f=24*/
    8.            char c;
    9.           while (f--) {
    10.           printf("%s\n", a);
    11.            asm ("movl    $1, %0;"
    12.            :"=r"(i)); /*i=1*/
    13.           while(a[i] >= a[i-1]) i++;
    14.            asm ("movl   $0, %0;"
    15.             :"=r"(j)); /*i=1*/
    16.            while(a[j] <= a[i])j++;
    17.       c=a[j];
    18.       a[j]=a[i];
    19.       a[i]=c;
    20. i--;
    21. for (j = 0; j < i; i--, j++) {
    22.   c = a[i];
    23.   a[i] = a[j];
    24.   a[j] = c;
    25.       }
    26.    }
    27. }
    28.  
    Если я верно перевёл:
    Код (Text):
    1.  
    2.  asm ("movl    $1, %0;" /*Значение 1 помещается в аргумент 0*/
    3.            :"=r"(i)); /*i=1*/  /*Здесь указывается, с какой  переменной связан аргумент 0*/
    4.  
    --- Сообщение объединено, 23 дек 2022 ---
    Вычитал где-то, что если требуется переменную в 0, то можно так, используя оператор xor:
    Код (Text):
    1.    asm ("xor   %0, %0;"
    2.             :"=r"(j)); /*j=0*/
    3.  
    --- Сообщение объединено, 23 дек 2022 ---
    https://gitflic.ru/project/dcc0/mix-c-89-php/blob?file=permutations_iterative.c
     
    Последнее редактирование: 23 дек 2022
  6. dcc0

    dcc0 Member

    Публикаций:
    2
    Регистрация:
    22 дек 2022
    Сообщения:
    60
    Фантастика: синтаксис inline позволяет делать обмен (swap) переменными.
    Обнаружил также на Stack Overflow.
    --- Сообщение объединено, 24 дек 2022 ---
    То есть, если мне требуется сделать декремент переменной, то я должен делать его так:
    Код (Text):
    1.     asm(
    2.         "movl %[arg_a],%%eax\n\t"
    3.         "decl %%eax\n\t"
    4.         :"=a"(a)
    5.         :[arg_a]"r"(a)
    6.         :"cc");
    7.  
    В целом понятно. Только зачем два знака % перед регистром?!
    Почему я не могу использовать для операнда запись %0?!
    --- Сообщение объединено, 24 дек 2022 ---
    Финальный код в целом интересный получился: :grin:

    Код (Text):
    1. /*Порождение перестановок*/
    2. #include <stdio.h>
    3. int main(){
    4.          int a[5] = {4,3,2,1};  /*Массив целых*/
    5.          int i, j, f, c;
    6.          asm("movl   $24, %0;"
    7.          :"=r"(f)); /*f=24 факториал - !4*/
    8.     while (f--) {
    9.          printf("%d%d%d%d\n", a[0], a[1], a[2], a[3]);
    10.          asm ("movl    $1, %0;"
    11.         :"=r"(i)); /*i=1*/
    12.     while(a[i] >= a[i-1]) i++;
    13.          asm ("xor   %0, %0;"
    14.          :"=r"(j)); /*j=0 Обнулим через строгую дизъюнкцию*/
    15.     while(a[j] <= a[i])j++;
    16.          asm("" : "=r" (a[j]), "=r" (a[i]) : "0" (a[i]), "1" (a[j]) :); /*Обмен*/
    17.          asm(
    18.         "movl %[arg_i],%%eax\n\t"
    19.         "decl %%eax\n\t"
    20.         :"=a"(i)
    21.         :[arg_i]"r"(i)
    22.         :"cc"); /*i-- 0 декремент i*/
    23.       for (j = 0; j < i; i--, j++) {
    24.          asm("" : "=r" (a[j]), "=r" (a[i]) : "0" (a[i]), "1" (a[j]) :); /*Обмен хвоста*/
    25. }}}
    26.  
     
  7. aa_dav

    aa_dav Active Member

    Публикаций:
    0
    Регистрация:
    24 дек 2008
    Сообщения:
    444
    В руководстве по ссылке это тоже объяснено. Рекомендую его внимательно всё-таки прочитать.