AMD CPU通过解码为两个128b操作来处理256b AVX指令.例如,vaddps ymm0, ymm1,ymm1在AMD上,Steamroller解码为2个宏操作,吞吐量的一半vaddps xmm0, xmm1,xmm1.
XOR归零是一种特殊情况(没有输入依赖性,并且在Jaguar上至少避免消耗物理寄存器文件条目,并且使得来自该寄存器的movdqa在发出/重命名时被消除,就像Bulldozer一直在做非零的REG)中. 但它是否足够vxorps ymm0,ymm0,ymm0早被检测到仍然只能解码为1个具有相同性能的宏操作 vxorps xmm0,xmm0,xmm0?(不像vxorps ymm3, ymm2,ymm1)
或者,在已经解码为两个uop之后,独立检测是否会发生?此外,AMD CPU上的向量xor-zeroing是否仍然使用执行端口?在Intel-CPU上,Nehalem需要一个端口,但Sandybridge系列在发布/重命名阶段处理它.
Agner Fog的指令表没有列出这个特例,他的微指南没有提到uop的数量.
这可能意味着vxorps xmm0,xmm0,xmm0更好的实施方式_mm256_setzero_ps().
对于AVX512 _mm512_setzero_ps(),如果可能的话,也只使用VEX编码的归零惯用语而不是EVEX来保存字节.(即对于zmm0-15. vxorps xmm31,xmm31,xmm31仍然需要EVEX).gcc/clang目前使用他们想要的任何寄存器宽度的xor-zeroing习语,而不是总是使用AVX-128.
报告为clang bug 32862和gcc bug 80636.MSVC已经使用了xmm.尚未向ICC报告,ICC也使用zmm regs进行AVX512归零.(虽然英特尔可能不会改变,因为目前任何英特尔CPU都没有任何好处,只有AMD.如果他们发布的低功耗CPU将矢量分成两半,他们可能.他们目前的低功耗设计(Silvermont)没有t支持AVX,只支持SSE4.)
我知道使用AVX-128指令清零256b寄存器唯一可能的缺点是它不会触发Intel CPU上256b执行单元的预热.可能会破坏试图加热它们的C或C++黑客攻击.
(在第一个256b指令之后的第一个~56k周期内,256b向量指令较慢.请参阅Agner Fog微格式pdf中的Skylake部分).如果调用noinline返回的函数_mm256_setzero_ps不是预热执行单元的可靠方法,那可能没问题.(一个仍然可以在没有AVX2的情况下工作,并且避免任何负载(可以缓存未命中)是__m128 onebits = _mm_castsi128_ps(_mm_set1_epi8(0xff));
return _mm256_insertf128_ps(_mm256_castps128_ps256(onebits), onebits)应该编译为pcmpeqd xmm0,xmm0,xmm0/ vinsertf128 ymm0,xmm0,1.对于你曾经呼叫一次预热(或保持)执行单元的事情,这仍然是非常微不足道的.关键循环.如果你想要内联的东西,你可能需要inline-asm.)
我没有AMD硬件所以我无法测试这个.
如果有人拥有AMD硬件但不知道如何测试,请使用perf计数器来计算周期(最好是m-ops或uops或AMD称之为的任何内容).
这是我用来测试短序列的NASM/YASM源:
section .text
global _start …Run Code Online (Sandbox Code Playgroud) 我正在使用Ubuntu,我正在为Linux寻找汇编编译器,我发现了GAS.
我正在尝试安装并运行它,但我不能.
是否可以使用相同字节的机器代码来确定它们是以32位还是64位模式运行,然后执行不同的操作?
即写多语言机器代码.
通常,您可以在构建时使用#ifdef宏检测.或者在C中,您可以编写一个if()以编译时常量作为条件,并让编译器优化它的另一面.
这仅适用于奇怪的情况,例如代码注入,或只是为了查看是否可能.
另请参见:多语言ARM/x86机器代码,用于分支到不同的地址,具体取决于解码字节的架构.
我有这个简短的你好世界计划:
#include <stdio.h>
static const char* msg = "Hello world";
int main(){
printf("%s\n", msg);
return 0;
}
Run Code Online (Sandbox Code Playgroud)
我用gcc将它编译成以下汇编代码:
.file "hello_world.c"
.section .rodata
.LC0:
.string "Hello world"
.data
.align 4
.type msg, @object
.size msg, 4
msg:
.long .LC0
.text
.globl main
.type main, @function
main:
.LFB0:
.cfi_startproc
pushl %ebp
.cfi_def_cfa_offset 8
.cfi_offset 5, -8
movl %esp, %ebp
.cfi_def_cfa_register 5
andl $-16, %esp
subl $16, %esp
movl msg, %eax
movl %eax, (%esp)
call puts
movl $0, %eax
leave
.cfi_restore 5
.cfi_def_cfa …Run Code Online (Sandbox Code Playgroud) 我正在学习汇编编程.下面是打印'Hello,World!'的简单程序.虽然程序运行完美,但我正在收到警告消息loading
ld:警告:找不到入口符号_start; 默认为0000000008048080
这是代码:
section .data
msg db 'Hello, world!', 0xa
len equ $ - msg
section .text
global main
main:
mov ebx, 1
mov ecx, msg
mov edx, len
mov eax, 4
int 0x80
mov eax, 1
int 0x80
Run Code Online (Sandbox Code Playgroud)
任何人都可以解释这个警告的含义.我使用的是nasm带ubuntu 14.
此描述适用于Linux 32位:当Linux程序开始时,所有指向命令行参数的指针都存储在堆栈中.参数的数量存储在0(%ebp),程序的名称存储在4(%ebp),参数存储在8(%ebp).
64位需要相同的信息.
编辑:我有工作代码示例,演示如何使用argc,argv [0]和argv [1]:http://cubbi.com/fibonacci/asm.html
.globl _start
_start:
popq %rcx # this is argc, must be 2 for one argument
cmpq $2,%rcx
jne usage_exit
addq $8,%rsp # skip argv[0]
popq %rsi # get argv[1]
call ...
...
}
看起来参数在堆栈上.由于此代码不清楚,我问这个问题.我猜我可以将rp保留在rbp中,然后使用0(%rbp),8(%rbp),16(%rbp)等来访问这些参数.这是正确的吗?
我制作了两个程序来输出两个字符串,一个在汇编中,另一个在C中.这是程序集中的程序:
.section .data
string1:
.ascii "Hola\0"
string2:
.ascii "Adios\0"
.section .text
.globl _start
_start:
pushl $string1
call puts
addl $4, %esp
pushl $string2
call puts
addl $4, %esp
movl $1, %eax
movl $0, %ebx
int $0x80
Run Code Online (Sandbox Code Playgroud)
我用它构建程序
as test.s -o test.o
ld -dynamic-linker /lib/ld-linux.so.2 -o test test.o -lc
Run Code Online (Sandbox Code Playgroud)
输出正如预期的那样
Hola
Adios
Run Code Online (Sandbox Code Playgroud)
这是C程序:
#include <stdio.h>
int main(void)
{
puts("Hola");
puts("Adios");
return 0;
}
Run Code Online (Sandbox Code Playgroud)
我得到了预期的输出,但是当使用gcc -S(OS是Debian 32位)将此C程序转换为汇编时,输出汇编源代码不包括两个字符串中的空字符,如下所示:
.file "testc.c"
.section .rodata
.LC0:
.string "Hola"
.LC1:
.string "Adios"
.text
.globl main
.type main, …Run Code Online (Sandbox Code Playgroud) 你们许多人可能还记得旧的DOS程序 - 调试.虽然在许多方面已经过时,但其中一个好处是可以轻松找到给定指令的字节序列,而无需完成编写程序,编译,反汇编,检查文件内容的步骤. ..输入指令,然后转储指令地址.令人遗憾的是'debug'不会执行32位指令.
有没有人知道一个类似于32位x86指令的工具?我不想经历整个编译过程; 我只需要能够输入几条指令并让它显示指令的长度及其字节序列.
我尝试用printf函数编写简单的汇编程序.我编译它nasm -f elf 64并使用链接gcc.跑完后我明白了segmentation fault.怎么了?
[Bits 32]
extern printf
global main
section .data
hello:
db "Hello", 0xa, 0
section .text
main:
push hello
call [printf]
add esp, 4
mov eax, 1
mov ebx, 0
int 80h
Run Code Online (Sandbox Code Playgroud) 如何mov [ebx], al从 NASM 转换为 GAS?我尝试过mov %al, (%ebx),但确实存在分段错误。
另一个问题,假设我在 GAS 中有一个数组,我是否必须像这样.lcomm array, 50
输入美元($)符号:或者不需要?arraymov %rbx, $array
任何答案都会有帮助:)