【问题标题】:The program crashes when running strlen() written in assembly with SSE4.2 instructions运行使用 SSE4.2 指令汇编编写的 strlen() 时程序崩溃
【发布时间】:2015-11-29 13:53:53
【问题描述】:

我的程序在下面,我想用它来计算一个字符串的长度。

.CODE
EQUAL_EACH = 1000b
strlen_sse PROC
string equ [esp+4]
mov ecx, string
;ecx = string
mov eax, -16
mov edx, ecx
pxor xmm0, xmm0

STRLEN_LOOP:
    add eax, 16
    PcmpIstrI xmm0, xmmword ptr [edx+eax], EQUAL_EACH
    jnz STRLEN_LOOP

add eax, ecx
ret

strlen_sse ENDP
END

当我运行它时它总是崩溃。这是什么原因造成的?

main 如下所示:

#include<stdio.h>
#include<windows.h>
extern "C" int strlen_sse(const char* src);

int main(){
    DWORD start,stop;
    char* str = "asdfasdfasdfasdfasdfasdfasdfasdfasdfasdfasdfasdfasdf";
    start = GetTickCount();
    for (; i < 100000000; i++) {
        strlen_sse(str);
    }
    stop = GetTickCount();
    printf("%lld ms\n",stop-start);
}

我的工作环境是visual studio 2015 community,项目的平台是x64(active),编译时没有任何错误。

我该如何修复这个错误?

【问题讨论】:

  • 你是否检查过你传入的字符串的对齐方式?
  • 当我更改str以满足对齐时,错误仍然存​​在,我将其更改为"asdfasdfasdfasd",长度为16个字节。
  • 但它是否在 16 个字节上对齐(即字符串地址的 4 个最低有效位全为零)?
  • 如果你写了汇编代码,但你不能让它工作,那么你需要切换到C或一些更高级别的代码。另一种选择是坚持;查找您有哪些调试工具,从英特尔网站下载说明手册等。
  • 这看起来很慢(因为 SSE4.2 字符串指令仍然不快,在引入了几代之后)。也许可以尝试使用归零寄存器的pcmpeqb,以及PTEST / jccpmovmsk / test/jccPcmpIstrI4 uops with a memory operand, with a throughput of one per 3 cycles,在 Intel Haswell 上。

标签: assembly sse strlen


【解决方案1】:

C 代码大概编译成 64 位代码,汇编是 32 位代码。在 64 位代码段中包含 32 位代码是行不通的。

将程序集更改为此(我也删除了不必要的代码):

.CODE
EQUAL_EACH = 1000b
strlen_sse PROC
    mov rax, -16
    mov rdx, [rsp + 8]
    pxor xmm0, xmm0

    STRLEN_LOOP:
        add rax, 16
        PcmpIstrI xmm0, xmmword ptr [rdx+rax], EQUAL_EACH
        jnz STRLEN_LOOP

    add rax, rcx
    ret

strlen_sse ENDP
END

【讨论】:

  • 设置 eax 将 rax 的 upper32 归零,所以在第一次迭代时,eax = 0 与他的原始代码。您不需要将 -16 符号扩展为 rax,因为 eax 在用作寻址模式中的索引之前变为非负数。不过,您对 rsp 和 rdx 的看法是正确的。
  • 我使用ml64 /c %(filename).asm 编译程序集,所以我认为程序集代码是64 位的,虽然我使用的是32 位regs。不是吗?
  • 它很可能被放入 64 位段中,但您仍然使用 32 位寄存器寻址堆栈 (esp) 和堆 ([edx+eax]),这会丢失一半地址信息,导致分段/寻址错误。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2019-08-06
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多