Author Topic: Experimenting with O2 assembler  (Read 8455 times)

0 Members and 1 Guest are viewing this topic.

Arnold

  • Guest
Experimenting with O2 assembler
« on: February 26, 2016, 12:23:06 AM »
Hi Charles, Peter,

can you help out a little bit?

I am interested to use some assembly code with OxygenBasic and I have started to study the book "PC Assembly Language" of Paul A. Carter which I found at:
http://www.drpaulcarter.com/pcasm/

The first program first.asm looks rather complicated although only two statements are of interest. I tried to do it in Oxygen:

Code: OxygenBasic
  1. ; file: first.o2bas
  2. ; First assembly program. This program asks for two integers as
  3. ; input and prints out their sum
  4.  
  5. #include "$/inc/console.inc"
  6.  
  7. 'Basic
  8.  
  9. int input1, input2
  10.  
  11. zstring prompt1 = "Enter a number: "
  12. zstring prompt2 = "Enter another number: "  
  13. zstring outmsg1 = "You entered : "
  14. zstring outmsg2 = " and "
  15. zstring outmsg3 = " The sum of these is "
  16.  
  17. print prompt1 : num = rtrim ltrim input() : input1 = val(num)
  18. print prompt2 : num = rtrim ltrim input() : input2 = val(num)
  19.  
  20. print outmsg1 input1 outmsg2 input2 outmsg3 input1+input2 & cr
  21.  
  22. ; Assembly
  23.  
  24. function add_two(int a, b) as int
  25.    mov eax,  a    ; eax =  a  same as mov eax, [a]?
  26.    add eax, [b]   ; eax += b
  27.  
  28.    'function = eax
  29.   return eax
  30. end function
  31.  
  32. printl "Using Assembly: " & cr
  33.  
  34. ; push / pop  for save / restore registers not necessary?
  35. print outmsg3 add_two(input1,input2) & cr
  36.  
  37. print "Enter ... ": waitkey
  38.  

   It seems that with OxygenBasic it is not necessary to push / pop the registers when calling a function with assembly code?
   Is there no difference between mov eax,a and move eax,[a]?
   The return value is stored in eax? 

Maybe my questions seem to be trivial but I am not sure if my assumptions are correct.

Roland     



.

Peter

  • Guest
Re: Experimenting with O2 assembler
« Reply #1 on: February 26, 2016, 07:20:57 AM »
Hi Arnold,
Code: [Select]
include "asm.inc"
window 640,480,1


Function add_two(sys a, b) as sys
  mov eax, a      ' eax =  a  same as mov eax, [a]?  NO!
  add eax, b      ' eax += b  NO!
  return eax
End Function

sub xAdd( byref a as sys, byref b as sys )
    addr esi,a
    addr edi,b
    mov  eax,[esi]
    add  eax,[edi]
end sub
 
sub AddMul( sys *a, b, c)
    addr esi,a
    mov  eax,[esi]
    add  eax, b
    imul eax, c
end sub

Text 10,10,24,add_two(100,200)
Text 10,26,24,xAdd(200,300)
Text 10,52,24,AddMul(200,300,2)

WaitKey
WinEnd
« Last Edit: February 26, 2016, 07:58:30 AM by Peter »

Charles Pegge

  • Guest
Re: Experimenting with O2 assembler
« Reply #2 on: February 26, 2016, 07:26:50 AM »
Hi Roland,



Oxygen will accept both operand forms as equivalent:
mov eax,a
mov eax,[a]

Integer values and pointers are normally returned in eax

Oxygen functions expect the ebx register to hold the base address for all static variables, and core functions. So it must be preserved by pushing and popping.

Similarly, the ebp register is used to reference all local variables, and the prior stack pointer esp.

Oxygen's exported functions obey the stdcall calling convention, by default. But it is totally different in 64 bit mode.


Arnold

  • Guest
