- html - 出于某种原因,IE8 对我的 Sass 文件中继承的 html5 CSS 不友好?
- JMeter 在响应断言中使用 span 标签的问题
- html - 在 :hover and :active? 上具有不同效果的 CSS 动画
- html - 相对于居中的 html 内容固定的 CSS 重复背景?
高效地做 x = x*10 + 1
,这可能是最佳使用
lea eax, [rax + rax*4] ; x*=5
lea eax, [1 + rax*2] ; x = x*2 + 1
3-component LEA has higher latency在现代 Intel CPU 上,例如Sandybridge 系列上有 3 个周期与 1 个周期,所以 disp32 + index*2
比 disp8 + base + index*1
快SnB 系列,即我们关心优化的大多数主流 x86 CPU。 (这主要仅适用于 LEA,不适用于加载/存储,因为 LEA 在 ALU 执行单元上运行,而不是在大多数现代 x86 CPU 中的 AGU 上运行。)AMD CPU 的 LEA 较慢,具有 3 个组件或 scale > 1
(http://agner.org/optimize/)
但是 NASM 和 YASM 将通过使用 [1 + rax + rax*1]
来优化代码大小对于第二个 LEA,它只需要 disp8 而不是 disp32。 (寻址模式始终有基址寄存器或 disp32)。
即他们总是 split reg*2
进入base+index
,因为这对于代码大小来说是最糟糕的。
我可以强制使用 lea eax, [dword 1 + rax*2]
的 disp32 ,但这并不能阻止 NASM 或 YASM 拆分寻址模式。 NASM手册似乎没有记录使用the strict
keyword的方法在比例因子上,和 [1 + strict rax*2]
不组装。 有没有办法使用strict
或其他一些语法来强制寻址模式所需的编码?
nasm -O0
禁用优化不起作用。显然,这仅控制多 channel 分支位移优化,而不是 NASM 所做的所有优化。当然,您不想首先对整个源文件执行此操作,即使它确实有效。我仍然明白
8d 84 00 01 00 00 00 lea eax,[rax+rax*1+0x1]
<小时/>我能想到的唯一解决方法是使用 db
手动对其进行编码。这是相当不方便的。根据记录,手动编码为:
db 0x8d, 0x04, 0x45 ; opcode, modrm, SIB for lea eax, [disp32 + rax*2]
dd 1 ; disp32
比例因子编码在 SIB 字节的高 2 位中。我组装lea eax, [dword 1 + rax*4]
获取正确寄存器的机器代码,因为 NASM 的优化仅适用于 *2
。 SIB 为 0x85
,并将字节顶部的 2 位字段递减,将比例因子从 4 减少到 2。
但问题是:如何以一种易于阅读的方式编写它,以便轻松更改寄存器,并让 NASM 为您编码寻址模式?(我想一个巨大的宏可以使用文本处理和手动 db
编码来做到这一点,但这并不是我正在寻找的答案。我现在实际上不需要这个,我主要想知道 NASM 或 YASM 是否有语法来强制执行此操作.)
我知道的其他优化,例如mov rax, 1
汇编为 5 字节 mov eax,1
在所有 CPU 上都是纯粹的胜利,除非您想要更长的指令在没有 NOP 的情况下进行填充,and can be disabled与 mov rax, strict dword 1
获取 7 字节符号扩展编码,或 strict qword
对于 10 字节 imm64。
gas 不会执行此操作或大多数其他优化(仅立即数和分支位移的大小):lea 1(,%rax,2), %eax
组装成
8d 04 45 01 00 00 00 lea eax,[rax*2+0x1]
,对于 .intel_syntax noprefix
也是如此版本。
不过,MASM 或其他汇编器的答案也很有趣。
最佳答案
NOSPLIT
:
Similarly, NASM will split
[eax*2]
into[eax+eax]
because that allows the offset field to be absent and space to be saved; in fact, it will also split[eax*2+offset]
into[eax+eax+offset]
.
You can combat this behaviour by the use of theNOSPLIT
keyword:[nosplit eax*2]
will force[eax*2+0]
to be generated literally.
[nosplit eax*1]
also has the same effect. In another way, a split EA form[0, eax*2]
can be used, too. However,NOSPLIT
in[nosplit eax+eax]
will be ignored because user's intention here is considered as[eax+eax]
.
lea eax, [NOSPLIT 1+rax*2]
lea eax, [1+rax*2]
00000000 8D044501000000 lea eax,[rax*2+0x1]
00000007 8D440001 lea eax,[rax+rax+0x1]
关于assembly - 如何强制 NASM 将 [1 + rax*2] 编码为 disp32 + index*2 而不是 disp8 + base + index?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/48848230/
我刚刚在学习 NASM,我有点想弄清楚这个问题。你如何在 NASM 中声明变量?例如,如何在 NASM 中声明 unsigned int i?谢谢 最佳答案 汇编语言中没有 unsigned int
我正在阅读这篇关于操作系统编程的精彩脚本 http://www.cs.bham.ac.uk/~exr/lectures/opsys/10_11/lectures/os-dev.pdf 第 12 页有一
我正在尝试使用 nasm 打印给我的程序的命令行参数: GLOBAL main EXTERN printf section .rodata fmt db "Argument: %s", 10, 0 s
这两种工具都将汇编指令直接翻译成机器代码,但是否有可能确定哪一种产生最快和最干净的代码? 最佳答案 当您使用汇编程序编写时,您准确地描述了生成 的说明所以它不依赖于汇编程序。这取决于你。您编写的助记符
代码: %define x 0x03 x equ 0x03 它们之间有什么区别? 最佳答案 %define是一种更强大的宏处理方式,类似于 C 预处理器。在您的简单情况下,使用 x 没有太大区
关闭。这个问题不符合Stack Overflow guidelines .它目前不接受答案。 关闭 8 年前。 这个问题似乎是题外话,因为它缺乏足够的信息来诊断问题。更详细地描述您的问题或inclu
我目前正在关注 a tutorial on OS development ,其中包括对引导加载程序的讨论。 我的引导加载程序当前处于 16 位实模式,因此,我能够使用提供的 BIOS 中断(例如 VG
len: equ 2 len: db 2 它们是否相同,产生的标签可以代替2使用?如果不是,那么每种声明形式的优点或缺点是什么?它们可以互换使用吗? 最佳答案 第一个是equate,类似于C
我的循环有问题,其中包含的代码很长,它给了我错误“短跳超出范围”,所以我想知道是否有一种方法可以通过不减少来使循环工作其中代码量有多少? 示例1: label: my code LOOP la
在阅读了至少约4本关于汇编编程的不同书籍的前3或4章之后,我进入了一个阶段,可以使用MASM 6.11将“Hello World”放置在dosbox控制台上。想象一下我的喜悦! 我程序的第一个版本使用
我正在做一个项目,将我编写的子程序附加到老师包含的主文件中。他给了我们使我们的子程序成为全局性的说明,但显然我是个白痴。这两个 asm 文件在同一个文件夹中,我正在使用 nasm -f elf -g
我最近开始使用 NASM 程序集编写代码,但我的问题是我不知道如何以正确的方式访问结构元素。我已经在这个网站和谷歌上搜索了解决方案,但我看到到处都有人说不同的话。我的程序崩溃了,我感觉问题出在访问结构
我正在尝试从用户那里获取输入,然后我想根据用户输入的内容输出一些文本。 我的问题是出于某种原因,它总是认为它是 A,我不知道为什么。你可以在下面找到我的代码: bits 16
我熟悉 TASM 但不太熟悉 NASM。我读过 NASM 允许使用本地标签,这些标签在名称前用点表示。例如代码 .loop: ;some code jmp .loop 定义一个局部标号,
您将如何在寄存器上对 NASM 进行位移?我读了手册,似乎只提到了这些运算符 >> , > 和 >仅用于整数常量。这就是“标量值”的含义。您可以使用 shl 移位寄存器中的值或 shr指示。它们用于将
首先,这是一个家庭作业。 我有一个循环来分别获取两位数的值,并通过将第一个数字乘以 10 并与第二个数字相加得到一个整数来加入它们。 我正在做这一切并保存在我的AL注册,现在我想将该整数插入一个数组,
我一直在做基本的 NASM 编码,我想知道是否可以使用 NASM 模拟按键。如果是这样,怎么做? 如果重要的话,我正在使用 Ubuntu linux 10.04 和 Pentium R T4300 处
我可以在 NASM 中创建一个新标签,它指向一个新的内存位置,该位置与另一个标签指向的内存位置偏移几个字节。 例如:如果 label1 指向内存位置 0x40h,有没有办法使用 label1 定义指向
我需要设置一些标签地址/偏移量的最高位。 我试过: 测试.nasm: BITS 32 dw mylabel | 0x8000 mylabel: dd 0 但是当我尝试组装它时,我得到: nasm -f
如果能向我解释以下使用 printf、使用 nasm 和 gcc 编译的示例中发生了什么,我将不胜感激。为什么“sud”只打印在屏幕上?我也不明白,当我将“push 'sud'”与“push 'sud
我是一名优秀的程序员,十分优秀!