x / 2 + 100 * (a + b) - 3 / (c + d) + e * e в сборке

Oct 21 2020

напишите алгоритм для: x / 2 + 100 * (a + b) - 3 / (c + d) + e * e, зная, что: a, c - слово, b, d - байт, e - двойное слово, x - qword

    mov eax, dword [x]
    mov edx, dword [x + 4] ; edx:eax = x
    mov ebx, 2
    idiv ebx ; eax = edx:eax / ebx = x / 2
    mov ebx, eax ; save the result in ebx so we can do the other operations
    mov al, [b]
    cbw ; ax = b
    add ax, [a] ; ax = a + b
    mov dx, 100
    imul dx ; dx:ax = ax * dx = 100 * (a + b)
    push dx
    push ax
    pop eax ; 100 * (a + b)
    add ebx, eax ; ebx = x / 2 + 100 * (a + b)
    mov al, [d] ; al = d
    cbw ; ax = d
    add ax, word [c] ; ax = c + d
    mov cx, ax ; cx = c + d
    mov ax, 3
    cwd
    idiv cx ; ax = dx:ax / cx 
    cwd
    push dx
    push ax
    pop eax ; eax = 3 / (c + d)
    sub ebx, eax
    mov eax, ebx
    cdq ; edx:eax = x / 2 + 100 * (a + b) - 3 / (c + d)
    mov ebx, eax
    mov ecx, edx ; ecx:edx = x / 2 + 100 * (a + b) - 3 / (c + d)
    mov eax, [e]
    imul dword [e] ; edx:eax = e * e
    add eax, ebx
    adc edx, ecx
    mov dword [result + 0], eax 
    mov dword [result + 4], edx

я сделал это излишне сложным?

Ответы

6 SepRoland Oct 22 2020 at 03:52

напишите алгоритм для: x / 2 + 100 * (a + b) - 3 / (c + d) + e * e

a, c - word,
b, d - byte,
e - doubleword,
x - qword

Поскольку ваше наибольшее число - 64 бита ( x - это qword), ваш окончательный результат тоже должен быть 64 бита!

Ваша первая операция заключалась в том, чтобы разделить qword в x на 2. Вы, кажется, ожидаете, что этот результат поместится только в одно двойное слово, потому что вы переместили частное в EBXрегистре. Вы не можете сделать это предположение и, что еще хуже, деление может легко привести к исключению деления, если частное не умещается в 32 бита.
Что касается решения, вы должны знать, что деление на 2 - это просто сдвиг вправо.

mov   ebx, [x]
mov   ebp, [x + 4] ; EBP:EBX is x
sar   ebp, 1
rcr   ebx, 1       ; EBP:EBX is x / 2

Это означает, что вам придется масштабировать и другие вычисления, чтобы добавить их к EBP:EBXusing:

add   ebx, ...
adc   ebp, ...

Поскольку сложение ассоциативно, вы можете начать с вычисления части e * e . Вы не переставляли выражение, и в итоге пришлось еще немного переставить регистры. Ничего страшного, но, по-моему, лучше:

mov   eax, [e]
imul  eax
add   ebx, eax
adc   ebp, edx

Затем идет 100 * (a + b) :

movsx eax, word [a]
movsx edx, byte [b]
add   eax, edx       ; eax = a + b
mov   edx, 100
imul  edx            ; edx:eax = 100 * (a + b)
add   ebx, eax
adc   ebp, edx

Я оставлю тебе 3 / (c + d) ...

... и, наконец, конец будет:

sub   ebx, eax
sbb   ebp, edx
mov   [result + 0], ebx 
mov   [result + 4], ebp

я сделал это излишне сложным?

  • Было немного сложно читать вашу программу, потому что вы не вставляли пустые строки между различными операциями.

  • Вам не нужно писать тег размера (байт, слово, двойное слово), если задействованный регистр уже подразумевает размер. В mov dword [result + 0], eaxтеге dword есть избыточность.

  • Лучше всего, чтобы комментарии в программе были выровнены друг над другом.

  • Перечитайте внимательно, чтобы избежать опечаток, например:

      mov ecx, edx ; ecx:edx = x / 2 + 100 * (a + b) - 3 / (c + d)
    

    Должно быть ECX:EBX.

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

      mov   eax, [e]
      imul  eax        ; Don't write "imul dword [e]"