ssoBAekiL
ssoBAekiL

Reputation: 635

How can I copy memory data from pointer to array ASSEMBLY 8086

I'm working on a C program that calls an assembly function passing an array as argument. In the assembly code (for 8086), I'm able to get the address of the array in memory and to save the address in ES:BX but after that I need to copy the values to the array BARCODE but I can't find any way of achieving that.

My code looks something like this:

Code:

unsigned char computeControlDigit(char* barCodeASCII);

int main( void ){
char barCodeStr[14]
unsigned char controlDigitCheck;

controlDigitCheck = computeControlDigit(barCodeStr);
}

Assemby code:

_DATA SEGMENT WORD PUBLIC 'DATA'
    BARCODE DB 13 DUP(?)
_DATA ENDS

PUBLIC _computeControlDigit                     
_computeControlDigit PROC FAR
    PUSH BP 
    MOV BP, SP
    PUSH ES
    LES BX, [BP+6]

    ; code to copy from memory to
    ; array and code of operations on the array

    POP ES
    POP BP
    RET
_computeControlDigit ENDP                           
_TEXT ENDS
END

Any help would be wery welcome.

Upvotes: 2

Views: 1146

Answers (2)

Michael Petch
Michael Petch

Reputation: 47563

In the large memory model all data and code is FAR and must be referenced through the proper segment. In the code below I load the pointer to the source string barcodestr into DS:SI and BARCODE into ES:DI. I then read the character from the barcodestr array with LODSB and save it to BARCODE with STOSB. The copy is finished when the NUL terminator has been reached.

Assuming the Direction Flag (DF) is set to 0 (forward movement):

  • STOSB is similar1 to doing:

    mov [ES:DI], al
    lea di, [DI + 1]              ; Increment DI by 1 without altering flags
    
  • LODSB is similar1 to doing:

    mov al, [DS:SI]
    lea si, [SI + 1]              ; Increment SI by 1 without altering flags
    

I don't know if you are using MASM or TASM as an assembler so I provide a version for both. Example TASM code that simply copies a NUL terminated string is as follows:

.MODEL LARGE, C

PUBLIC computeControlDigit

_DATA SEGMENT WORD PUBLIC 'DATA'
    BARCODE DB 13 DUP(?)
_DATA ENDS

_TEXT SEGMENT WORD PUBLIC 'TEXT'
ASSUME DS:_DATA, CS:_TEXT

computeControlDigit PROC C FAR
    ARG %%barcodestr:DWORD      ; barcodestr is a FAR pointer (DWORD)
    USES DS, SI, DI             ; Save non-volatile registers

    MOV AX, SEG BARCODE         ; Get segment and offset (FAR PTR) of BARCODE
    MOV ES, AX                  ; into ES:DI
    MOV DI, OFFSET BARCODE

    LDS SI, %%barcodestr        ; Load barcodestr FAR pointer into DS:SI
    JMP %%GETCHAR               ; Get next character

%%NEXTCHAR:
    STOSB                       ; Store character to ES:DI (BARCODE), DI++
%%GETCHAR:
    LODSB                       ; Read character from DS:SI (barcodestr), SI++
    TEST AL, AL                 ; Is it a NUL terminator?
    JNZ %%NEXTCHAR              ;     If not go back and get next character

%%ENDLOOP:
    STOSB                       ; Store NUL terminator at end of BARCODE

    RET

computeControlDigit ENDP
_TEXT ENDS
END

Of course you do whatever processing you choose. I just did a straight copy of the data as an example.

If using MASM you may have to use a slightly different syntax:

.MODEL LARGE, C

PUBLIC computeControlDigit

_DATA SEGMENT WORD PUBLIC 'DATA'
    BARCODE DB 13 DUP(?)
_DATA ENDS

_TEXT SEGMENT WORD PUBLIC 'TEXT'
ASSUME DS:_DATA, CS:_TEXT

computeControlDigit PROC FAR C USES DS SI DI barcodestr:DWORD    
; DS, SI, DI are saved as they are non-volatile registers
; barcodestr is a FAR pointer (DWORD)

    MOV AX, SEG BARCODE         ; Get segment and offset (FAR PTR) of BARCODE
    MOV ES, AX                  ; into ES:DI
    MOV DI, OFFSET BARCODE

    LDS SI, barcodestr          ; Load barcodestr FAR pointer into DS:SI
    JMP GETCHAR                 ; Get next character

NEXTCHAR:
    STOSB                       ; Store character to ES:DI (BARCODE), DI++
GETCHAR:
    LODSB                       ; Read character from DS:SI (barcodestr), SI++
    TEST AL, AL                 ; Is it a NUL terminator?
    JNZ NEXTCHAR                ;     If not go back and get next character

    STOSB                       ; Store NUL terminator at end of BARCODE

    RET

computeControlDigit ENDP
_TEXT ENDS
END

A raw version without using special assembler directives that may look more natural to you would be:

                PUBLIC  _computeControlDigit

_DATA           SEGMENT WORD PUBLIC USE16 'DATA'
BARCODE:
    DB  13 DUP(?)    
_DATA           ENDS

_TEXT           SEGMENT WORD PUBLIC USE16 'TEXT'
                ASSUME CS:_TEXT, DS:_DATA

_computeControlDigit:
        push            bp
        mov             bp,sp
        push            ds
        push            si
        push            di
        mov             ax,seg BARCODE
        mov             es,ax
        mov             di,offset BARCODE
        lds             si,dword ptr 6[bp]
        jmp             GETCHAR
NEXTCHAR:
        stosb
GETCHAR:
        lodsb
        test            al,al
        jne             NEXTCHAR
        stosb
        pop             di
        pop             si
        pop             ds
        pop             bp
        retf
_TEXT           ENDS
                END

Footnote

  • 1LODSB and STOSB are similar to the equivalent code shown with the exception that LODSB and STOSB are executed in their entirety as one instruction each.

Upvotes: 2

rcgldr
rcgldr

Reputation: 28818

You can use

        mov     al,es:[bx]

to read a character from the string, but since this is large model, you'll need to create a far pointer to BARCODE. You might want to consider using ds:si for the input, and es:di for the output, since that would allow the code to lodsb and stosb.

Upvotes: 1

Related Questions