Re: Experimenting with O2 assembler
« Reply #3 on: February 27, 2016, 12:54:13 AM »
Hi Charles,

thank you for the info. Can you help me with this problem too:
How would the above example look without using a function?

I learned that there can be:

a .data section with initialized data
a .bss section with unitialized data
a .code section

but I must admit that it is not obvious to me how I can apply this in Oxygen.

I would like to use the input function to get input1 and input2, then

create variable a and b, store input1 and input2 to a and b
create variable outmsg3, store text to it (or create a constant with text)
do the calculation

use the print function to print outmsg3 and the result.

It would be very helpful to see how the low level steps are done with Oxygen.

Roland

Arnold

  • Guest
Re: Experimenting with O2 assembler
« Reply #4 on: February 27, 2016, 03:09:14 AM »
Hi Peter,

thanks for the examples. Using your latest asm.inc / asm.dll I tested them with Windows Vista and Win7.

In the first example I can indeed use a,b or [a]  and get the same result.
The same is valid for the second example. But there would be a difference if I used esi, edi instead of [esi], [edi].
The third example is interesting. I tested different combinations:

AddMul( sys a, b, c) -> ok
AddMul( sys *a, b, c) -> ok
AddMul( sys a, *b, c) -> ok
AddMul( sys a, b, *c) -> ok
AddMul( sys *a, *b, c) -> different
AddMul( sys *a, b, *c) -> different
AddMul( sys a, *b, *c) -> different
AddMul( sys *a, *b, *c) -> different

I will need some time to reflect about the logic and what happens here. But the examples are very useful to test these situations. Maybe this is only my subjective opinion but I think it is much easier to do these tests with Oxygen than using an independant assembler.

Roland

Peter

  • Guest
Re: Experimenting with O2 assembler
« Reply #5 on: February 27, 2016, 05:46:09 AM »
Quote
AddMul( sys *a, *b, *c) -> different

Hi Arnold,
Code: [Select]
include "asm.inc"
window 640,480,1

sub AddMul( sys *a, *b, c )
    addr  esi,a
    addr  edi,b
    mov   eax,[esi]
    mov   ecx,[edi]
    add   eax, ecx
    imul  eax, c
end sub

sub AddDiv( sys *a, *b, *c )
    xor   edx,edx
    addr  esi,a
    addr  edi,b
    mov   eax,[esi]
    mov   ecx,[edi]
    add   eax, ecx
    addr  ecx,c
    mov   ecx,[ecx]
    cmp   ecx,0
    jz    gOut
    idiv  ecx
    .gOut
end sub
 
Text 10,10,20, AddDiv(200,300,3)

WaitKey
WinEnd

.

Arnold

  • Guest
Re: Experimenting with O2 assembler
« Reply #6 on: February 28, 2016, 02:52:34 AM »
Hi Peter,

I assume the key is "addr". If I add in the first example: addr c, I can create the function with or without using the '*' pointer. This is the code for only using the console window (I do not know if I did it correctly):

Code: [Select]
$ filename "addmuldiv.exe"

'#include "$/inc/RTL32.inc"
#include "$/inc/console.inc"

function AddMul( int a, b, c )
    addr  esi,a           ; esi=addr a
    addr  edi,b           ; edi=addr b
    mov   eax,[esi]       ; eax=[esi] =[a]
    mov   ecx,[edi]       ; ecx=[edi] =[b]
    add   eax, ecx        ; eax+=ecx
    addr  ecx,c           ; ecx=addr c
    imul  eax,[ecx]       ; eax i*= [ecx] ; =[c]
    return eax
end function

