【问题标题】:How can I copy memory data from pointer to array ASSEMBLY 8086如何将内存数据从指针复制到数组 ASSEMBLY 8086
【发布时间】:2019-03-27 21:19:46
【问题描述】:

我正在编写一个 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

欢迎任何帮助。

【问题讨论】:

  • 到目前为止你尝试了什么?例如,您可以复制 1 个字符吗?
  • 您是否将此代码编译为large 模型?如果不是,那么它应该是...PROC NEAR,而不是LES...,而是使用MOV BX,[BP+4],(DS 将是数据段寄存器)。
  • Yes 编译为 large 并且工作正常,问题在于我的汇编知识......到目前为止,我已经尝试了许多 MOV 组合,如 MOV BARCODE[0], ES:AX 但这只是复制指向数组的指针的值
  • 是的,我只需要将收到的值复制到数组中

标签: c assembly masm x86-16 real-mode


【解决方案1】:

在大内存模型中,所有数据和代码都是 FAR,必须通过适当的段引用。在下面的代码中,我将指向源字符串barcodestr 的指针加载到DS:SI 中,并将BARCODE 加载到ES:DI 中。然后,我使用LODSBbarcodestr 数组中读取字符,并使用STOSB 将其保存到BARCODE。当到达 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

脚注

  • 1LODSBSTOSB 与所示的等效代码相似,但LODSBSTOSB 分别作为一条指令整体执行。

【讨论】:

  • 作为一个选项,可以在本地代码段中定义一个指向 BARCODE 的远指针,然后可以使用 LES DI,... 来加载该指针。
  • @rcgldr :这是非常正确的,也是许多高级语言为默认使用远数据的内存模型发出的。我不会让它变得比现在更混乱,哈哈。但你是对的。
  • 在 MASM 中,指针参数有一个可选语法:barcodestr:PTR。这将默认为大型模型的远指针。也可以使用barcodestr:FAR PTR。对于codeview,如果使用codeview查看数据,声明限定符类型(BYTE、WORD、DWORD),例如barcodestr:FAR PTR BYTE会有所帮助。
【解决方案2】:

你可以使用

        mov     al,es:[bx]

从字符串中读取一个字符,但由于这是一个大模型,您需要创建一个指向 BARCODE 的远指针。您可能需要考虑使用 ds:si 作为输入,使用 es:di 作为输出,因为这将允许代码 lodsb 和 stosb。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2020-02-26
    • 2015-03-11
    • 1970-01-01
    • 2015-03-24
    • 2021-11-17
    • 2018-04-26
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多