Разделить 128 битное число на 5 - Assembler
Формулировка задачи:
Я решил данную задачу так
Кто-то предложит лучше?
число находится в памяти по указателю rcx в классическом обратном порядке, младший байт rcx[15] старший rcx[0]
_TEXT SEGMENT d0$ = 8; положение в стеке частного от младшей 64bit части r0$ = 16; положение в стеке остатка от младшей 64bit части d1$ = 24; положение в стеке частного от старшей 64bit части r1$ = 32; положение в стеке остатка от старшей 64bit части ?Div5@Integer128@@QEAAHXZ PROC ;__int32 Integer128::Div5() mov rax, QWORD PTR [rcx] xor rdx, rdx mov rbx,5 div rbx; частное в rax, остаток в rdx mov QWORD PTR d0$[rsp], rax mov QWORD PTR r0$[rsp], rdx mov rax, QWORD PTR [rcx+8] xor rdx, rdx div rbx; частное в rax, остаток в rdx mov QWORD PTR d1$[rsp], rax mov QWORD PTR r1$[rsp], rdx mov rax, 3333333333333333h mul rdx ; до умножения rdx = r1$ результат в rax, rdx=0 mov rbx, rax inc rbx ; rbx = 0x3333333333333333*r1$+1 mov rdx, QWORD PTR r0$[rsp]; rdx = r0$ mov r8, QWORD PTR r1$[rsp]; r8 = r1$ add rdx, r8; rdx = r0$+r1$ mov r8, rdx; r8 = r0$+r1$ sub r8, 5; r8 = r0$+r1$-5 cmp rdx,5 cmovae rax, rbx; if (r1$+r2$<5) rax = 0x3333333333333333*r1$ else rax = 0x3333333333333333*r1$+1 cmovae rdx, r8; if (r1$+r2$<5) rdx = r1$+r2$ else r1$+r2$-5 mov rbx, QWORD PTR d0$[rsp]; rbx = d0$ mov r8, QWORD PTR d1$[rsp]; r8 = d1$ add rax, rbx; rax = младшая часть частного adc r8, 0; r8 = старшая часть частного mov QWORD PTR [rcx], rax mov QWORD PTR [rcx+8], r8 mov rax, rdx ret ?Div5@Integer128@@QEAAHXZ ENDP ;__int32 Integer128::Div5() _TEXT ENDS
Решение задачи: «Разделить 128 битное число на 5»
textual
Листинг программы
_TEXT SEGMENT ?Div5@Integer128@@QEAAHXZ PROC ;__int32 Integer128::Div5() mov rax, QWORD PTR [rcx] mov r10, QWORD PTR [rcx+8] mov r8, rax; делимое в r8 mov r9, 0CCCCCCCCCCCCCCCDh mul r9 shr rdx, 2; частное в rdx mov r11, rdx; частное в r11 mov rax, rdx mov rdx, 5 mul rdx; rax = d0*5 sub r8, rax; остаток от деления в r8 mov rax, r10; старшее делимое в rax mul r9 shr rdx, 2; частное в rdx; частное в rdx mov r9, rdx; частное в r9 mov rax, rdx mov rdx, 5 mul rdx; rax = d1*5 sub r10, rax; остаток в r10 ; r11 = d0 r8 = r0 r9 = d1 r10 = r1 add r8, r10; r8 = r0+r1 mov rdx, r8 sub rdx,5; rdx = r0+r1-5 cmp r8d, 5 cmovae r8, rdx ;if(r0+r1<5) r8 = r0+r1 else r8 = r0+r1-5 ;if(r8-r10>=0) -> r0+r1<5 else r0+r1>=5 mov rax, 3333333333333333h mul r10 mov rdx, rax inc rdx cmp r8, r10 cmovl rax, rdx ;if (r1+r0<5) rax = 0x3333333333333333*r1 else rax = 0x3333333333333333*r1+1 add rax, r11; rax = младшая часть частного adc r9, 0; r9 = старшая часть частного mov QWORD PTR [rcx], rax mov QWORD PTR [rcx+8], r9 mov rax, r8 ret ?Div5@Integer128@@QEAAHXZ ENDP ;__int32 Integer128::Div5() _TEXT ENDS
Объяснение кода листинга программы
Список элементов:
- [rcx] - это адрес делимого числа, в сегменте данных
- [rcx+8] - это адрес старшего полубайта делимого числа, в сегменте данных
- r8 - это делимое число, в регистре
- r9 - это мультектор, в регистре
- rdx - это частное числа, в регистре
- r10 - это старший делитель, в регистре
- r11 - это младший делитель, в регистре
- rax - это результат операций, в регистре
- QWORD PTR [rcx] - это младшая часть частного числа, в сегменте данных
- QWORD PTR [rcx+8] - это старшая часть частного числа, в сегменте данных
- r8 - это остаток от деления, в регистре
- r10 - это остаток от деления, в регистре
- rdx - это мультектор, в регистре
- r9 - это мультектор, в регистре
- rax - это результат операций, в регистре
- rdx - это мультектор, в регистре
- r8 - это остаток от деления, в регистре
- r10 - это остаток от деления, в регистре
- rdx - это мультектор, в регистре
- r9 - это мультектор, в регистре