"最佳"意味着最少的指令(或最少的uops,如果任何指令解码到多个uop).机器码大小(以字节为单位)是相同insn计数的平局.
恒定生成本质上是一个新的依赖链的开始,所以延迟很重要.在循环内生成常量也很不寻常,因此吞吐量和执行端口需求也几乎无关紧要.
生成常量而不是加载它们需要更多指令(除了全零或全一),因此它会占用宝贵的uop-cache空间.这可能是比数据缓存更有限的资源.
Agner Fog优秀的优化装配指南涵盖了这一点Section 13.4.表13.10具有用于产生向量序列,每一个元素是0,1,2,3,4,-1,或-2,与从8位到64位单元大小.表13.11具有用于产生一些浮点值序列(0.0,0.5,1.0,1.5,2.0,-2.0,和位掩码为符号位.)
Agner Fog的序列仅使用SSE2,无论是设计还是因为它尚未更新一段时间.
使用短的非显而易见的指令序列可以生成哪些其他常量? (具有不同移位计数的进一步扩展是显而易见的而不是"有趣的".)是否有更好的序列用于生成Agner Fog列出的常量?
如何将128位immediates移动到XMM寄存器说明了将任意128b常量放入指令流的一些方法,但这通常是不合理的(它不会节省任何空间,并占用大量的uop-cache空间.)
要清除所有位,您经常会看到一个独占或在XOR eax, eax.反过来也有这样的伎俩吗?
我能想到的是用额外的指令反转零.
我将一些程序集与一些c链接起来测试函数调用的成本,使用以下程序集和c源代码(分别使用fasm和gcc)
部件:
format ELF
public no_call as "_no_call"
public normal_call as "_normal_call"
section '.text' executable
iter equ 100000000
no_call:
mov ecx, iter
@@:
push ecx
pop ecx
dec ecx
cmp ecx, 0
jne @b
ret
normal_function:
ret
normal_call:
mov ecx, iter
@@:
push ecx
call normal_function
pop ecx
dec ecx
cmp ecx, 0
jne @b
ret
Run Code Online (Sandbox Code Playgroud)
c来源:
#include <stdio.h>
#include <time.h>
extern int no_call();
extern int normal_call();
int main()
{
clock_t ct1, ct2;
ct1 = clock();
no_call();
ct2 = clock(); …Run Code Online (Sandbox Code Playgroud) 在我的64位Intel机器下面代码工作:
mov rdi, 1 << 40
add r10, rdi
Run Code Online (Sandbox Code Playgroud)
而这相当于一个产生警告并且不起作用:
add r10, 1 << 40
Run Code Online (Sandbox Code Playgroud)
我应该坚持1号还是我错过了什么?这种行为似乎很尴尬.
代码nr 2产生的警告:
warning: signed dword immediate exceeds bounds
Run Code Online (Sandbox Code Playgroud) 我正在尝试推送一个64位整数但是在组装NASM时似乎想把它看成是一个DWORD而不是QWORD.
我正在使用ASM来创建shellcode,我需要将64位DLL注入到64位进程中.第一个QWORD是旧指令指针,第二个是包含DLL地址的地址,第三个是LoadLibrary的地址.占位符在运行时填充.
section .text
global _start
_start:
BITS 64
PUSH QWORD 0xACEACEACACEACEAC
PUSHFQ
push rax
PUSH QWORD 0xACEACEACACEACEAC
MOV RAX, 0xACEACEACACEACEAC
CALL RAX
pop RAX
POPFQ
RETN
Run Code Online (Sandbox Code Playgroud) 我想测试按位运算是否真的比算术运算更快.我以为他们是.
我写了一个小的C程序来测试这个假设,令我惊讶的是,加法平均比按位AND运算少.这对我来说是令人惊讶的,我无法理解为什么会这样.
根据我所知的附加,来自较低有效位的进位应该被携带到下一位,因为结果也取决于进位.对我来说逻辑运算符比加法更慢是没有意义的.
我的鳕鱼在下面:
#include<stdio.h>
#include<time.h>
int main()
{
int x=10;
int y=25;
int z=x+y;
printf("Sum of x+y = %i", z);
time_t start = clock();
for(int i=0;i<100000;i++)z=x+y;
time_t stop = clock();
printf("\n\nArithmetic instructions take: %d",stop-start);
start = clock();
for(int i=0;i<100000;i++)z=x&y;
stop = clock();
printf("\n\nLogic instructions take: %d",stop-start);
}
Run Code Online (Sandbox Code Playgroud)
一些结果:
Arithmetic instructions take: 327
Logic instructions take: 360
Arithmetic instructions take: 271
Logic instructions take: 271
Arithmetic instructions take: 287
Logic instructions take: 294
Arithmetic instructions take: 279
Logic instructions take: …Run Code Online (Sandbox Code Playgroud) c assembly instructions logical-operators integer-arithmetic