你可以只用mov
and cmp
, no lea
需要计算结束指针。 (无论如何,您都没有可以与 LEA 一起使用的长度)。
您应该在数组末尾添加一个新标签,以便可以引用内存中的该位置(也称为地址)。并删除终止0
从数组中,因为我们使用地址而不是哨兵值。
.section .data
data_items:
.long 3,67,34,222,45,75,54,34,44,33,22,11,66 # ,0 remove the sentinel / terminator
data_items_end: # and add this new label
您不需要将该地址记录在寄存器中;您可以使用cmp $data_items_end, %reg
将其用作立即数,链接器将正确的字节填充到机器代码中,就像它为您的代码所做的那样mov data_items(,%edi,4), %eax
. (cmp symbol, %reg
将与该地址处的内存进行比较。$symbol
是 AT&T 语法中的立即数地址。)
你什么do寄存器中需要的是start地址,以便您可以递增和取消引用它。 (对于采用指针+长度的函数,您可以计算寄存器中的结束地址。)
_start:
mov $data_items, %edi # int *ptr = &data_items[0]
mov (%edi), %ebx # current max
# setting %eax is unnecessary here, it's always written before being read in this and the original version
loop_start:
add $4, %edi # ptr++ (4 byte elements)
cmp $data_items_end, %edi
je loop_exit # if (ptr == endp) break
... # compare with (%edi) and update %ebx if greater.
jmp loop_start
...
更有效的是do{}while像编译器使用的循环结构,特别是因为您知道数组包含超过 1 个元素,因此您无需检查循环体应运行 0 次的情况。请注意,没有无条件的jmp
除了 cmp/jcc 之外,它每次都必须执行。
_start:
mov $data_items, %edi # int *ptr = &data_items[0]
mov (%edi), %ebx # current max
loop_start: # do{
add $4, %edi # ptr++; (4 byte elements)
## maybe update max:
mov (%edi), %eax # tmp = *ptr;
cmp %ebx, %eax
cmovg %eax, %ebx # max = (tmp > max) ? tmp : max;
## end of loop body
cmp $data_items_end, %edi
jne loop_start # }while(ptr != endp)
## end of loop, but nothing jumps here so no label is needed.
mov $1, %eax
int $0x80 # SYS_exit(%ebx)
I used cmp
/cmovg
(条件移动)而不是仅仅因为输入的指令较少且没有分支而分支within循环,更容易看到循环结构。
循环和指针的其他示例:
-
汇编语言 (x86):如何创建循环来计算斐波那契数列- 采用指针+长度作为参数,并使用 LEA 计算结束指针的函数。 (x86-64 NASM 语法)
-
如何用汇编语言(ASM)检查“数组的长度”,- 根据a的长度定义汇编时间常数
.long
静态数组,而不是在末尾放置标签。
-
复制到 NASM 中的阵列- 编写循环的高效循环的一些技巧two数组,例如相对于另一个进行索引,仍然只使用一个增量,但避免索引寻址模式。或者将负索引向上计数到零,这样您仍然可以在内存中向前循环,但仍然不需要单独的 cmp 指令,只需
inc / jnz
.