2

编辑:这是使用 AT&T 语法

我正在使用 GAS 汇编器学习汇编,并且必须编写一个程序,在其中比较数组中的 int 值并根据比较更改值。我正在使用 C 中的内联汇编编写它。我知道对于一个基本变量,比如 int i,我使用以下行将值存储在寄存器 eax 中:

movl i, %eax

但现在说我有一个变量 a[2][2],我想将 a[1][1] 移动到 %eax。明显的错误答案是:

movl a[1][1], %eax

我在表达式之后得到错误垃圾“[1][1]”。如何将二维数组的值移动到寄存器中?谢谢!

4

2 回答 2

3

将 a[1][1] 转换为线性地址取决于您。换句话说,我们必须a[1][1]弄清楚这距离a. 我们首先计算一行的大小——在本例中为 2 个整数。因此,(目前在整数中工作)第 0 行的开头位于距 a 的偏移 0 处,第 1 行位于偏移 2 处,并且(如果有更多行)以此类推。然后我们添加该行内的偏移量。最后,我们按单个项目的大小对其进行缩放。

从那里开始,我们有几种可能性。a[1][1]一个是我们只需要一个固定的位置——无论如何,我们都会得到。另一个是我们真的在看a[i][j], where iandj恰好是 1 ,但可能是其他大小。

首先,我们可以利用汇编器可以做一些数学运算来为我们计算地址这一事实。

// one row down times 2 ints per row + offset of 1 into last row, all times size of int
movl a + (1 * 2 + 1)*4, eax

在第二种情况下,假设我们有iinesijin ebx。在这种情况下,我们必须自己进行数学运算(抱歉,目前我将使用 Intel 语法——我只是更习惯了):

shl esi, 1    ; i * 2
add esi, ebx  ; i * 2 + j
shl esi, 2    ;(i * 2 + j) * 4

mov eax, a[esi]

x86 实际上可以组合一些常见的寻址操作,因此您不必像我上面那样将它们作为单独的指令执行,因此我们可以很容易地将其简化为:

shl esi, 1
mov eax, a[esi][ebx]

最后一点可能需要一些解释——至少对于 MASM(我猜可能还有 gas),汇编器知道,因为你正在加载一个值eax,所以你正在以 4 字节的数量工作,所以它自动将偏移量缩放 4。

于 2012-04-12T04:48:53.337 回答
2

我不是 100% 确定 AT&T 语法,所以我会发布我的英特尔解决方案以及转换后的 AT&T,以防出现混淆。

基本上,需要先查找数组的值,然后再进行交换。

英特尔语法

mov ecx, a  ;move the pointer to the 2D array into a register first
mov ecx, [ecx + 04h] ;walk to the a[1] dimension (4h happens to be the size of a pointer on my system)
mov eax, [ecx + 04h] ;eax now holds the value of a[1][1] and ecx still holds the memory location of a[1]
;do stuff with the eax register
mov DWORD PTR SS: [ecx + 4h], 1h ;change the value of a[1][1]

AT&T 语法

   movl a, %ecx
   movl 4%(ecx),%ecx
   movl 4%(ecx),%eax
   ; do stuff with eax
   movl $1,4%(ecx)

编辑:如果你有一个固定大小的数组,那么 Jerry 的解决方案可能会更好,这样你就可以计算一个线性地址,但这也适用于动态分配的二维数组。

于 2012-04-12T04:55:38.907 回答