Author Topic: mol_bolom's code  (Read 13195 times)

Offline Mol_Bolom

  • Jr. Member
  • *
  • Posts: 4
mol_bolom's code
« on: February 22, 2017, 07:13:14 PM »
Note: This is more of a place holder for things I'm writing as I'm often on the road and without an internet connection, and my addled brain will be more than likely to remember this here than on my computer.

So it's been a long long time since I've done any assembly, but I've been attacking it with renewed vigor, and have even found some useful tidbits of information through the AMD documentation (Desktop: Fam: 15, Model: 75, Processor 3800+) and the intel documentation (Laptop: I5 forgot which particular processor it is).

Also, I used yasm instead of nasm, but I don't think there's that much difference.

The main functions I wanted to create were hexadecimal and binary string generation functions, so I could examine the registers easily.  Which is the first code. (The latest incarnate). (Also, I know there's millions of these kinds of examples on the internet, again, this is primarily to help my addled brain to remember this).

Note: I'll update this and add more as I move along.  So take all this with a grain of salt as I'm still a beginner.

Code: [Select]
;
;   tobdoh functions    tohex, tobin, todec, tooct
;
;
;
;   Assembly,     RDI       string
;                 RAX       number
;                 RCX       length
;
;
;   C             RDI       string
;                 RSI       number
;                 RDX       length
;
;
;       tohex, tobin    restricted to the 64 bits of a register.
;
;       todec           Restricted to the length passed to the funtion.
;
;       tooct           Restricted to 7 octal digits.

section .text
    global tobin, todec, tohex, tooct


tobin:
%ifdef _WITH_C_
    MOV     RAX ,         RSI
    MOV     RCX ,         RDX
%endif

    AND     RCX ,             63             ; Make sure we use no more than up to 64 bits.             0-63
    ROR     RAX ,          CL
   TEST      CL ,             63
    JNZ                             tobin_loop
    MOV      CL ,             64

tobin_loop:
    XOR      BL ,          BL
    SHL     RAX ,              1
    ADC      BL , BYTE      0x30
    MOV    [RDI],          BL
    INC     RDI
   LOOP                             tobin_loop

    MOV    [RDI], BYTE         0
    RET

tohex:
%ifdef _WITH_C_
    MOV     RAX ,         RSI
    MOV     RCX ,         RDX
%endif

    AND     RCX ,             15             ; Make sure we use no more than up to 16 hexadecimal digits.             0-15
    SHL      CL ,              2
    ROR     RAX ,          CL
    SHR      CL ,              2
   TEST      CL ,             15
    JNZ                             tohex_loop
    MOV      CL ,             16

tohex_loop:
    ROL     RAX ,              4
    MOV      BL ,          AL
    AND      BL ,            0xF
    CMP      BL ,             10
     JL                             tohex_continue
    ADD      BL ,              7
tohex_continue:
    ADD      BL ,           0x30
    MOV    [RDI],          BL
    INC     RDI
   LOOP                             tohex_loop

    MOV    [RDI], BYTE         0
    RET

tooct:
%ifdef _WITH_C_
    MOV     RAX ,        RSI
    MOV     RCX ,        RDX
%endif

    AND     RCX ,              7
    MOV      CH ,         CL
    SHL      CL ,              1
    ADD      CL ,         CH
    ROR     RAX ,         CL
    MOV      CL ,         CH
    XOR      CH ,         CH
   TEST      CL ,              7
    JNZ                             tooct_loop
    MOV      CL ,              8
tooct_loop:
    ROL     RAX ,              3
    MOV      BL ,         AL
    AND      BL ,              7
    ADD      BL ,           0x30
    MOV    [RDI],         BL
    INC     RDI
   LOOP                             tooct_loop

    MOV    [RDI], BYTE         0
    RET

todec:
%ifdef _WITH_C_
    MOV     RAX ,        RSI
    MOV     RCX ,        RDX
%endif
    ADD     RDI ,        RCX                        ; Move to end of string.
    MOV    [RDI], BYTE         0
    DEC     RDI
    MOV     RBX ,             10
todec_loop:
    XOR     RDX ,        RDX            ; Clear RDX
    DIV     RBX
    ADD      DL ,           0x30
    MOV    [RDI],         DL
    DEC     RDI
   LOOP                         todec_loop
    MOV    [RDI], BYTE         0
    RET

The second code is my very first attempt at writing a big number library.  For my current purposes I only need addition, multiplication, and modulo routines, so that is my primary goal.




Update big 2/22/17 5:10pm
  • Cleaned up the code for bigadd.

Update big 2/23/17 3:10pm
  • Added multiplication function

Update big 2/24/17 1:00am
  • Added subtraction function that returns a copy of A if A is smaller than B, else A-B
  • Rewrote bignum_write_stack into a local CALL.
  • Added macros for saving RBX, R10, and R11 as I've read those should be restored.
  • Added array2big for converting an array of ints/unsigned longs to a malloced space so free can be called...well...freely.

Function list
  • genbig (int / unsigned long ) Creates a big number from a 64bit or 32bit number.
  • bigi ( big , i ) returns the i'th element in a big number. bigi(array, 0) returns the length of the array.
  • bignum_write_stack Useless outside of the assembly file. Just writes a newly generated big number that was written to the stack.
  • array2big( array of ints/unsigned longs ) Allocates space and copies the array to the allocated space.
  • C = bigadd( A, B ), adds a big number A with a big number B and returns a newly created big number C.
  • C = bigmul( A, B ), multiplies a big number A with a big number B and returns a newly created big number C.
  • C = bigsub( A, B ), If A is larger than B then returns a new big number C = A-B, else returns A.

Currently on the todo list, studying the XMM# registers and instructions to see if I can simplify some of this, as well as cutting out some of the useless code I think I've found.

Update big 3/4/17 10:40am
  • Total rewrite and redesign.
  • Added str2big for converting a string to a big number. So other functions not necessary, at the moment.
  • Functions:
  • big * str2big( char *)
  • big * bigadd( big A, big B)
  • big * bigmul( big A, big B)
  • big * bigsub( big A, big B)
  • unsigned short bigtest( big A, big B )

Update big 3/5/17 1:00am
  • Cleaned up the code a bit
  • Now bignum_write_stack takes care of the unnecessary 0's.

Code: [Select]
%ifdef _WITH_C_

%macro Save_C 0
    PUSH RBX
    PUSH R10
    PUSH R11
%endmacro

%macro Restore_C 0
    POP RBX
    POP R10
    POP R11
%endmacro

%endif

section .text
    extern malloc

    global  bigadd, bigmul, bigsub, str2big


;
;   bignum_write_stack    Only used in this file.
;
;   Registers modified:
;           RAX, RBX, RCX, RDI, RSP


bignum_write_stack:
    POP     RBX                 ; Get call

    MOV     RCX ,       [RSP]   ; Get counter

    XOR     RAX ,        RAX    ; Empty RAX for testing all 64bits
                                ; as I'm unsure if XOR r64/m64, imm32 does so.

bignum_write_stack_remove_zeroes:
    ADD     RSP ,          8
    CMP    [RSP],        RAX
    JNZ                  bignum_write_stack_remove_zeroes_finished
   LOOP                  bignum_write_stack_remove_zeroes

    INC     RCX                 ; If end of elements, inc RCX to 1
bignum_write_stack_remove_zeroes_finished:
   PUSH     RCX                 ; Reset stack
   PUSH     RBX

    MOV     RDI ,        RCX
    INC     RDI
    SHL     RDI ,          3
   CALL                  malloc

    POP     RBX                 ; Save the CALL for RET

    POP     RCX                 ; Get the counter

    MOV    [RAX],        RCX    ; Write the counter

    SHL     RCX ,          3
    ADD     RAX ,        RCX    ; Move to end of RAX
    SHR     RCX ,          3

bignum_write_stack_loop:
    POP     RDX                 ; Get element.
    MOV    [RAX],        RDX    ; Write it to new bignum
    SUB     RAX ,          8    ; Move to next element.
   LOOP                  bignum_write_stack_loop
 
   PUSH     RBX                 ; Reset CALL
    RET

;
;   short bigtest( big A, big B )
;
;   Returns:    00 => A=B
;               10    A>B
;               01    A<B
;
;   Registers modified:   AX, RCX, RSI, RDI,

bigtest:
    MOV    RCX ,        [RDI]       ; Set up counters.
    MOV     R9 ,        [RSI]

    MOV     AX ,         0x0100     ; Init for A > B

    CMP    RCX ,          R9
     JG                   bigtest_ret
     JL                   bigtest_lessthan

    SHL    RCX ,           3        ; Move to the high order of both big numbers.
    ADD    RDI ,         RCX
    ADD    RSI ,         RCX
    SHR    RCX ,           3
bigtest_loop:
    MOV    RDX ,        [RDI]       ; Test first elements.
    CMP    RDX ,        [RSI]
     JG                  bigtest_ret
     JL                  bigtest_lessthan
    SUB    RDI ,           8
    SUB    RSI ,           8
   LOOP                  bigtest_loop
    MOV     AX ,         0x0000
    JMP                  bigtest_ret
bigtest_lessthan:
    MOV     AX ,         0x0001
bigtest_ret:
    RET


;
;   big * str2big( char * )
;   RAX = str2big( RDI )
;
;   Registers modified:  RAX, RBX, RCX, RDX, R8, R9

str2big:
   Save_C
   PUSH     RBP                     ; Save RBP
    MOV     RBP ,       RSP         ; Save RSP

    XOR     RAX ,       RAX         ; Empty RAX
    MOV     RCX ,        10         ; Multiplier
    XOR     RBX ,       RBX         ; Empty char.

   PUSH     RAX                     ; Write 0 to the stack.

str2big_loop:

    MOV      BL ,      [RDI]        ; Char to BL
   TEST      BL ,       0xFF        ; EOS?
     JZ                 str2big_ret

    SUB      BL ,       0x30        ; Set digit to decimal value.
    INC     RDI                     ; Next byte

    MOV      R8 ,       RBP         ; Init low order
    SUB      R8 ,         8

str2big_mul:
    MOV     RAX ,      [ R8]
    MUL     RCX

    ADD     RAX ,       RBX         ; Add low decimal digit to RAX
    ADC     RDX ,         0         ; Carry to RDX
    MOV     RBX ,       RDX         ; RBX = low decimal digits.
   
    MOV    [ R8],       RAX         ; Write RAX back to stack.
    SUB      R8 ,         8       
    CMP      R8 ,       RSP         ; Is this the end of the stack?
    JGE                 str2big_mul
    CMP     RDX ,         0         ; Is there a high order element?
    JNZ                 str2big_push_high

    ADD      R8 ,         8         ; Reset R8 if no carry.
    JMP                 str2big_loop

str2big_push_high:
   PUSH     RDX
    JMP                 str2big_loop

str2big_ret:
    MOV     RCX ,       RBP         ; Get length.
    SUB     RCX ,       RSP
    SHR     RCX ,         3
   PUSH     RCX
   CALL                 bignum_write_stack
    MOV     RSP ,       RBP
    POP     RBP
   Restore_C
    RET


;
;   big * bigadd( big A, big B )
;   RAX = bigadd( RDI  , RSI   )
;
;   Registers modified: RAX, RCX, RDX, R9, RDI, RSI

bigadd:
   Save_C
   PUSH     RBP
    MOV     RBP ,       RSP         ; Save the stack

    MOV     RCX ,      [RDI]        ; Set up counters.
    MOV      R9 ,      [RSI]

    CMP     RCX ,        R9         ; Insure RDI > RSI in length.
    JGE                 bigadd_continue

   XCHG     RDI ,       RSI

bigadd_continue:
    MOV     RCX ,      [RDI]
    MOV      R9 ,      [RSI]

    ADD     RDI ,         8
    ADD     RSI ,         8


    XOR     RAX ,       RAX

bigadd_loop:
    XOR     RDX ,       RDX

    ADD     RAX ,      [RDI]        ; Add A
    ADC     RDX ,         0
 
    ADD     RDI ,         8         ; Move to next element.

   TEST      R9 ,       0xFFFFFFFF
     JZ                 bigadd_no_B
    ADD     RAX ,      [RSI]        ; Add B
    ADC     RDX ,         0
    ADD     RSI ,         8
    DEC      R9

bigadd_no_B:
   PUSH     RAX
    MOV     RAX ,       RDX         ; Move high order to RAX.
   LOOP                 bigadd_loop

   PUSH     RDX                     ; Since bignum_write_stack takes care of 0,
                                    ; fahget abaht it.
   MOV      RCX ,       RBP
   SUB      RCX ,       RSP
   SHR      RCX ,         3

  PUSH      RCX
  CALL                  bignum_write_stack
   POP      RBP
  Restore_C
   RET


;
;   big * bigmul( big *A, big *B )
;   RAX = bigmul( RDI ,   RSI    )
;
;   Registers modified: RAX, RBX, RCX, RDX, R8, R9, R10, R11
;

bigmul:
   Save_C
   PUSH     RBP
    MOV     RBP ,       RSP         ; Backup RSP

    MOV      R8 ,      [RDI]        ; Setup counters.
    MOV      R9 ,      [RSI]

    MOV     R10 ,       RDI         ; Backup A and B
    MOV     R11 ,       RSI

    XOR     RAX ,       RAX         ; Empty RAX

    MOV     RCX ,        R8         ; Setup length of stack.
    ADD     RCX ,        R9
    INC     RCX

bigmul_init_stack:                  ; Initialize the stack space.
   PUSH     RAX
   LOOP                 bigmul_init_stack

    MOV     RBX ,       RSP          ; Backup RSP
                     
    ADD     RSI ,         8          ; First elements of A and B
    ADD     RDI ,         8
                     
bigmul_loop:         
                     
    MOV     RAX ,      [RDI]         ; Move RDI's element
    MUL QWORD [RSI]                 

    ADD      R8 ,        R9          ; Move to current element in C.
    SHL      R8 ,         3
    ADD     RSP ,        R8
    SHR      R8 ,         3
    SUB      R8 ,        R9
                       
    ADD    [RSP],       RAX          ; Write low order
    ADC QWORD RDX ,       0          ; Add any carry
                       
;    MOV     RAX ,        1         ; Setup 1 for adc
    SUB     RSP ,        8          ; Next element
    ADD    [RSP],       RDX          ; Add high order
    JNC                 bigmul_no_adc
                       
bigmul_adc:                          ; Span the list and add all carry.
    SUB     RSP ,         8
    ADD QWORD   [RSP],    1
     JC                 bigmul_adc
                       
bigmul_no_adc:         
    MOV     RSP ,       RBX          ; Reset RSP
                       
    DEC      R8                      ; Move to next element.
    ADD     RDI ,         8
   TEST      R8 ,       0xFFFFFFFF   ; Test for end of A
    JNZ                 bigmul_loop
                       
    DEC      R9         
    ADD     RSI ,         8
   TEST      R9 ,       0xFFFFFFFF   ; Test for end of B
     JZ                 bigmul_exit
                       
    MOV     RDI ,       R10          ; Restore RDI
    MOV      R8 ,      [RDI]
    ADD     RDI ,         8
    JMP                 bigmul_loop
                       
bigmul_exit:           
    MOV     RCX ,       RBP          ; Setup counter
    SUB     RCX ,       RSP
    SHR     RCX ,         3

   PUSH     RCX
   CALL                 bignum_write_stack
    MOV     RSP ,       RBP
    POP     RBP
   Restore_C
    RET

;
;   big * bigsub( big * A, big * B )
;   RAX = bigsub( RDI    , RSI      )
;
;   Registers modified:  RAX, RCX, R8, R9, R10, R11, R12

bigsub:
   Save_C
    MOV     R10 ,       RDI             ; Test A and B
    MOV     R11 ,       RSI
   CALL                 bigtest

    XOR     RDX ,       RDX             ; Empty high order
    XOR     RCX ,       RCX             ; Empty counter

  TEST       AH ,         1             ; If A <= B return 0.
    JZ                  bigsub_ret_empty

    MOV     RDI ,       R10             ; Restore A B
    MOV     RSI ,       R11
    MOV      R8 ,      [RDI]
    MOV      R9 ,      [RSI]

    ADD     RDI ,         8             ; Begin reading elements.
    ADD     RSI ,         8

bigsub_loop:
    MOV     RAX ,       RDX             ; Move high order to low order
    XOR     RDX ,       RDX

   TEST      R8 ,       0xFFFFFFFF
     JZ                 bigsub_ret
    ADD     RAX ,      [RDI]
    ADD     RDI ,         8

   TEST      R9 ,       0xFFFFFFFF
     JZ                 bigsub_push_rax

    SUB     RAX ,      [RSI]
    JNC                 bigsub_inc_B

    MOV QWORD RAX ,        -1

bigsub_inc_B:
    DEC      R9
    ADD     RSI ,         8
bigsub_push_rax:
   PUSH     RAX
    INC     RCX
    JMP                 bigsub_loop

bigsub_ret_empty:
    MOV     RCX ,         1
   PUSH     RDX
bigsub_ret:
   PUSH     RCX
   CALL                 bignum_write_stack
   Restore_C
    RET
« Last Edit: March 05, 2017, 07:03:05 AM by Mol_Bolom »