相关疑难解决方法(0)

使用xmm寄存器而不是ymm时,vxorps在AMD Jaguar/Bulldozer/Zen上的归零速度是否更快?

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)

x86 assembly avx micro-optimization amd-processor

11
推荐指数
1
解决办法
691
查看次数

如何在Linux上安装和使用GAS(GNU编译器)?

我正在使用Ubuntu,我正在为Linux寻找汇编编译器,我发现了GAS.

我正在尝试安装并运行它,但我不能.

linux ubuntu assembly gnu-assembler

10
推荐指数
2
解决办法
2万
查看次数

x86-32/x86-64多语言机器码片段,在运行时检测64位模式?

是否可以使用相同字节的机器代码来确定它们是以32位还是64位模式运行,然后执行不同的操作?

即写多语言机器代码.

通常,您可以在构建时使用#ifdef宏检测.或者在C中,您可以编写一个if()以编译时常量作为条件,并让编译器优化它的另一面.

这仅适用于奇怪的情况,例如代码注入,或只是为了查看是否可能.


另请参见:多语言ARM/x86机器代码,用于分支到不同的地址,具体取决于解码字节的架构.

x86 assembly

10
推荐指数
1
解决办法
789
查看次数

如果我要在程序集中编写程序,那么这个HelloWorld汇编代码的哪些部分是必不可少的?

我有这个简短的你好世界计划:

#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)

c linux x86 assembly

10
推荐指数
1
解决办法
1149
查看次数

加载警告:找不到条目符号_start

我正在学习汇编编程.下面是打印'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)

任何人都可以解释这个警告的含义.我使用的是nasmubuntu 14.

assembly warnings

8
推荐指数
3
解决办法
1万
查看次数

程序集中的Linux 64命令行参数

此描述适用于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)等来访问这些参数.这是正确的吗?

linux 64-bit assembly command-line

7
推荐指数
2
解决办法
6705
查看次数

从C转换为汇编时,以null结尾的字符串在哪里?

我制作了两个程序来输出两个字符串,一个在汇编中,另一个在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)

c linux x86 gcc

7
推荐指数
1
解决办法
650
查看次数

DOS调试类似于32位x86程序集的程序

你们许多人可能还记得旧的DOS程序 - 调试.虽然在许多方面已经过时,但其中一个好处是可以轻松找到给定指令的字节序列,而无需完成编写程序,编译,反汇编,检查文件内容的步骤. ..输入指令,然后转储指令地址.令人遗憾的是'debug'不会执行32位指令.

有没有人知道一个类似于32位x86指令的工具?我不想经历整个编译过程; 我只需要能够输入几条指令并让它显示指令的长度及其字节序列.

debugging assembly

6
推荐指数
1
解决办法
2221
查看次数

Linux程序集和printf

我尝试用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)

c assembly printf nasm

6
推荐指数
1
解决办法
7018
查看次数

从 NASM 翻译为 GAS

如何mov [ebx], al从 NASM 转换为 GAS?我尝试过mov %al, (%ebx),但确实存在分段错误。

另一个问题,假设我在 GAS 中有一个数组,我是否必须像这样.lcomm array, 50 输入美元($)符号:或者不需要?arraymov %rbx, $array

任何答案都会有帮助:)

x86 assembly gnu-assembler nasm att

5
推荐指数
1
解决办法
5708
查看次数