21

Re: [Асемблер8086]Від нуба до професіонала(або шлях на асемблерну вершину)

можна і бітами здвигу бітів в право і ліво застосувати

- Поганому трояну фаєрвол заважає
- Ніколи не програмуйте та не пийте пиво
Якщо ви з першого разу написали програму, в якій немає жодної помилки, повідомте про це системного програмісту: він виправить помилки в компіляторі
Подякували: Betterthanyou1

22

Re: [Асемблер8086]Від нуба до професіонала(або шлях на асемблерну вершину)

А ще існує команда lea, яка зазвичай рахує зсув, але може обмежено обчислювати прості арихметичні вирази. Наприклад, lea ax, [bx+1] додасть до bx регістру одиницю та одержаний резутьтат запише у ax

Говорила баба діду: «Я поїду к Білодіду, Ізучу двомовну мову І вернусь обратно знову». А дід бабі: «Не *изди, К Білодіду нєт їзди, — Туди не ходять поїзди»
Подякували: reverse2500, koala, Betterthanyou, leofun014

23 Востаннє редагувалося koala (22.07.2017 18:52:06)

Re: [Асемблер8086]Від нуба до професіонала(або шлях на асемблерну вершину)

0xDADA11C7 випередив :)

Подякували: 0xDADA11C71

24 Востаннє редагувалося Betterthanyou (23.07.2017 23:41:47)

Re: [Асемблер8086]Від нуба до професіонала(або шлях на асемблерну вершину)

не актуально

DD означає Define DoubleWord тобто 4 байти або 32 біти ? Чому я не можу записати в змінну SUM число 211261 ?
Завдання
Виконати обчислення SUM=(X1+X2+X3)^2-15*C

В рядку 42-43, DX=00:03, a CX=39:3D, разом 0003393Dh або 211261d
Спочатку я намагаюся записати молодших 16 біт - записує, а старші (рядок 43) не хоче

data segment
    X1 DB 250d
    X2 DB 199d
    X3 DB 12d
    C1 DB 84d          
    SUM DD ?
ends

code segment
start:
; set segment registers:
    mov ax, data
    mov ds, ax
    
    ;X1+X2+X3
    MOV AL, X1
    MOV AH, 0
    
    MOV BL, X2
    MOV BH, 0
    
    ADD AX, BX
    MOV BX, AX
    
    MOV AL, X3
    MOV AH, 0 
    ADD AX, BX
    
    ;^2
    MUL AX
    MOV CX, AX    
    
    ;15*C
    MOV AL, 15d
    MOV BL, C1    
    MUL BL
    
    ;EXPRESSION1-EXPRESSION2    
    SUB CX, AX
    
    ;SUM
    MOV WORD PTR SUM, DX
    MOV WORD PTR SUM+2, CX
    
    mov ax, 4c00h ; exit to operating system.
    int 21h    
ends

end start ; set entry point and stop the assembler.

кому цікаво як виправити
поміняти місцями 42-43 рядки

MOV WORD PTR SUM, CX
MOV WORD PTR SUM+2, DX

на дебагері включити розмір для змінних dword

SUM=(X1+X2+X3)^2-15*C1

;Calculate SUM=(X1+X2+X3)^2-15*C1

data segment
    X1 DB 250d
    X2 DB 199d
    X3 DB 12d
    C1 DB 84d          
    SUM DD ?
ends

code segment
start:
; set segment registers:
    mov ax, data
    mov ds, ax
    
    ;X1+X2+X3
    MOV AL, X1
    MOV AH, 0
    
    MOV BL, X2
    MOV BH, 0
    
    ADD AX, BX
    MOV BX, AX
    
    MOV AL, X3
    MOV AH, 0 
    ADD AX, BX
    
    ;^2
    MUL AX
    MOV CX, AX    
    
    ;15*C
    MOV AL, 15d
    MOV BL, C1    
    MUL BL
    
    ;EXPRESSION1-EXPRESSION2    
    SUB CX, AX
    
    ;SUM
    MOV WORD PTR SUM, CX
    MOV WORD PTR SUM+2, DX
    
    mov ax, 4c00h ; exit to operating system.
    int 21h    
ends

