Перебор массивов в сборке для решения общего уравнения - PullRequest
1 голос
/ 10 июля 2020

Я изучаю язык ассемблера с помощью NASM и столкнулся с проблемой программирования, которую, похоже, не могу понять. Цель программы - решить это уравнение: Изображение уравнения Для тех, кто не может видеть фотографию, уравнение говорит, что для двух массивов длины n, массива a и массива b, найти: для i = От 0 до n-1, ((ai + 3) - (bi - 4))

Я должен использовать только три общих регистра, и я выяснил образец кода, который, я думаю, мог бы работать , но я продолжаю сталкиваться с ошибками запятых и операндов в строках 16 и 19. Я понимаю, что для выполнения итерации по массиву вам нужно переместить указатель на каждый индекс, но поскольку оба массива имеют разные значения (массив 1 - это dw и массив 2 - db) Я не знаю, как это объяснить. Я все еще новичок в сборке, и я буду благодарен за любую помощь или указатели. Вот изображение моего текущего кода: Пример кода

       segment .data
  a         dw    12, 14, 16      ; array of three values        
  b         db    2, 4, 5         ; array of three values
  n         dw    3               ; length of both arrays
  result    dq    0               ; memory to result
      segment .text
      global main
  main:
      mov   rax, 0
      mov   rbx, 0
      mov   rdx, 0
  loop_start:
      cmp   rax, [n]
      jge   loop_end
      
      add   rbx, a[rax*4]   ; adding element of a at current index to rbx
      add   rbx, 3          ; adding 3 to current index value of array a in rbx
      
      add   rdx, BYTE b[rax]
      sub   rdx, 4

      sub   rbx, [rdx]
      add   [result], rbx
      
      xor   rbx, rbx
      xor   rdx, rdx
      add   rax, 1
  loop_end:
      ret 

Ответы [ 2 ]

2 голосов
/ 12 июля 2020

... но поскольку оба массива имеют разные значения (массив 1 - dw, а массив 2 - db), я не уверен, как это учитывать

Ответ Эрика Эйдта объясняет, почему вы «продолжаете сталкиваться с ошибками запятых и операндов». Хотя вы можете вернуться к использованию меньших регистров (добавив префиксы размера операндов), мой ответ использует другой подход.

В наборе команд есть movzx (перемещение с нулевым расширением) и movsx (перемещение с sign extension) инструкции по работе с этими различными размерами. См. Ниже, как их использовать.

Я тоже внес несколько изменений.

  • Не упустите возможность упростить расчет:

    ((a[i] + 3) - (b[i] - 4)) эквивалентно (a[i] - b[i] + 7)

  • Ни один из этих массивов не является пустым, поэтому вы можете просто поместить условие l oop под его телом.

  • Вы можете обрабатывать массивы, начиная с конца, если это удобно. Операция суммирования не имеет значения!

     segment .data
a      dw    12, 14, 16      ; array of three values        
b      db    2, 4, 5         ; array of three values
n      dw    3               ; length of both arrays
result dq    0               ; memory to result
    segment .text
    global main
main:
       movzx rcx, word [n]
loop_start:
       movzx rax, word [a + rcx * 2 - 2]
       movzx rbx, byte [b + rcx - 1]
       lea   rax, [rax + rbx + 7]
       add   [result], rax
       dec   rcx
       jnz   loop_start
       ret

Обратите внимание, что существуют дополнительные отрицательные смещения - 2 и - 1, чтобы компенсировать тот факт, что l oop контролирует принимает значения {3, 2, 1}, когда {2, 1, 0} было бы идеально. Это не вводит дополнительный компонент смещения в инструкцию, поскольку упоминание массивов a и b фактически уже является смещением.

Хотя это помечено как x86 -64, вы можете записать все это, используя 32-битные регистры и не требуя префиксов REX. То же результат .

     segment .data
a      dw    12, 14, 16      ; array of three values        
b      db    2, 4, 5         ; array of three values
n      dw    3               ; length of both arrays
result dq    0               ; memory to result
    segment .text
    global main
main:
       movzx ecx, word [n]
loop_start:
       movzx eax, word [a + ecx * 2 - 2]
       movzx ebx, byte [b + ecx - 1]
       lea   eax, [eax + ebx + 7]
       add   [result], eax
       dec   ecx
       jnz   loop_start
       ret
2 голосов
/ 11 июля 2020

Вы используете 16-битные и 8-битные данные, но 64-битные регистры. Вообще говоря, процессору требуется один и тот же размер данных, несмотря на операнды любой отдельной инструкции.

cmp rax,[n] имеет различный размер данных, что недопустимо: rax - это 64-битный регистр, и [n] - это 16-битный элемент данных. Итак, мы можем изменить это на cmp ax,[n], и теперь все будет 16-битным.

add rbx,a[rax*4] также смешивает операнды разных размеров (не разрешено). rbx - 64-битный, а a[] - 16-битный. Вы можете изменить регистр на bx, и это будет разрешено. Но также отметим, что *4 слишком много, это должно быть *2, поскольку dw - это 16-битные данные (2-байтовые), а не 32-битные (4-байтовые). Поскольку вы очищаете rbx, вам не нужен add, вы можете просто mov.

add rdx, BYTE b[rax] также смешивает разные размеры. rax имеет ширину 64 бита, а b[] - 8 бит. Используйте dl вместо rdx. Здесь нечего добавить, поэтому вы должны использовать mov вместо add. Теперь, когда есть значение в dl, и вы ранее очистили rdx, вы можете переключиться на использование dxdl), это будет иметь 16-битное значение b [i].

sub rbx, [rdx] имеет ошибочное почтение. Здесь вы просто хотите sub bx,dx.

Вы не используете метку loop_start, поэтому нет l oop. (Добавьте обратную ветвь в конце l oop.)

...