Reputation: 635
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
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
LODSB
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
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