end start ; set entry point and stop the assembler.
Подякували: 0xDADA11C7, koala, leofun013

25

Re: [Асемблер8086]Від нуба до професіонала(або шлях на асемблерну вершину)

Розгалуження
Задача
y = {
a*b+c, if x=0
a+b*c, if x=2
(a+b)*c, if x!=0 and x!=2
}
Розв'язок
(крім "х" бажано нічого не міняти, якщо будуть великі числа програма працюватиме не правильно, звичайно це можна виправити, але мені лінь)

data segment
   Y DW ?
   X DB 1
   A DB 4
   B DB 5
   C DB 8
ends

code segment
start:
; set segment registers:
    mov ax, data
    mov ds, ax
    
    ;A*B+C, X=0
    ;A+B*C, X=2
    ;(A+B)*C, X!=0 AND X!=2
    
    CMP X, 0
    JE X0
    CMP X, 2
    JE X2
    JMP XN0N2
    
    X0:
    ;A*B+C, X=0
    MOV AH, 0
    MOV AL, A
    MUL B
    MOV BH, 0
    MOV BL, C
    ADD AX, BX
    MOV Y, AX
    JMP IFEND
    X2:
    ;A+B*C, X=2
    MOV AH, 0
    MOV AL, B
    MUL C     
    MOV BH, 0
    MOV BL, A
    ADD AX, BX
    MOV Y,AX
    JMP IFEND
    XN0N2:    
    ;(A+B)*C, X!=0 AND X!=2
    MOV AH, A
    MOV AL, B
    ADD AL, AH
    MUL C
    MOV Y, AX
    
    IFEND:
    
    mov ax, 4c00h ; exit to operating system.
    int 21h    
ends

end start ; set entry point and stop the assembler.
Подякували: 0xDADA11C71

26 Востаннє редагувалося Betterthanyou (26.07.2017 06:17:06)

Re: [Асемблер8086]Від нуба до професіонала(або шлях на асемблерну вершину)

до речі, для тих хто хоче вивчати асемблер, не потрібно вчити таблицю переходів

оцю
https://image.slidesharecdn.com/108086instructionset-141212191052-conversion-gate02/95/10-8086-instruction-set-61-638.jpg?cb=1418411543

Достатньо зрозуміти логіку.

Спочатку йде J(JUMP)
потім йде N(NOT) - якщо заперечення
ще дальше йде L(LESS) - менше, G(GREATER) - більше; - для цілих чисел зі знаком
A(ABOVE) - менше, B(BELOV) - більше; - для цілих чисел без знаку
і в кінці E(EQUAL) - рівне
тобто виходить така конструкція Jx(заперечення)x(більше/менше)x(рівне)

Або, якщо порівняння йде з флагами (flag), то пишеться перша буква флага.

Є тільки одне виключення JCXZ

Подякували: 0xDADA11C7, Chemist-i2

27

Re: [Асемблер8086]Від нуба до професіонала(або шлях на асемблерну вершину)

Саме так, варто вчити лише прапорці процесора, а ота таблиця сама потім в голову сяде.

Говорила баба діду: «Я поїду к Білодіду, Ізучу двомовну мову І вернусь обратно знову». А дід бабі: «Не *изди, К Білодіду нєт їзди, — Туди не ходять поїзди»
Подякували: Betterthanyou, koala2

28

Re: [Асемблер8086]Від нуба до професіонала(або шлях на асемблерну вершину)

Цикли
Серед 100 заданих чисел визначити кількість додатних, від'ємних і нульових.
(сто чисел заданих немає, але я думаю код буде працювати і при 100 )

data segment
    ARR1 DB 10, 81, 0, -9, 5, 0, -8, 0, 0, -9, -10, 121, 44
    SIZE_OF_ARR1 DB $-ARR1
    NUMADD DB 0
    NUMSUB DB 0
    NUMZERO DB 0 
ends

