使用 Turbo C++ 内联 asm 索引包含常量的数组

Index an array with constants with Turbo C++ inline asm

我正在尝试在 Turbo C++ 3.0 IDE 中编写 16 位内联汇编代码。我需要使用内联汇编访问以高级语言(如 C++ 定义的数组,但我的尝试失败了。编译失败的代码:

#include<stdio.h>

int main()
{
       int array[10] = {1,2,3,4,5,6,7,8,9,0};
       asm{
           mov ax,array[0]
       }
       // fall off the end of the function with return value in AX
       // Or else C++ implicit return 0 still happens.
}

上面的代码在指令 mov ax,array[0]:

上给我一个错误

Invalid combination of opcode and operands

我试图通过 Turbo C++ 3.0 的手册来学习如何复制内容,但是没有关于如何使用内联汇编来完成的信息。

我什至浏览了 8086 到 Pentium 汇编语言这本书,但我找不到问题的答案。

当我尝试其他方法时,我似乎得到了不正确的答案,例如 -22,而不是 1。

(编者注:不清楚 OP 是用调试器查看 AX 还是只查看 main 的 return 值。)

访问在堆栈上生成的数组元素可能有点棘手。当访问基于堆栈的变量(即:在堆栈上定义的非静态变量,如 array)时,编译器会生成相对于寄存器 BP 的内存引用。您的指示:

mov ax,array[0]

会报错:

Invalid combinations of opcodes and operands

该语法不适用于包括数组在内的堆栈变量。将起作用的是:

mov ax,[array]     ; Get first int in array
mov ax,[array+2]   ; Get second int in array
mov ax,[array+4]   ; Get third int in array

[0] 在内联汇编中的使用不像在 C 代码中那样有效。您必须计算数组中每个元素的字节地址,因此 [array+2] 指向第二个元素,而 [array+4] 指向数组中的第三个元素。开发人员必须根据元素的大小缩放添加的偏移量。如果 arraychar 的数组,那么 [array+1] 指向第二个元素,而 [array+2] 指向数组中的第三个元素。对于 long(32 位值)数组,[array+4] 指向第二个元素,[array+8] 指向数组中的第三个元素。

您的内联程序集可能看起来像这样访问 int 数组的第三个元素:

asm{
    mov ax, [array+4]
};

通常,在处理数组时,您可能希望访问多个元素,或者创建一个循环来对多个元素执行一些操作。在那种情况下,您需要考虑将数组的地址加载到寄存器中,例如 SI1。一旦你有了数组的地址,你就可以访问单个元素。获得数组地址后,您可以将字节偏移量添加到元素(在本例中为 int)并检索值。如果数组的地址放在SI中,那么[si+0](或[si])就是数组中第一个整数的地址。

要检索堆栈变量或全局变量的地址,您可以使用 LEA 指令(加载有效地址)。下面的代码使用LEAarray的基地址(元素0)取到SI中。该代码检索第 3 个整数元素 (array+4) 的值并将其放入 AX。然后代码将另一个变量 myint 设置为 AX 中的值。 C 代码然后打印该值。示例代码:

#include<stdio.h>
int main()
{
    int array[10] = {1,2,3,4,5,6,7,8,9,0};
    int myint;

    asm{
        lea si, [array]
        mov ax, [si+4]             ; Get third int element from the array
        mov [myint], ax
    };

    printf("Third element: %d\n", myint);
    return 0;
}

应该将其作为输出:

Third element: 3


如果您想对数组中的所有整数求和,则内联汇编可能如下所示:

#include<stdio.h>
int main()
{
    int array[10] = {1,2,3,4,5,6,7,8,9,0};
    /* arrsize = number of ints in array */
    const unsigned int arrsize = sizeof(array)/sizeof(int);
    int total;

    asm{
        /* Sum a non-zero length array from the last element down to first element */
        lea si, [array]        /* SI = base address of array */
        mov bx, [arrsize]      /* BX = Number of 16-bit ints in array */
        shl bx, 1              /* BX = BX * 2 = length of array in bytes
                                  BX points at element just beyond the end of the array */
        xor ax, ax             /* AX = current sum = 0 */
    }
    numloop:
    asm{
        add ax, [si+bx-2]      /* Add current element */
        sub bx, 2              /* BX =  position of previous element in array */
        jnz numloop            /* If the index = 0 then we aren't finished */

        mov [total], ax        /* Move the sum into variable total */
    };

    printf("Sum of all ints: %d\n", total);
    return 0;
}

某些版本的 Turbo-C 不能正确支持内联汇编语句中的标签。相反,您可以使用通常用于 C 中的 goto 语句的 C 标签。您只需将内联程序集分解为多个部分,以便在必要时放置标签,就像上面示例中标签 numloop 所做的那样。

输出应该是:

Sum of all ints: 45


脚注:

  • 1BX, DI, SI16-bit addressing modes 中允许的寄存器。 BP 也是允许的,但它隐含地使用 SS 作为段而不是 DS.