LinuxForum.Fans
Тема

Assembler x86_64 (AT&T синтаксис)

Автор: Osanve 9 сообщений 2828 просмотров
#198511

Здравствуйте.

Сейчас в универе идет курс системного программного обеспечения, т.е. сплошное программирование на асме. В распоряжении только Linux. Первую лабораторную сделал без проблем, т.к. стоял GNU/Linux Debian i386. Потом дошли руки - сменил систему на GNU/Linux Debian amd64, и сразу возникли проблемы.

Для второй лабораторной требуется модуль из первой лабораторной, следовательно начал переводить код на 64-разрядную архитектуру.

Для начала представлю код, который был:

Показать
main.cpp:
text
#include <iostream>
#include <ctime>
#include <stdlib.h>

using namespace std;

int *processing(int*, int);

int main() { srand(time(NULL)); int a[30]; for(int i = 0; i < 30; i++) { a[i] = rand()%10; } for(int i = 0; i < 30; i++) { cout << a[i] << " "; } cout << endl; int *result; result = processing(a, 30); cout << "Минимальное значение в массиве: " << result[0] << endl; cout << "Положение минимального значения: " << result[1] << endl; cout << "Количество нулей до минимального значения: " << result[2] << endl; cout << "Среднее положение после минимального: " << result[3] << endl; return 0; }

processing.cpp:

text
void *processing(int *array, int length)
{
    int min = array[0];
    int min_pos = 0;
    for(int i = 0; i < length; i++)
    {
        if(min >= array[i])
        {
            min = array[i];
            min_pos = i;
        }
    }
    int zero_count = 0;
    for(int i = 0; i < min_pos; i++)
    {
        if(array[i] == 0)
        {
            zero_count++;
        }
    }
    min_pos++;
    int middle = length - min_pos;
    middle >>= 1;
    middle += min_pos;
    middle++;
    if(middle == 31)
    {
        middle = -1;
    }
    int *result = new int[4];
    result[0] = min;
    result[1] = min_pos;
    result[2] = zero_count;
    result[3] = middle;
    return result;
}

main.s:

text
.data
    print_format:
        .string "\n"
    print_format_array:
        .string "%d "
    print_format_result:
        .string "%s%d\n"
    print_min:
        .string "Минимальное значение в массиве: "
    print_min_pos:
        .string "Положение минимального значения: "
    print_zero_count:
        .string "Количество нулей до минимального значения: "
    print_middle:
        .string "Среднее положение после минимального: "
    array:
        .long 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0
    array_end:

.text .globl main .type main, @function main: pushl %ebp movl %esp, %ebp

pushl $0 call time pushl %eax call srand movl $array, %ebx generate_loop: call rand xorl %edx, %edx movl $10, %ecx divl %ecx movl %edx, (%ebx) addl $4, %ebx cmpl $array_end, %ebx jne generate_loop movl $array, %eax print_loop: pusha pushl (%eax) pushl $print_format_array call printf addl $8, %esp popa addl $4, %eax cmpl $array_end, %eax jne print_loop pusha pushl $print_format call printf addl $4, %esp popa pushl $30 pushl $array call _Z10processingPii pusha movl (%eax), %ebx pushl %ebx pushl $print_min pushl $print_format_result call printf addl $12, %esp popa addl $4, %eax pusha movl (%eax), %ebx pushl %ebx pushl $print_min_pos pushl $print_format_result call printf addl $12, %esp popa addl $4, %eax pusha movl (%eax), %ebx pushl %ebx pushl $print_zero_count pushl $print_format_result call printf addl $12, %esp popa addl $4, %eax pusha movl (%eax), %ebx pushl %ebx pushl $print_middle pushl $print_format_result call printf addl $12, %esp popa

movl %ebp, %esp popl %ebp ret

processing.s случайно удалил при следующих действиях.

Для того, чтобы разобраться с переводом кода, скомпилировал исходники на C++ в g++ с флагом -S. В полученном коде вроде как разобрался, но остались некоторые вопросы:
1) gcc ругается на инструкции pusha и popa. Чем их можно заменить?
2) С вызовом time и srand разобрался, т.к. передается один параметр и он заносится в регистр %rdi, а не кладется в стек. А как быть с printf (т.е. надо передать больше одного параметра)? Способ, который применял на 32-разрядной архитектуре (т.е. положить параметры в стек в обратном порядке) компилятору не нравится.
3) Команды имеют постфикс q. В случае 32-разрядной архитектуры для объявления массива я использовал .long, а в командах постфикс l, а как сейчас объявить массив чисел, чтобы был полностью занят весь регистр, а не его половина?