function AddDiv( int a, b, c )
    xor   edx,edx         ; edx=0 , division rest?
    addr  esi,a           ; esi=addr a
    addr  edi,b           ; edi=addr b
    mov   eax,[esi]       ; eax=[esi] =[a]
    mov   ecx,[edi]       ; ecx=[edi] =[b]
    add   eax, ecx        ; eax+=ecx
    addr  ecx,c           ; ecx=addr c
    mov   ecx,[ecx]       ; ecx=[ecx] =[c]
    cmp   ecx,0           ; ecx ? 0
    jz    gOut            ; if 0 .gOut
    idiv  ecx             ; eax i\= ecx ; =[c]
    return eax
    .gOut
    return 1/0  ; should be fixed
end function

print AddMul(200,300,3) : print cr
print AddDiv(200,300,3) : print cr

printl "Enter ..." : WaitKey

I cannot use:
print AddMul(200,300,3) & cr  (crashes)
Maybe something is missing in the functions?

Roland

Peter

  • Guest
Re: Experimenting with O2 assembler
« Reply #7 on: February 28, 2016, 05:40:32 AM »
Quote
I can create the function with or without using the '*' pointer.


Hi Arnold,

sure, you have not any pointers in your source code.
but is not necessary to write it with indirect addressing.
Code: [Select]
include "asm.inc"
window 320,240,1

function AddMul( int a, b, c ) as int
    mov  eax,a           
    add  eax,b           
    imul eax,c
    return eax   
end function

function AddDiv( int a, b, c ) as int
    mov  ecx,c
    cmp  ecx,0
    jz   gOut
    xor  edx,edx         
    mov  eax,a                         
    add  eax,b           
    idiv ecx             
    return eax
    .gOut
end function

text 10,10,12,AddMul(10,10,10)
text 10,22,12,AddDiv(10,10, 4)

waitkey
winEnd


.
« Last Edit: February 28, 2016, 06:15:59 AM by Peter »

Peter

  • Guest
Re: Experimenting with O2 assembler
« Reply #8 on: February 28, 2016, 06:52:49 AM »
Better is we use a SUB, we need then no RETURN.
Code: [Select]
sub AddMul( int a, b, c )
    mov  eax,a           
    add  eax,b           
    imul eax,c
end sub

sub AddDiv( int a, b, c )
    mov  ecx,c
    cmp  ecx,0
    jz   gOut
    xor  edx,edx         
    mov  eax,a                         
    add  eax,b           
    idiv ecx             
    .gOut
end sub

Arnold

  • Guest
Re: Experimenting with O2 assembler
« Reply #9 on: February 29, 2016, 01:47:30 AM »
Hi Peter,

I think your latest code works better and is easier to underständ. Also print (result) & cr works. I could also combine the console window with asm.inc which might be useful sometimes with debugging.

example1:
Code: [Select]
#include "$/inc/console.inc"
include "asm.inc"

window 320,240,1

function AddMul( int a, b, c ) as int
    mov  eax,a           
    add  eax,b           
    imul eax,c
    return eax   
end function

function AddDiv( int a, b, c ) as int
    mov  ecx,c
    cmp  ecx,0
    jz   gOut
    xor  edx,edx         
    mov  eax,a                         
    add  eax,b           
    idiv ecx             
    return eax
    .gOut
end function

text 10,10,12,AddMul(10,10,10)
text 10,22,12,AddDiv(10,10, 4)
text 10,40,12, "Enter ..."

print AddMul(10,10,10) & cr
print AddDiv(10,10, 4) & cr

waitkey
winEnd

example2:
Code: [Select]
#include "$/inc/console.inc"

sub AddMul( int a, b, c )
    mov  eax,a           
    add  eax,b           
    imul eax,c
end sub

sub AddDiv( int a, b, c )
    mov  ecx,c
    cmp  ecx,0
    jz   gOut
    xor  edx,edx         
    mov  eax,a                         
    add  eax,b           
    idiv ecx             
    .gOut
end sub

AddMul(10,10,10)
print eax & cr

AddDiv(10,10,4)
print eax & cr

printl "Enter ..." : waitkey

Of course I underständ these examples are not fully assembly language but they hopefully will help me some day to combine OxygenBasic with some assembly snippets.

