【问题标题】:Why does this REPNE SCASB implementation of strlen work?为什么 strlen 的这个 REPNE SCASB 实现有效?
【发布时间】:2017-03-07 18:22:31
【问题描述】:

为什么这段代码有效?

http://www.int80h.org/strlen/ 表示字符串地址必须在EDI 寄存器中,scasb 才能工作,但这个汇编函数似乎没有这样做。

mystrlen 的汇编代码:

global  mystrlen
mystrlen:
        sub             ecx, ecx
        not             ecx
        sub             al, al
        cld
        repne scasb
        neg             ecx
        dec             ecx
        dec             ecx
        mov             eax, ecx
        ret

C 主要:

int mystrlen(const char *);
int main()
{
    return (mystrlen("1234"));
}

编译:

nasm -f elf64 test.asm
gcc -c main.c
gcc main.o test.o

输出:

./a.out
echo $?
4

【问题讨论】:

  • 64 位 sysv 调用约定将第一个参数放入 rdi。所以调用者main 已经为你完成了这个加载。您可以检查它的汇编代码并亲自查看。
  • cld 也是废话/多余的。调用约定要求在函数入口处清除方向标志。
  • @R.. 这是什么意思?我对 asm 真的很陌生
  • 我相信这有点意外,那个来源实际上是32b,最多搜索4G字符串长度(如果你给它提供5G长字符串,它会返回错误的答案)。归零ecx 也将清除rcx,但随后not ecx 失败(dec rcx 会更好)然后ecx 的剩余反转也必须调整为rcx,并返回值rax.
  • @Ped7g 你是对的,也许可以添加这个作为答案?

标签: c assembly x86-64 calling-convention strlen


【解决方案1】:

问题中的代码是 strlen 的 32 位版本,它仅在 64b 环境中部分工作,有点“偶然”(因为大多数 SW 在现实中工作,无论如何;))。

64b 环境的一个意外影响是(在 64b linux OS 使用的 System V ABI 中,其他 64b 平台可能遵循不同的调用约定,使此无效!),函数调用中的第一个参数通过rdi 注册,scasb 在 64b 模式下使用 es:rdi,所以这很自然地结合在一起(正如 Jester 的回答所说)。

其他64b环境效果不太好,该代码将返回4+G长字符串的错误值(我知道,在实际使用中不太可能发生,但可以通过提供如此长的字符串的综合测试来尝试)。

修复了 64b 版本(例程结束时利用 rax=0 在单个指令中同时执行 neg ecxmov eax,ecx):

global  mystrlen
mystrlen:
        xor       ecx,ecx    ; rcx = 0
        dec       rcx        ; rcx = -1 (0xFFFFFFFFFFFFFFFF)
        ; rcx = maximum length to scan
        xor       eax,eax    ; rax = 0 (al = 0 value to scan for)
        repne scasb          ; scan the memory for AL
        sub       rax,rcx    ; rax = 0 - rcx_leftover = scanned bytes + 1
        sub       rax,2      ; fix that into "string length" (-1 for '\0')
        ret

【讨论】:

    【解决方案2】:

    64 位 sysv 调用约定将第一个参数放入 rdi。所以调用者main 已经为你完成了加载。您可以检查它的汇编代码并亲自查看。

    (答案由Jester提供)

    【讨论】:

      猜你喜欢
      • 2013-12-17
      • 1970-01-01
      • 2010-10-17
      • 1970-01-01
      • 1970-01-01
      • 2019-03-26
      • 2019-07-13
      • 2011-06-19
      • 2020-10-19
      相关资源
      最近更新 更多