das*_*20s 2 linux x86 assembly pointers att
从头开始编程的挑战之一是“修改程序以使用结束地址而不是数字 0 来知道何时停止。”
\n我发现很难做到这一点,因为到目前为止,这本书只介绍了movl,,cmpl(incl以及寻址模式)和jmp指令。基本上,下面的代码片段中的所有内容都是到目前为止所介绍的。我发现的所有解决方案都涉及本书中尚未介绍的说明。下面的代码查找集合中的最大值。
.section .data\ndata_items: #These are the data items\n.long 3,67,34,222,45,75,54,34,44,33,22,11,66,0\n\n.section .text\n.globl _start\n_start:\n movl $0, %edi # move 0 into the index register\n movl data_items(,%edi,4), %eax # load the first byte of data\n movl %eax, %ebx # since this is the first item, %eax is\n # the biggest\nstart_loop: # start loop\n cmpl $0, %eax # check to see if we\xe2\x80\x99ve hit the end\n je loop_exit\n incl %edi # load next value\n movl data_items(,%edi,4), %eax\n cmpl %ebx, %eax # compare values\n jle start_loop # jump to loop beginning if the new\n # one isn\xe2\x80\x99t bigger\n movl %eax, %ebx # move the value as the largest\n jmp start_loop # jump to loop beginning\nloop_exit:\n # %ebx is the status code for the exit system call\n # and it already has the maximum number\n movl $1, %eax #1 is the exit() syscall\n int $0x80\nRun Code Online (Sandbox Code Playgroud)\n请注意,这个问题与随后的问题明显不同,后者要求修改程序以使用长度计数而不是数字 0。对我来说,数组中最后一个数字的地址似乎应该存储在寄存器中,然后进行比较到指针的地址。我无法找到一种适合本书进展的方法,因为到目前为止,这本书只介绍了大概的框架。
\n您只需使用mov和即可完成此操作cmp,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
Run Code Online (Sandbox Code Playgroud)
您不需要在寄存器中保存该地址;您可以将cmp $data_items_end, %reg其用作立即数,链接器将正确的字节填充到机器代码中,就像为您的mov data_items(,%edi,4), %eax. (cmp symbol, %reg将与该地址处的内存进行比较。 $symbol该地址是 AT&T 语法中的立即数。)
您在寄存器中需要的是起始地址,因此您可以递增和取消引用它。(对于采用指针+长度的函数,您可以计算寄存器中的结束地址。)
_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
...
Run Code Online (Sandbox Code Playgroud)
更有效的是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)
Run Code Online (Sandbox Code Playgroud)
我使用cmp/ cmovg(条件移动)而不是分支只是因为输入的指令较少并且循环内没有分支,从而更容易查看循环结构。
循环和指针的其他示例:
.long,而不是在末尾放置标签。inc / jnz.| 归档时间: |
|
| 查看次数: |
278 次 |
| 最近记录: |