code segment
start:
; set segment registers:
    mov ax, data
    mov ds, ax
                        
    MOV CH, 0                        
    MOV CL, SIZE_OF_ARR1    
        
    LOOPBEGIN:
    MOV SI, CX
    DEC SI
    CMP ARR1[SI], 0    
    JL NUMLESS
    JG NUMGREATER
    
    ;EQUAL ZERO
    MOV AL, NUMZERO
    INC AL
    MOV NUMZERO, AL
    JMP IFEND:
    
    ;MORE THAN ZERO
    NUMGREATER:
    MOV AL, NUMADD
    INC AL
    MOV NUMADD, AL
    JMP IFEND:
    
    ;LESS THAN ZERO
    NUMLESS:
    MOV AL, NUMSUB
    INC AL
    MOV NUMSUB, AL
        
    
    IFEND:
    LOOP LOOPBEGIN
    
    mov ax, 4c00h ; exit to operating system.
    int 21h    
ends

end start ; set entry point and stop the assembler.

зараз ще три задачки скину...

Подякували: 0xDADA11C71

29 Востаннє редагувалося Betterthanyou (27.07.2017 04:20:42)

Re: [Асемблер8086]Від нуба до професіонала(або шлях на асемблерну вершину)

Задача - перевернути число. (12345-54321)
Мала бути задача на цикли, але щось не вийшло робити через цикли. Мені не зручна умова CX=0, тому я не використовував  LOOP, LOOPE, LOOPNE і JCXZ. Я зробив цикли через розгалуження, логіка така:
В кінці, коли вже буде ділитися останнє число (наприклад 5/10 = 0 - частка і 5 - залишок), перевіряється частка  (тобто АХ), очевидно якщо частка = 0 значить "число закінчилося" і пора виходити з розгалуження.

Також, додатково, я використав розгалуження-цикл для знаходження степеня. Можливо в емуляторі 8086 є бібліотеки для математики, але я поки що вивчаю синтаксис, вже на MASM32 буду пробувати використовувати бібліотеки (якщо вони існують).

Загалом алгоритм такий

 - є число input - вхідне
 - є число output - вихідне
 - є число i = 1 

q - частка, r - залишок = input/10;
output=output * 10^i + q;
i++;
input = q;
поки q!=0

Програма

data segment
    INPUT DW 12345
    OUTPUT DW 0   
ends

code segment
start:
; set segment registers:
    mov ax, data
    mov ds, ax
             
    MOV CX, 1
    MOV AX, INPUT  
    
    LOOPBEGIN:        
    MOV BX, 10        
    DIV BX     ;AX/10
    PUSH AX    ;SAVE REMAINDER
    PUSH DX    ;SAVE QUOTIENT                     
    PUSH CX    ;SAVE COUNTER
    
    ;10 ^ INCREMENT
    MOV AX, 0
    LOOPBEGIN2:
    CMP CX, 1
    JE CONTINUE
    MOV AX, 1
    MUL BX        
    DEC CX    
    JMP LOOPBEGIN2
                
    CONTINUE:
    MOV BX, AX
    POP CX  ;GET COUNTER
    MOV AX, OUTPUT    
    ;OUTPUT * (10 ^ INCREMENT) + QUOTIENT
    MUL BX  
    INC CX  ;INC++   
    POP BX  ;GET QUOTIENT
    ADD AX, BX
    MOV OUTPUT,AX
    POP AX ;GET REMAINDER
    ;WHILE AX!=0        
    CMP AX, 0
    JE LOOPEND 
    JMP LOOPBEGIN
    LOOPEND:
    
    mov ax, 4c00h ; exit to operating system.
    int 21h    
ends

end start ; set entry point and stop the assembler.
Подякували: 0xDADA11C71

30

Re: [Асемблер8086]Від нуба до професіонала(або шлях на асемблерну вершину)

Betterthanyou написав:

Можливо в емуляторі 8086 є бібліотеки для математики

Є одна така, FPU називається
Колись ми її на форумі трохи обговорювали http://replace.org.ua/post/42089/

Maybe a = Just a | Nothing
Подякували: Betterthanyou1

31 Востаннє редагувалося Betterthanyou (02.08.2017 00:08:43)

Re: [Асемблер8086]Від нуба до професіонала(або шлях на асемблерну вершину)

Питання про "чергу", чи правильну організацію "стеку"
є такий код

    PUSH CRAMER[SI]
    PUSH CRAMER[SI+2]
    PUSH CRAMER[SI+4]
    PUSH CRAMER[SI+8]
    PUSH CRAMER[SI+10]    
    CALL DETERMINANT3X3
