Сборка 8086 (IA32) проблема с добавлением элементов двух массивов - PullRequest
0 голосов
/ 03 мая 2018

Итак, я изучаю базовую сборку IA-32, и у меня возникают проблемы с пониманием того, как на самом деле регистрируется содержимое магазина. Предполагается, что следующая программа добавит элементы двух данных массивов по позиции индекса (a1 [i] + a2 [i]) и сохранит результат во втором регистре. Массивы имеют одинаковую длину. Я использую GDB, поэтому я знаю, что циклическая часть работает.

EXIT = 1
WRITE = 4
LINUX_SYSCALL =0x80

.data
array1: .int -1, 5, 1, 1, 4  # um vetor de inteiros
array2: .int 1, -3, 1, -5, 4 # vetor que fica com a soma dos dois

.text

.global _start
_start: 
             movl   $array1,            %eax
             movl   $array2,            %ebx

    ifThen:

             jz     fim
             jmp    soma    

    soma:
             add    %eax,               %ebx
             jmp    next_pos

    next_pos:
             inc    %ecx
             add        $4,                 %eax
             add        $4,                 %ebx
             jmp    ifThen

    fim:
             movl   $EXIT,              %eax
             int    $LINUX_SYSCALL

Моя оригинальная идея была слишком сквозной для gbd, если значения в регистре ebx добавлялись правильно (следовательно, никаких системных вызовов записи). Вместо этого я продолжаю видеть большие числа в реестрах, которые я предполагаю, чтобы быть адресами, а не результаты суммы элементов в массивах. Однако если я удаляю знак доллара в инструкции movl (movl array1,% eax), я получаю ожидаемые числа, но не могу перейти к следующей позиции массивов, поскольку инструкция add фактически добавляет 4 к значению в регистре вместо перемещения указателя регистра на следующие 4 байта.

Любая помощь приветствуется, спасибо заранее!

1 Ответ

0 голосов
/ 03 мая 2018

Вы хорошо наблюдали за поведением, и вы (в основном?) Правильно относились к ним.

movl $array1, %eax против movl array1, %eax: да, первый загрузит eax с адресом памяти, второй загрузит eax с 32-битным значением из памяти (с этого адреса).

У меня возникли проблемы с пониманием того, как на самом деле регистрируется содержимое магазина.

Регистры общего назначения, такие как eax, представляют собой 32-разрядные регистры (на современных 64-разрядных процессорах x86, поддерживающих 64-разрядные, eax - это младшая 32-разрядная часть rax, то есть 64-разрядных регистров). Это означает, что регистр содержит 32-битные значения (0 или 1). Ничего больше. Отладчики, если вы не переключите их на другую интерпретацию, обычно будут отображать значения в виде 32-разрядного шестнадцатеричного целого числа без знака, потому что из вывода, такого как шестнадцатеричное 1234ABCD, вы можете прочитать конкретную комбинацию битов в голове (каждая шестнадцатеричная цифра ровно 4 бита, т.е. B = 11 = 8 + 2 + 1 = 1011 двоичный), но это не означает, что регистр содержит шестнадцатеричное значение, регистр всего 32 бита, и вы можете интерпретировать их так, как пожелаете (или код).

Чтобы получить доступ к элементам массива с индексом i, вы можете выбрать разные методы, в вашей задаче суммирования массивов я, вероятно, остановлюсь на вашем исходном коде, используя адреса памяти непосредственно на элементах, но тогда вам понадобится еще один регистр для загрузки фактическое значение, то есть:

    # loop initialization
    movl $array1, %eax   # eax = array1 pointer
    movl $array2, %ebx   # ebx = array2 pointer
    # TODO: set up also some counter or end address
loop_body:
    # array1[i] += array2[i];
    movl (%ebx), %edx    # load value array2[i] from memory into edx
    addl %edx, (%eax)    # add edx to the array1[i] (value in memory at address eax)
    # advance array1 and array2 pointers (like ++i;)
    addl $4, %eax
    addl $4, %ebx
    # TODO: do some loop termination condition and loop

Это позволяет использовать простой код цикла тела и предоставлять один и тот же код суммирования с различными массивами для суммирования.

Другие опции

Вы можете избежать необходимости регистрации по адресу памяти, кодируя его непосредственно в инструкции доступа к памяти, например:

    # loop initialization
    xorl %ecx, %ecx      # ecx = 0 (index + counter)
loop_body:
    # array1[i] += array2[i];
    movl array2(,%ecx,4), %eax  # load value array2[i] from memory into eax
    addl %eax, array1(,%ecx,4)  # add eax to the array1[i]
    incl %ecx                   # ++i
    # TODO: do some loop termination condition and loop

Но этот код нельзя перенаправить в разные массивы.

Или вы можете использовать адреса массивов в регистрах, но избегать их изменения, используя адресацию регистров индекса:

    # loop initialization
    movl $array1, %eax   # eax = array1 pointer
    movl $array2, %ebx   # ebx = array2 pointer
    xorl %ecx, %ecx      # ecx = 0 (index + counter)
loop_body:
    # array1[i] += array2[i];
    movl (%ebx,%ecx,4), %edx  # load value array2[i] from memory into edx
    addl %edx, (%eax,%ecx,4)  # add edx to the array1[i]
    incl %ecx                 # ++i
    # TODO: do some loop termination condition and loop

Это может иметь смысл, если вы все равно планируете использовать значение индекса, поэтому вам нужен простой i, и вы планируете использовать адреса массивов позже, поэтому не нужно их модифицировать, и т. Д ...

Существуют и другие способы доступа к значениям в памяти, но описанные выше наиболее просты для тех, кто изучает сборку x86.

Имейте в виду, что в сборке нет переменных или массивов и т. Д. Память компьютера похожа на один огромный массив без имени с индексами от 0 до N-1 (N = размер физической памяти) и на каждом индексе доступен один байт (8 бит информации).

Регистры представляют собой 8/16/32/64 бит информации, доступной непосредственно на микросхеме ЦП, поэтому ЦПУ не нужно знать адрес (имя «eax» похоже на адрес) и не нужно обратитесь к микросхеме памяти для получения значения (поэтому регистры работают быстрее, чем память).

Чтобы связаться с памятью в синтаксисе AT & T, вы должны написать что-то в виде: displacement(base_reg, index_reg, scale), посмотрите этот вопрос с деталями: Пара вопросов о [base + index * scale + disp]

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...