如何使用静态数组的结束指针作为循环条件来比较 x86 中的地址?

2023-12-01

中的挑战问题之一从头开始编程就是“修改程序以使用结束地址而不是数字0来知道何时停止。”

我发现很难做到这一点,因为到目前为止这本书只介绍了movl, cmpl, incl(以及寻址模式)和jmp指示。基本上,下面的代码片段中的所有内容都是到目前为止所介绍的。我发现的所有解决方案都涉及本书中尚未介绍的说明。下面的代码查找集合中的最大值。

.section .data
data_items:             #These are the data items
.long 3,67,34,222,45,75,54,34,44,33,22,11,66,0

.section .text
.globl _start
_start:
    movl $0, %edi                   # move 0 into the index register
    movl data_items(,%edi,4), %eax  # load the first byte of data
    movl %eax, %ebx                 # since this is the first item, %eax is
                                    # the biggest
start_loop:                     # start loop
    cmpl $0, %eax                   # check to see if we’ve hit the end
    je loop_exit
    incl %edi                       # load next value
    movl data_items(,%edi,4), %eax
    cmpl %ebx, %eax                 # compare values
    jle start_loop                  # jump to loop beginning if the new
                                    # one isn’t bigger
    movl %eax, %ebx                 # move the value as the largest
    jmp start_loop                  # jump to loop beginning
loop_exit:
    # %ebx is the status code for the exit system call
    # and it already has the maximum number
    movl $1, %eax   #1 is the exit() syscall
    int $0x80

请注意,这个问题与随后的问题明显不同,后者要求修改程序以使用长度计数而不是数字 0。对我来说,数组中最后一个数字的地址似乎应该存储在寄存器中,然后进行比较到指针的地址。我无法找到一种适合本书进展的方法,因为到目前为止这本书只介绍了大概的框架。


你可以只用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.
本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