mov ax, 4c00h

Я хочу зробити так, щоб CALL записався самим першим у стек (тобто адрес на наступну команду + зміщення)

PUSH адрес команди "mov ax, 4c00h"
PUSH CRAMER[SI+2]
    PUSH CRAMER[SI+4]
    PUSH CRAMER[SI+8]
    PUSH CRAMER[SI+10]    
    виклик функції без запису в стек DETERMINANT3X3

Так можна зробити ?

що я хочу зробити
Я знаю про регістр BP, але я не знаю як організувати виклик іншої функції в поточній функції

DETERMINANT3X3 PROC
    POP BP      
    CALL DERERMINANT2X2
    ...
    PUSH BP
    RET     
DETERMINANT3X3 ENDP

DERERMINANT2X2 PROC
    POP BP
    
    ...
        
    PUSH BP
    RET   
DERERMINANT2X2 ENDP

виходить перезапис BP, і програма зациклюється на рядку 5-6. Я хочу це виправити.

32

Re: [Асемблер8086]Від нуба до професіонала(або шлях на асемблерну вершину)

Ви хочете виконати команду call не виконуючи команду call?

        PUSH CRAMER[SI]
        PUSH CRAMER[SI+2]
        PUSH CRAMER[SI+4]
        PUSH CRAMER[SI+8]
        PUSH CRAMER[SI+10]    
        CALL DETERMINANT3X3
    mov ax, 4c00h

Як би я зробив

        PUSH CRAMER[SI]
        PUSH CRAMER[SI+2]
        PUSH CRAMER[SI+4]
        PUSH CRAMER[SI+8]
        PUSH CRAMER[SI+10]    
        PUSH OFFSET END_OF_PROGRAM
        JMP DETERMINANT3X3
END_OF_PROGRAM:
    mov ax, 4c00h
Говорила баба діду: «Я поїду к Білодіду, Ізучу двомовну мову І вернусь обратно знову». А дід бабі: «Не *изди, К Білодіду нєт їзди, — Туди не ходять поїзди»
Подякували: Betterthanyou, leofun012

33 Востаннє редагувалося koala (02.08.2017 07:40:26)

Re: [Асемблер8086]Від нуба до професіонала(або шлях на асемблерну вершину)

Для початку:
PUSH щось еквівалентно SUB SP, розмір чогось + MOV [SP], щось.
POP щось еквівалентно MOV щось, [sp] + ADD SP, розмір чогось
CALL X еквівалентно PUSH NEXT_INSTRUCTION + JMP X, де NEXT_INSTRUCTION - адреса наступної команди
RET еквівалентно POP IP

Стек викликів використовується для зберігання:
- адрес повернення з функцій, тому так і зветься
- збереження значень регістрів

PUSH BP ;нам цей BP ще знадобиться
MOV BP, ... ;якась робота, що змінює BP
...
POP BP ; відновлюємо значення BP

- зберігання локальних змінних

MOV BP, SP;тепер BP вказує на верхівку стека
PUSH AX ;"створюємо змінну", частіше просто відніманням від SP потібної кількості байтів
MOV [BP-2],2 ;BP-2 - адреса нашої змінної, поки ми не змінимо BP

Якщо функція з локальними змінними буде викликана рекурсивно, то вона створить собі нову змінну.
- передачі параметрів у функцію
Працює так само, як і з локальними змінними, тільки треба чітко домовитися, де саме вони будуть розташовані і які регістри можуть бути змінені, а які - ні. Оскільки існує інструкція CALL, яка, вочевидь, має бути останньою перед початком роботи функції, то природно робити так:

PUSH аргумент
CALL функція
POP аргумент ; або просто ADD SP,2 - викидаємо зі стеку аргументи функції

функція:
PUSH BP ; BP знадобиться функції, що нас викликала
MOV BP, SP ; в стеку зараз: зовнішній BP = [BP], адреса повернення = [BP+2], аргумент = [BP+4]
... ;працюємо
POP BP ; відновлюємо BP
RET 

Хоча ніхто не може заборонити вам зробити власний стандарт виклику функцій, заміняти PUSH, POP, CALL і RET на аналоги і викликати що вам хочеться:

