Warning: file_get_contents(/data/phpspider/zhask/data//catemap/0/assembly/6.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181

Warning: file_get_contents(/data/phpspider/zhask/data//catemap/8/svg/2.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Assembly 获取最后一行分隔符_Assembly_X86 64 - Fatal编程技术网

Assembly 获取最后一行分隔符

Assembly 获取最后一行分隔符,assembly,x86-64,Assembly,X86 64,我认为这是一个非常常见的任务,应该有一些快速简洁的解决方案。我有一个四字,我想得到最低字节位置,它等于0x0A(Linux中的换行符)。我编写了以下简单程序: SYS_exit equ 0x3C section .text global _start _start: mov rax, 0x0A mov rbx, [dt] mov rcx, 0x07 loop: mov r13, rbx and r13, 0xFF

我认为这是一个非常常见的任务,应该有一些快速简洁的解决方案。我有一个四字,我想得到最低字节位置,它等于0x0A(Linux中的换行符)。我编写了以下简单程序:

SYS_exit equ 0x3C

section .text
    global _start

_start:
    mov rax, 0x0A
    mov rbx, [dt]
    mov rcx, 0x07
    loop:
        mov r13, rbx
        and r13, 0xFF
        cmp r13, 0x0A
        jz ok
        shr rbx, 8
        dec rcx
        jnz loop
        jmp fail
    ok:
        mov rax, SYS_exit
        mov rdi, 8
        sub rdi, rcx
        syscall
    fail:
        mov rax, SYS_exit
        mov rdi, -1
        syscall


section .data
    dt: dq 0xAB97450A8733AA1F
而且它工作得很好<代码>边距。/bin打印

execve("./bin", ["./bin"], [/* 69 vars */]) = 0
exit(5)                                 = ?
+++ exited with 5 +++
但是这个程序看起来很难看,事实上我正在寻找一种方法使它尽可能快。你能给出一些优化建议吗

但是这个节目看起来很难看

祝贺你注意到:p

我正在寻找一种方法,使它尽可能快

SSE2是x86-64的基线,所以您应该使用它。您可以在两条指令中执行此操作,使用pcmpeqb/pmovmskb获得字节比较结果的位图,然后使用位扫描指令,如(扫描反向为您提供最高设置位的索引)

显然,在循环中,您将在寄存器中保留
换行掩码
(然后您可以使用AVX
vbroadcastss
,或SSE3
movddup
,而不需要内存中的整个16字节常量)

当然,您可以使用
movdqu
load一次加载16个字节,或者使用AVX2一次加载32个字节如果您有一个大的缓冲区,那么您基本上是在实现向后的
memcmp
,应该考虑优化的库实现。
它们可能会将整个缓存线的
pcmpeqb
结果与
por
结合起来,因此,他们保存了3/4的
pmovmskb
工作,直到最后,当他们确定缓存线的哪个部分被命中时

如果您关心AMD CPU(其中
bsr
速度较慢),在使用
tzcnt
之前,可以使用
test edi、edi
/
jz
单独测试input=0。(
tzcnt(x)
为您提供
31 bsr(x)
,如果输入为零,则为32。)如果您可以依赖BMI2可用


如果要使用标量循环,可以在寄存器的低位字节上使用字节比较,而不是复制和屏蔽值

    ; we test byte 7 first, so start the counter there.
    mov  edi, 7         ; no idea why you were using a 64-bit counter register
   ; loop body runs with edi=7..0
.loop:                ; do{
    rol  rbx, 8         ; high byte becomes low

    cmp  bl, 0xa        ; check the low byte
    je   .found

    dec  edi
    jge  .loop        ; } while(--edi>=0) signed compare
   ; not found falls through with edi=-1

 .found:
    mov  eax, SYS_exit
    syscall           ; exit(7..0) for found, or exit(-1) for not-found
根据您对结果所做的操作,您可能会以不同的方式排列循环计数器

但是这个节目看起来很难看

祝贺你注意到:p

我正在寻找一种方法,使它尽可能快

SSE2是x86-64的基线,所以您应该使用它。您可以在两条指令中执行此操作,使用pcmpeqb/pmovmskb获得字节比较结果的位图,然后使用位扫描指令,如(扫描反向为您提供最高设置位的索引)

显然,在循环中,您将在寄存器中保留
换行掩码
(然后您可以使用AVX
vbroadcastss
,或SSE3
movddup
,而不需要内存中的整个16字节常量)

当然,您可以使用
movdqu
load一次加载16个字节,或者使用AVX2一次加载32个字节如果您有一个大的缓冲区,那么您基本上是在实现向后的
memcmp
,应该考虑优化的库实现。
它们可能会将整个缓存线的
pcmpeqb
结果与
por
结合起来,因此,他们保存了3/4的
pmovmskb
工作,直到最后,当他们确定缓存线的哪个部分被命中时

如果您关心AMD CPU(其中
bsr
速度较慢),在使用
tzcnt
之前,可以使用
test edi、edi
/
jz
单独测试input=0。(
tzcnt(x)
为您提供
31 bsr(x)
,如果输入为零,则为32。)如果您可以依赖BMI2可用


如果要使用标量循环,可以在寄存器的低位字节上使用字节比较,而不是复制和屏蔽值

    ; we test byte 7 first, so start the counter there.
    mov  edi, 7         ; no idea why you were using a 64-bit counter register
   ; loop body runs with edi=7..0
.loop:                ; do{
    rol  rbx, 8         ; high byte becomes low

    cmp  bl, 0xa        ; check the low byte
    je   .found

    dec  edi
    jge  .loop        ; } while(--edi>=0) signed compare
   ; not found falls through with edi=-1

 .found:
    mov  eax, SYS_exit
    syscall           ; exit(7..0) for found, or exit(-1) for not-found

根据您对结果所做的操作,您可能会以不同的方式安排循环计数器。

由于您有工作代码,因此您的问题在上的提问更为恰当。请要求将问题迁移到最高字节位置=最后一个?因为在您的示例中,第一次跳转到
ok
。那是哪一个?@Ped7g当然,是打字错误。我指的是第一个问题,当然,谢谢。因为你有工作代码,你的问题在上问得更恰当。请要求将问题迁移到最高字节位置=最后一个?因为在您的示例中,第一次跳转到
ok
。那是哪一个?@Ped7g当然,是打字错误。我指的是第一个,当然,谢谢。顺便说一句,这是最后一行分隔符,就像你的问题标题要求的那样。我以为这是你代码中的一个bug。如果您想要第一个,请使用bsf。(或者在标量循环中,检查低字节后使用
shr rbx,8
。@fuz:您可以使用它,但我不确定它是否有用,即使它内置了BSF功能。在Skylake上,p0为3 uops,延迟为12c。但是对于p01,
pcmpeqb
是1c,
pmovmskb
对于p0是2到3c,
bsf
对于p1是1c。因此,这比
pcmpistri
具有更好的吞吐量和延迟<如果您不知道长度,并且还必须检查终止字节,即实现
strchr
而不是
memchr
,则code>pcmpistri可能很有用。但可能仍然没有;可能只对更复杂的搜索有用,比如字符范围。如果你有AVX2,SSE4.2字符串指令就不值得考虑了;一次32个字节会将它们吹走。顺便说一句,这会得到最后一行分隔符,就像你的问题标题要求的那样。我以为这是你代码中的一个bug。如果您想要第一个,请使用bsf。(或者在标量循环中,检查低字节后使用
shr rbx,8
。@fuz:您可以使用它,但我不确定它是否有用,即使它内置了BSF功能。在Skylake上,p0为3 uops,延迟为12c。但是对于p01,
pcmpeqb
是1c,对于p01,
pmovmskb
是2到3c