如何使用静态数组的结束指针作为循环条件来比较 x86 中的地址? 的相关文章

  • linux perf:如何解释和查找热点

    我尝试了linux perf https perf wiki kernel org index php Main Page今天很实用 但在解释其结果时遇到了困难 我习惯了 valgrind 的 callgrind 这当然是与基于采样的 pe
  • 添加要在给定命令中运行的 .env 变量

    我有一个 env 文件 其中包含如下变量 HELLO world SOMETHING nothing 前几天我发现了这个很棒的脚本 它将这些变量放入当前会话中 所以当我运行这样的东西时 cat env grep v xargs node t
  • 使用按位运算符相乘

    我想知道如何使用按位运算符将一系列二进制位相乘 但是 我有兴趣这样做来查找二进制值的十进制小数值 这是我正在尝试做的一个例子 假设 1010010 我想使用每个单独的位 以便将其计算为 1 2 1 0 2 2 1 2 3 0 2 4 虽然我
  • SIMD 和 VLIW 指令是一样的吗?

    SIMD 单指令多数据 和 VLIW 超长指令字 到底有什么区别 其中一个是另一个的子集吗 或者它们是两个完全不同的东西 完全不相关且正交 一台机器可以有一个或两个 或者两者都没有 SIMD 指令可以作为扩展添加到 VLIW ISA 但 V
  • PHP 从命令行启动 gui 程序,但 apache 不启动

    首先 我阅读了有类似问题的人的一些帖子 但所有答案都没有超出导出 DISPLAY 0 0 和 xauth cookies 这是我的问题 提前感谢您的宝贵时间 我开发了一个小库 它使用 OpenGL 和 GLSL 渲染货架 过去几天我将它包装
  • 避免 gcc 函数序言开销?

    我最近遇到了很多 gcc 在 x86 上生成非常糟糕的代码的函数 它们都符合以下模式 if some condition do something really simple and return else something comple
  • 将 PDF 转换为 600dpi 的 TIFF 和 jpg 96 dpi

    我想使用 ImageMagick 从 Python 脚本将 pdf 转换为 600 dpi 的 tiff 和 96 dpi 的 jpg 我使用 imagemagick 命令行完成了这项任务 但我想使用python中的Imagemagick将
  • 安装J语言的JQt IDE,出现错误

    我一直按照这里的说明进行操作 http code jsoftware com wiki System Installation Linux http code jsoftware com wiki System Installation L
  • movzbl(%rdi, %rcx, 1), %ecx 在 x86-64 汇编中意味着什么?

    我想我明白 movzbl rdi rcx 1 ecx 意思是 将零扩展字节移至长整型 并表示将 ecx 扩展为 32 位 但我不完全确定语法 rdi rcx 1 指的是什么 我在某处看到该语法指的是 Base Index Scale 但我找
  • 如何在shell中输出返回码?

    我正在尝试通过调用自定义 shell 脚本sh bin sh c myscript sh gt log txt 2 gt 1 echo 该命令的输出是创建的后台进程的 PID 我想指导 bin sh保存返回码myscript sh到某个文件
  • 在 Linux 上使用多处理时,TKinter 窗口不会出现

    我想生成另一个进程来异步显示错误消息 同时应用程序的其余部分继续 我正在使用multiprocessingPython 2 6 中的模块来创建进程 我试图用以下命令显示窗口TKinter 这段代码在Windows上运行良好 但在Linux上
  • 汇编器8086将32位数字除以16位数字

    我尝试将 32 位数字除以 16 位数字 例如 10000000h 除以 2000h 根据我尝试做的设计除以 右 4 位数字除以除数 然后左 4 位数字除以除数 这是我的代码 DATA num dd 10000000h divisor dw
  • jpegtran 优化而不更改文件名

    我需要优化一些图像 但不更改它们的名称 jpegtran copy none optimize image jpg gt image jpg 但是 这似乎创建了 0 的文件大小 当我对不同的文件名执行此操作时 大小仍然完全相同 怎么样 jp
  • 我可以在“字节数”设置为零的情况下调用 memcpy() 和 memmove() 吗?

    当我实际上没有什么可以移动 复制的时候 我是否需要处理这些情况memmove memcpy 作为边缘情况 int numberOfBytes if numberOfBytes 0 memmove dest source numberOfBy
  • 如何授予 apache 使用 NTFS 分区上的目录的权限?

    我在一台带有 20GB 硬盘的旧机器上运行 Linux Lubutu 12 10 我有一个 1 TB 外部硬盘 上面有一个 NTFS 分区 在该分区上 有一个 www 目录 用于保存我的网页内容 它在启动时自动安装为 media t515
  • C 问题与指针

    我有一个程序问题 这是代码 int main int p q p int 1000 printf d p q int 2000 printf d q printf d p q return 0 但答案如下 1000 2000 250 我无法
  • 查找哪些页面不再与写入时复制共享

    假设我在 Linux 中有一个进程 我从中fork 另一个相同的过程 后forking 因为原始进程将开始写入内存 Linux写时复制机制将为进程提供与分叉进程使用的不同的唯一物理内存页 在执行的某个时刻 我如何知道原始进程的哪些页面已被写
  • 我的线程图像生成应用程序如何将其数据传输到 GUI?

    Mandelbrot 生成器的缓慢多精度实现 线程化 使用 POSIX 线程 Gtk 图形用户界面 我有点失落了 这是我第一次尝试编写线程程序 我实际上并没有尝试转换它的单线程版本 只是尝试实现基本框架 到目前为止它是如何工作的简要描述 M
  • 在脚本内使用不带密码的 sudo

    由于某种原因 我需要作为用户在没有 sudo 的情况下运行脚本 script sh 该脚本需要 root 权限才能工作 我认为将 sudo 放入 script sh 中是唯一的解决方案 让我们举个例子 script sh bin sh su
  • 当前的 x86 架构是否支持非临时加载(来自“正常”内存)?

    我知道有关此主题的多个问题 但是 我没有看到任何明确的答案或任何基准测量 因此 我创建了一个处理两个整数数组的简单程序 第一个数组a非常大 64 MB 第二个数组b很小 无法放入 L1 缓存 程序迭代a并将其元素添加到相应的元素中b在模块化