PUSH адреса_повернення
PUSH аргумент
JMP функція
адреса_повернення: ...

функція:
...
POP аргумент ;викидаємо аргумент
RET ; відновлюємо адресу IP на наступну команду після виклику функції
Подякували: 0xDADA11C7, Betterthanyou, leofun013

34

Re: [Асемблер8086]Від нуба до професіонала(або шлях на асемблерну вершину)

ще

CALL [ESP]

еквівалент

RET
- Поганому трояну фаєрвол заважає
- Ніколи не програмуйте та не пийте пиво
Якщо ви з першого разу написали програму, в якій немає жодної помилки, повідомте про це системного програмісту: він виправить помилки в компіляторі

35

Re: [Асемблер8086]Від нуба до професіонала(або шлях на асемблерну вершину)

reverse2500 написав:

ще

CALL [ESP]

еквівалент

RET

CALL - це PUSH+JMP, а RET - це POP+JMP. Так що не виходить. Ви краще Лінукс критикуйте, там без конкретики у вас краще виходить.

Подякували: 0xDADA11C7, Betterthanyou, leofun013

36

Re: [Асемблер8086]Від нуба до професіонала(або шлях на асемблерну вершину)

коли йде використання початок стекового фрейму, а приблизно так виглядає:
адресс: байт код
адресс: call [adress} // перехід по адресу, і якщо буде повернення назад в разі успішного повернення, то в стеку буде, адреса що за call інструкцією виконується ret, це святе в пошуку по переповнення буфера.

не вірю словам теж, по можливості загляну в отладчик

- Поганому трояну фаєрвол заважає
- Ніколи не програмуйте та не пийте пиво
Якщо ви з першого разу написали програму, в якій немає жодної помилки, повідомте про це системного програмісту: він виправить помилки в компіляторі

37

Re: [Асемблер8086]Від нуба до професіонала(або шлях на асемблерну вершину)

reverse2500 написав:

коли йде використання початок стекового фрейму, а приблизно так виглядає:
адресс: байт код
адресс: call [adress} // перехід по адресу, і якщо буде повернення назад в разі успішного повернення, то в стеку буде, адреса що за call інструкцією виконується ret, це святе в пошуку по переповнення буфера.

не вірю словам теж, по можливості загляну в отладчик

Ви початківцю пишете не забувайте, а оце бурмотіння з неправильним синтаксисом й наполовину видране з дампу стека знежучувача з додаванням святих пошуків в переповненні бухвера початківець не розпарсить.

Говорила баба діду: «Я поїду к Білодіду, Ізучу двомовну мову І вернусь обратно знову». А дід бабі: «Не *изди, К Білодіду нєт їзди, — Туди не ходять поїзди»

38

Re: [Асемблер8086]Від нуба до професіонала(або шлях на асемблерну вершину)

Ви початківцю пишете не забувайте

я ж не пишу, про інклуд dll бібліотеки і це початківцю.
коли буде цікаво, колись згадає і згодиться

- Поганому трояну фаєрвол заважає
- Ніколи не програмуйте та не пийте пиво
Якщо ви з першого разу написали програму, в якій немає жодної помилки, повідомте про це системного програмісту: він виправить помилки в компіляторі

39 Востаннє редагувалося Betterthanyou (03.08.2017 00:10:30)

Re: [Асемблер8086]Від нуба до професіонала(або шлях на асемблерну вершину)

Як записати в стек додатне число?

PUSH 00A6h

Як не пробую, всеодно в стеку опиняється "FFA6"

40

Re: [Асемблер8086]Від нуба до професіонала(або шлях на асемблерну вершину)

це не проблема стеку - це проблема вашого сприйняття стеку, гадаю ви просто не туди дивитесь. спробуйте пересвідчитись в цьому за допомогою всунення в стек 0A6h і діставання в якийсь регістр загального призначення - наприклад, аумулятор ax

Говорила баба діду: «Я поїду к Білодіду, Ізучу двомовну мову І вернусь обратно знову». А дід бабі: «Не *изди, К Білодіду нєт їзди, — Туди не ходять поїзди»
Подякували: Betterthanyou, koala2