Roland


.

Peter

  • Guest
Re: Experimenting with O2 assembler
« Reply #10 on: February 29, 2016, 04:52:01 AM »
Hi Roland,

I am glad it works.

Arnold

  • Guest
Re: Experimenting with O2 assembler
« Reply #11 on: March 02, 2016, 08:29:17 AM »
Hello,

this is the second example of the book "PC Assembly Language" by Paul A. Carter. It takes some time to study the theory (and will take some more time to understand it).
For using the code in Oxygen I tried to create a function and a sub. Using the function works quite nice.

Code: [Select]
;
; file: math1.o2bas
; This program demonstrates how the integer multiplication and division
; instructions work.
;

#include "$/inc/console.inc"

;segment .data
;
; Output strings
;
zstring
prompt      = "Enter a number: ",
square_msg  = "Square of input is ",
cube_msg    = "Cube of input is ",
cube25_msg  = "Cube of input times 25 is ",
quot_msg    = "Quotient of cube/100 is ",
rem_msg     = "Remainder of cube/100 is ",
neg_msg     = "The negation of the remainder is "


;segment .bss
;entry   resd 1
int entry

print prompt
entry = val (rtrim ltrim input())


function do_math(int num) as string
    int square, cube, cube25, quot, rem_, neg_

    pushad                    ' save registers

    mov     eax, num
       
    imul    eax               ; edx:eax = eax * eax       
    mov     square, eax

    mov     ebx, eax          ; save answer in ebx
    imul    ebx, [num]        ; ebx *= [num]
    mov     eax, ebx
    mov     cube, eax

    imul    ecx, ebx, 25      ; ecx = ebx*25
    mov     eax, ecx
    mov     cube25, eax

    mov     eax, ebx
    cdq                       ; initialize edx by sign extension
    mov     ecx, 100          ; can't divide by immediate value
    idiv    ecx               ; edx:eax / ecx
    mov     ecx, eax          ; save quotient into ecx
    mov     eax, ecx
    mov     quot, eax

    mov     eax, edx
    mov     rem_, eax

    neg     edx               ; negate the remainder
    mov     eax, edx
    mov     neg_, eax

    popad                     ' restore registers

' Output
    string s = square_msg + square + cr +
               cube_msg + cube + cr +
               cube25_msg + cube25 + cr +
               quot_msg + quot + cr +
               rem_msg + rem_ + cr +
               neg_msg + neg_ + cr
    return s
end function

print do_math(entry)

printl "Enter ..." : waitkey


For using the code in a sub I had to replace "ebx" with "esi". I assume the reason is because I used variables which are created outside the sub? I thought the use of pushad / popad would be sufficient but it seems I missed something else.

I wonder if there is a way to use "ebx" in the example which uses sub?

Roland

Code: [Select]
;
; file: math2.o2bas
; This program demonstrates how the integer multiplication and division
; instructions work.
;

#include "$/inc/console.inc"

;segment .data
;
; Output strings
;
zstring
prompt      = "Enter a number: ",
square_msg  = "Square of input is ",
cube_msg    = "Cube of input is ",
cube25_msg  = "Cube of input times 25 is ",
quot_msg    = "Quotient of cube/100 is ",
rem_msg     = "Remainder of cube/100 is ",
neg_msg     = "The negation of the remainder is "


;segment .bss
int entry
int square, int cube, cube25, quot, rem_, neg_

print prompt
entry = val (rtrim ltrim input())