随机推荐

  • 你能让一个函数接受两种不同的数据类型吗?

    我有一个函数应该接受两种不同的数据类型作为输入 vec3 add vec3 vec this x vec x this y vec y this z vec z return this vec3 add num scalar this x
  • React - 在父级中拥有 api 函数总是一个好主意吗

    我有一个在 3 个不同地方使用的组件 该组件非常简单 它是一个带有按钮的输入文件组件 因此用户选择文件然后单击upload 我们称之为childComponent upload单击按钮时 应将图像上传到某些 API 服务axios 现在 正
  • 如何使用 open xml C# 禁用 Excel 中的网格线?

    我想在 Excel 中禁用 GridLines 并使用 C 中的 open xml 将自定义边框放入 Excel 单元格 我尝试过下面的代码 但是当我打开Excel时抛出异常 例外情况是 已修复部分 xl worksheets sheet
  • Msysgit bash 在 Windows 7 中慢得可怕

    我喜欢 git 并且经常在家中在 OS X 上使用它 在工作中 我们在Windows上使用svn 但希望在工具完全成熟后立即迁移到git 不仅仅是乌龟Git 而且还类似于由以下提供的非常好的 Visual Studio 集成视觉SVN 但我
  • 使用 C# 的年份差异[重复]

    这个问题在这里已经有答案了 如何计算两个日期之间的日期差 以年为单位 例如 Datetime Now Today 11 03 2007 多年 我编写了一个实现 可以正确处理相隔一年的日期 然而 与其他算法不同 它不能很好地处理负时间跨度 它
  • 如何使用类型标签/镜像在方法中获取构造函数参数?

    对于案例类别 case class MyClass param1 String param2 String 为什么采用这种反思方法 import scala reflect runtime universe import scala ref
  • 使用 PHP 查询 XML 文件

    使用PHP5有没有一种方法可以像查询数据库一样查询XML文件 如果我有一个包含 50 个酒店条目的 XML 文件 我如何查询该 XML 文件以获取特定条目 我还可以按字段 例如日期字段 重新组织 XML 条目吗 那么 如果我想按日期降序显示
  • 如何将信号 NaN 转换为安静 NaN?

    我想在 C 中将信号 NaN 转换为安静 NaN 有人可以建议一种方法吗 Thanks 我想我会扩展我的评论并提供解决方案 这里棘手的部分是能够读取 比较sNaN而不触发异常 毕竟 它被称为 信号 是有原因的 维基百科说 即使是比较操作sN
  • ASP.NET 路由:如何使routeConfig 处理更动态的URL 结构

    我的场景如下 一个场地可以属于多个类别 用户也可以在多个类别类型上添加过滤器 所以我的 URL 现在是这样的 venues beaches boats themeparks 这将显示所有海滩 船只和主题公园的场地 venues beache
  • 使用 JButton 增加/减小 textArea 内的字体大小

    我正在使用 Java 创建一个便签应用程序 我想做的事 我想增加里面文字的大小textArea每次我点击增加尺寸 显然我会知道如何做相反的事情 短代码 JButton incButton new JButton fontFrame add
  • 通过套接字接收文件,TCP 连接冻结

    我已经研究了 4 个小时的套接字 我使用的方式是只有一个应用程序作为客户端和服务器 一旦客户端连接 它就会与新客户端打开线程并等待消息 一旦消息发送到服务器 客户端就会收到响应 该部分工作正常 没有任何问题 客户主题的一部分 while t
  • 如何伪造 H2 数据库中的 ENUM 列以进行单元测试?

    我有一套玩 我已经针对 H2 数据库运行了单元测试 我已向模型中添加了一些枚举列 但由于用于创建模型表的 sql 语句 测试现在失败了 错误信息是 14 42 10 435 ERROR Unknown data type ENUM SQL
  • 将 powershell 命令的输出存储在变量中

    以下命令 sun PowerShell DateTime Today AddDays 8 ToString dd MMM yyyy echo sun 回声的输出是 PowerShell DateTime Today AddDays 8 To
  • 更改 JQuery 范围滑块图像

    我正在尝试使用 JQuery 范围滑块 可以为 手柄 其中两个 很好 但我希望两个手柄都有一个 不同的图像而不是相同的图像 左箭头和右箭头 这可能吗 Thanks 抱歉拖了一个老问题 但我想做同样的事情 不幸的是 上面的方法不起作用 因为它
  • 如何将 p 值表添加到生存图中?

    我有数据如下 library survival library survminer data aml aml x lt as character aml x aml 10 3 lt SuperMaintained aml 11 3 lt S
  • Symfony2 数据库翻译加载器未执行

    我必须实现我自己的翻译加载器 我已经使用了以下教程 http blog elendev com development php symfony use a database as translation provider in symfon
  • php 如果小写字母前面没有空格,则将字符串分解为大写

    str Hello MotoBell RingsKing Speech 如果该字符串之前存在小写字母 我需要将其分解为大写字母 像这样 splitted array 0 gt Hello Moto 1 gt Bell Rings 2 gt
  • Kafka Broker SSL - NoAuth 异常 - /brokers/ids 的 KeeperErrorCode NoAuth

    在为 Broker 到 Zookeeper 身份验证实施 SSL 时 我最终在 Broker 2 节点上出现以下异常 从 SSL 设置中 集群配置了 SSL 身份验证 Broker 1 成功连接到 Zookeeper 但在 Broker 2
  • 将多个图分组到一张图中Python

    我的函数返回 28 个图 图 但我需要将它们分组在一个图上 这是我生成 28 个图的代码 for cat in df ASS ASSIGNMENT unique a df loc df ASS ASSIGNMENT cat dates a
  • 如何使用静态数组的结束指针作为循环条件来比较 x86 中的地址?

    中的挑战问题之一从头开始编程就是 修改程序以使用结束地址而不是数字0来知道何时停止 我发现很难做到这一点 因为到目前为止这本书只介绍了movl cmpl incl 以及寻址模式 和jmp指示 基本上 下面的代码片段中的所有内容都是到目前为止