Также есть пара вопросов по второй лабораторной (методички написаны для MS-DOS, поэтому они не рулят, благо препод разрешает делать под любую систему):
1) В консоли надо сделать три окна (ввод начальных данных, вывод результата, меню). Если я правильно понял то, что мне сказал google, то надо использовать FrameBuffer. Но вот как его правильно использовать? С эти никак разобраться не могу. Может быть есть другие способы?
2) Надо организовать поддержку мыши. Информацию на эту тему я так и не смог найти :( Можете что-нибудь подсказать?

Заранее спасибо.

P.S. Забыл указать, что окна должны быть разноцветные и реализованы с помощью прямой записи в видеопамять.

#198513
Osanve написал:
методички написаны для MS-DOS, поэтому они не рулят, благо препод разрешает делать под любую систему

добрый совет, делайте под dosbox - жизнь будет намного проще... и вас гарантированно не пошлют всё переделывать...

Osanve написал:
В консоли надо сделать три окна

скорей всего подразумевается псевдографика... но с этим уже к преподу...

Osanve написал:
Надо организовать поддержку мыши. Информацию на эту тему я так и не смог найти Можете что-нибудь подсказать?

для линукса - обратитесь к документации ядра input/input-programming.txt.

по поводу отличий amd64 - ИМХО вы также себе жизнь усложняете... но если хотите, то напишите на си, асемблируйте и найдите отличия...

#198517
Fat-Zer написал:
добрый совет, делайте под dosbox - жизнь будет намного проще...

dosbox да, как вариант, но мне хочется узнать как все это делается в современных системах

Fat-Zer написал:
и вас гарантированно не пошлют всё переделывать...

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

Fat-Zer написал:
скорей всего подразумевается псевдографика...

Да, именно она

Fat-Zer написал:
но с этим уже к преподу...

Препод не смог нормально описать отличия асма под 32 разряда и 64 :( Приходится разбираться самому

Fat-Zer написал:
но если хотите, то напишите на си, асемблируйте и найдите отличия...

Ничего похожего на pusha и popa ни в 64, ни в 32 не было. Массив вообще в переменных не задавался.

Fat-Zer написал:
для линукса - обратитесь к документации ядра input/input-programming.txt.

Спасибо, посмотрю

#198521

В соседней темке была ссылка: http://developer.amd.com/documentation/guides/Pages/default.aspx#manuals
Посмотрел. Там приводятся инструкции pushad и popad.

Теперь вместо:
[console]$ gcc ./main.s
./main.s: Assembler messages:
./main.s:43: Error: `pusha' is not supported in 64-bit mode
./main.s:48: Error: `popa' is not supported in 64-bit mode[/console]
выдает:
[console]$gcc ./main.s
./main.s: Assembler messages:
./main.s:43: Error: no such instruction: `pushad'
./main.s:48: Error: no such instruction: `popad'[/console]

#198528
Osanve написал:
мне хочется узнать как все это делается в современных системах

в современных системах всё пишется на си и только особенно ответственные (по времени или по выполнению) участки на асме...

Osanve написал:
Ничего похожего на pusha и popa ни в 64, ни в 32 не было.

логично... они там вообще не нужны... сохранять регистры - дело функции...
и вообще pusha - мерзость... правильно, что её запретили... всё надо делать ручками...

Osanve написал:
Массив вообще в переменных не задавался.

в смысле "в переменных"? значит так написали...

#198533
Fat-Zer написал:
в смысле "в переменных"?

Сегмент .data
Строки на вывод там были

Fat-Zer написал:
значит так написали...

В коде на C++ прописано:

text
int a[30];

Но этот массив в сегменте .data не прописывается, а идет работа со стеком каким-то не очень понятным, для меня, образом.

P.S. Также printf'а как такового в коде не наблюдается, хотя time, srand и rand есть. Именно из-за этого я понял, что параметр надо передавать в %rdi.

#198539
Osanve написал:
Но этот массив в сегменте .data не прописывается, а идет работа со стеком каким-то не очень понятным, для меня, образом.

надо объявлять за пределами main и с классификатором static.

Osanve написал:
P.S. Также printf'а как такового в коде не наблюдается, хотя time, srand и rand есть. Именно из-за этого я понял, что параметр надо передавать в %rdi.

вы на си переписали? или то цппшное, что в первом посте ассеблируете? - тогда не будет видно, конечно...
разрешение лучше поставить ".c". ЕМНИП для с++ printf через обёртки вызывается...

#198542

Понял почему не было никакого намека на printf в ассемблерном коде: я использовал std::cout.
Переписал на C, посмотрел, с printf разобрался, но получаю ошибку сегментирования.

Код:

text
print_loop:
  pushq %rax
  pushq %rsi
  pushq %rdi
  movq  (%rax),              %rsi
  movq  $print_format_array, %rdi
  call  printf
  addq  $16,                 %rsp
  popq  %rdi
  popq  %rsi
  popq  %rax
  addq  $4,                  %rax
  cmpq  $array_end,        %rax
  jne   print_loop

Инструкция

text
addq  $16,                 %rsp

для выравнивания стека (по крайней мере в 32-разрядной архитектуре требуется). 16 из-за того, что один параметр занимает 8 байт, а передаем их два. Хотя явно в стек ничего не кладется, но и без этой инструкции ошибка сегментирования
Инструкция

text
addq  $4,                  %rax

Для перехода к следующему элементу массива. Массив объявлен следующим образом:

text
array:
  .long 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0
array_end:

А .long, на сколько мне известно занимает 4 байта.

Собственно что я делаю не так?

#198543
Fat-Zer написал:
надо объявлять за пределами main и с классификатором static.

Все равно отсутствует.

Fat-Zer написал:
вы на си переписали? или то цппшное, что в первом посте ассеблируете? - тогда не будет видно, конечно...
разрешение лучше поставить ".c". ЕМНИП для с++ printf через обёртки вызывается...

Да, это я понял и уже переписан на C :)

Войдите или зарегистрируйтесь, чтобы ответить.