sub do_math(int num)               

    pushad                    ' save registers

    mov     eax, num
       
    imul    eax               ; edx:eax = eax * eax           
    mov     square, eax

    mov     esi, eax          ; save answer in ebx
    imul    esi, [num]        ; ebx *= [num]
    mov     eax, esi
    mov     cube, eax

    imul    ecx, esi, 25      ; ecx = ebx*25
    mov     eax, ecx
    mov     cube25, eax

    mov     eax, esi
    cdq                       ; initialize edx by sign extension
    mov     ecx, 100          ; can't divide by immediate value
    idiv    ecx               ; edx:eax / ecx
    mov     ecx, eax          ; save quotient into ecx
    mov     eax, ecx
    mov     quot, eax

    mov     eax, edx
    mov     rem_, eax

    neg     edx               ; negate the remainder
    mov     eax, edx
    mov     neg_, eax

    popad                     ' restore registers

end sub

do_math(entry)

' Output
string s = square_msg & square & cr &
           cube_msg & cube & cr &
           cube25_msg & cube25 & cr &
           quot_msg & quot & cr &
           rem_msg & rem_ & cr &
           neg_msg & neg_ & cr
print s

printl "Enter ..." : waitkey



.

Peter

  • Guest
Re: Experimenting with O2 assembler
« Reply #12 on: March 02, 2016, 11:33:45 AM »
Hi Arnold,

same here!

Here is a shorter version of your source code.
Code: [Select]
include "asm.inc"
window 320,240,1

int data[6]

sub do_math(int num)
    pushad                    ' save registers
    mov     eax, num
    xor     edx, edx
       
    imul    eax               ; edx:eax = eax * eax       
    mov     data[0], eax
    mov     edi, eax          ; save answer inedi
    imul    edi, num          ; edi *= [num]
    mov     eax,edi
    mov     data[1], eax

    imul    ecx,edi, 25      ; ecx =edi*25
    mov     data[2], ecx

    mov     eax,edi
    mov     ecx, 100          ; can't divide by immediate value
    div     ecx               ; edx:eax / ecx
    mov     ecx, eax          ; save quotient into ecx
    mov     data[3], ecx

    mov     eax, edx
    mov     data[4], eax

    neg     edx               ; negate the remainder
    mov     data[5], edx
    popad
end sub


do_math(15)

text 10, 20, 20, data[0]
text 10, 40, 20, data[1]
text 10, 60, 20, data[2]
text 10, 80, 20, data[3]
text 10,100, 20, data[4]
text 10,120, 20, data[5]

backcolor 0,0,255
text 10,160, 20, "OKAY!"

waitkey
winEnd

.
« Last Edit: March 02, 2016, 12:39:04 PM by Peter »

Arnold

  • Guest
Re: Experimenting with O2 assembler
« Reply #13 on: March 03, 2016, 02:05:16 AM »
Hi Peter,

thank you for the alternative code. It will work in a console window too.
I am not quite sure why using ebx does work in the function but fails with the sub. I assume the reason is because global variables are declared and used in the sub. In examples\Asm32\Opengl2.o2bas and WinApi1.o2bas Charles used a way for saving and restoring procs and globals table ptr. But at the moment I do not understand this approach and am not able to apply it. I understand that EBX is used by Oxygen itself internally for several tasks.

I found this in a previous message:
Quote
You have defined variables in global/static memory space, which are always referenced by the ebx register

The cure is to put this into a procedure and use local variables, which are referenced by ebp.

How could this approach be applied with the example above?

Roland

Peter

  • Guest
Re: Experimenting with O2 assembler
« Reply #14 on: March 03, 2016, 05:44:50 AM »
Hi Roland,

This may be interesting: 
Without STR() I got a nervous crash.
Code: [Select]
include "asm.inc"
window 640,480,1

sub test1
    push ebx
    mov  ebx,200
    mov  eax,ebx
    pop  ebx
    return eax
end sub

sub test2(sys a, b)
    push ebx
    mov  ebx,a
    add  ebx,b
    mov  eax,ebx
    pop  ebx
    return eax
end sub

text 20,10,12,str(test1) + " bananas"
waitkey

text 20,26,12, str(test2(50,50)) + " apples"
waitkey
winEnd
« Last Edit: March 03, 2016, 03:09:48 PM by Peter »