В модели большой памяти все данные и код имеют значение FAR и должны указываться через соответствующий сегмент.В приведенном ниже коде я загружаю указатель на исходную строку barcodestr
в DS: SI и BARCODE
в ES: DI .Затем я читаю символ из массива barcodestr
с помощью LODSB и сохраняю его в BARCODE
с помощью STOSB
.Копирование заканчивается, когда достигнут терминатор NUL.
STOSB
похоже 1 на выполнение:
mov [ES:DI], al
inc di
LODSB
аналогично 1 на выполнение:
mov al, [DS:SI]
inc si
Я не знаю, используете ли вы MASM или TASM в качестве ассемблера, поэтому я предоставляю версию для обоих.Пример кода TASM, который просто копирует завершенную NUL-строку, выглядит следующим образом:
.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
Конечно, вы выполняете любую обработку по вашему выбору.Я просто сделал прямую копию данных в качестве примера.
При использовании MASM вам, возможно, придется использовать немного другой синтаксис:
.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
Необработанная версия без использования специальных директив ассемблера, которыеможет показаться более естественным для вас:
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
Сноска
- 1
LODSB
и STOSB
похожи к эквивалентному коду, показанному за исключением того, что LODSB
и STOSB
не изменяют флаги.