如何将内存数据从指针复制到数组 ASSEMBLY 8086
How can I copy memory data from pointer to array ASSEMBLY 8086
我正在开发一个 C 程序,该程序调用一个将数组作为参数传递的汇编函数。
在汇编代码中(对于 8086),我能够获取内存中数组的地址并将地址保存在 ES:BX
中,但之后我需要将值复制到数组 BARCODE
但我找不到任何方法来实现它。
我的代码看起来像这样:
代码:
unsigned char computeControlDigit(char* barCodeASCII);
int main( void ){
char barCodeStr[14]
unsigned char controlDigitCheck;
controlDigitCheck = computeControlDigit(barCodeStr);
}
汇编代码:
_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
我们欢迎任何帮助。
您可以使用
mov al,es:[bx]
从字符串中读取一个字符,但由于这是一个大型模型,您需要创建一个指向 BARCODE 的远指针。您可能需要考虑对输入使用 ds:si,对输出使用 es:di,因为这将允许代码到 lodsb 和 stosb。
在大内存模型中,所有数据和代码都是 FAR,必须通过适当的段引用。在下面的代码中,我将指向源字符串 barcodestr
的指针加载到 DS:SI 并将 BARCODE
加载到 ES:DI.然后我用 LODSB and save it to BARCODE
with STOSB
从 barcodestr
数组中读取字符。当到达 NUL 终止符时,复制完成。
假设方向标志 (DF) 设置为 0(向前运动):
STOSB
与1 类似:
mov [ES:DI], al
lea di, [DI + 1] ; Increment DI by 1 without altering flags
LODSB
与1 类似:
mov al, [DS:SI]
lea si, [SI + 1] ; Increment SI by 1 without altering flags
我不知道您使用的是 MASM 还是 TASM 作为汇编程序,所以我提供了两者的版本。简单复制 NUL 终止字符串的示例 TASM 代码如下:
.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
分别作为一条指令完整执行。
我正在开发一个 C 程序,该程序调用一个将数组作为参数传递的汇编函数。
在汇编代码中(对于 8086),我能够获取内存中数组的地址并将地址保存在 ES:BX
中,但之后我需要将值复制到数组 BARCODE
但我找不到任何方法来实现它。
我的代码看起来像这样:
代码:
unsigned char computeControlDigit(char* barCodeASCII);
int main( void ){
char barCodeStr[14]
unsigned char controlDigitCheck;
controlDigitCheck = computeControlDigit(barCodeStr);
}
汇编代码:
_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
我们欢迎任何帮助。
您可以使用
mov al,es:[bx]
从字符串中读取一个字符,但由于这是一个大型模型,您需要创建一个指向 BARCODE 的远指针。您可能需要考虑对输入使用 ds:si,对输出使用 es:di,因为这将允许代码到 lodsb 和 stosb。
在大内存模型中,所有数据和代码都是 FAR,必须通过适当的段引用。在下面的代码中,我将指向源字符串 barcodestr
的指针加载到 DS:SI 并将 BARCODE
加载到 ES:DI.然后我用 LODSB and save it to BARCODE
with STOSB
从 barcodestr
数组中读取字符。当到达 NUL 终止符时,复制完成。
假设方向标志 (DF) 设置为 0(向前运动):
STOSB
与1 类似:mov [ES:DI], al lea di, [DI + 1] ; Increment DI by 1 without altering flags
LODSB
与1 类似:mov al, [DS:SI] lea si, [SI + 1] ; Increment SI by 1 without altering flags
我不知道您使用的是 MASM 还是 TASM 作为汇编程序,所以我提供了两者的版本。简单复制 NUL 终止字符串的示例 TASM 代码如下:
.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
分别作为一条指令完整执行。