【问题标题】:Index an array with constants with Turbo C++ inline asm使用 Turbo C++ 内联 asm 索引具有常量的数组
【发布时间】:2019-07-30 18:20:22
【问题描述】:

我正在尝试在 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]上给了我一个错误:

操作码和操作数的组合无效

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

我什至已经阅读了 8086 到 Pentium 汇编语言书,但我无法找到问题的答案。

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

(编者注:不清楚 OP 是在使用调试器查看 AX 还是仅查看 main 的返回值。)

【问题讨论】:

  • 没人记得。你从这个千年切换到一些东西怎么样? :) 不管怎样,试试mov ax, [array]。验证生成的汇编代码。
  • mov ax, WORD PTR [array]。还要检查int 的大小,16 位还是 32 位
  • @Renat : 在 Turbo-C (Borland) 和其他类似的 16 位编译器(16 位 Microsoft、Watcom、Zortech)中,int 是 16 位,short int 是 16 位, long 是 32 位的。

标签: assembly x86 x86-16 inline-assembly turbo-c++


【解决方案1】:

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

mov ax,array[0]

会报错:

操作码和操作数的无效组合

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

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。代码检索第三个整数元素 (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;
}

应该产生这个作为输出:

第三个元素: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 标签,这些标签通常用于 C 中的 goto 语句。您只需将内联程序集分解为多个部分,以便在必要的地方放置标签,就像上面示例中的标签 numloop 一样。

输出应该是:

所有整数的总和:45


脚注:

  • 1BXDISI16-bit addressing modes 中允许的寄存器。 BP 也是允许的,但它隐式使用 SS 作为片段而不是 DS

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2021-02-21
    • 1970-01-01
    • 2011-05-06
    • 2011-08-02
    • 1970-01-01
    • 2015-02-19
    • 1970-01-01
    • 2012-02-08
    相关资源
    最近更新 更多