汇编字符串指令在实模式下寄存器 DS 和 ES

标签 assembly x86 nasm real-mode

我一直在从我的书中研究这个汇编程序,我有一个关于它的问题。该程序的目的是将 string1 复制到 string2。我的问题涉及以下两条说明:

mov    AX,DS        
mov    ES,AX 

我发现如果没有它们,程序将无法正常工作,但我会想通过将 ESI 指向 string1 并将 EDI 指向 string2,这就是你的全部需要做。然后只需增加 ESIEDI 并逐个字符地移动它。 DS 到底包含什么以及为什么我们需要将其移至 ES

.DATA
string1    db    'The original string',0
strLen     EQU   $ - string1
.UDATA
string2    resb    80
.CODE
    .STARTUP
    mov    AX,DS          ; set up ES
    mov    ES,AX          ;  to the data segment
    mov    ECX,strLen     ; strLen includes NULL
    mov    ESI,string1
    mov    EDI,string2
    cld                   ; forward direction
    rep    movsb

最佳答案

所有使用EDI字符串指令都使用ES:EDI。 (或dirdi)

使用EDI(如[edi])的显式寻址模式默认为DS,但movs/stos/scas/cmps (with/without rep/repz/nz) all use es:edilods 仅使用ds:esi。 (rep lods “有效”,但很少有用。当 cx=0 或 1 时,它可以作为缓慢的条件加载,因为与 loop 不同,rep 在递减之前检查 cx。)

请注意,尽管 scas 是只读的,但它使用 (r|e)di。这使得它可以很好地与 lods 配合使用:使用 lods 从一个数组加载,scas 可以与不同的数组进行比较。 (可选地在比较之前对 (r|e)ax 进行某种处理)。


通常,当您可以使用 32 位地址时,您将拥有一个平面内存模型,其中所有段都具有相同的基址和限制。或者,如果您使用 NASM 制作 .COM 平面二进制文件,则您将拥有微小的实模式内存模型,其中所有段都具有相同的值。请参阅@MichaelPetch 的评论 on this answeron the question如果您的程序在不设置ES的情况下无法运行,那么您正在做一些奇怪的事情。 (就像可能在某个地方破坏es?)

请注意,在没有地址大小前缀的 16 位模式下,rep movsb 使用 CXDS:SI ES:DI,无论您是否使用操作数大小前缀来编写 edi 而不是 di


另请注意,代表字符串指令(尤其是非代表版本)**通常不是最快的方法。它们适合代码大小,但通常比 SSE/AVX 循环慢。

rep stosrep movs 具有快速微编码实现,可以以 16 或 32 字节(或 Skylake-AVX512 上的 64 字节?)为单位存储或复制。请参阅Enhanced REP MOVSB for memcpy 。凭借 32 字节对齐的指针和中等到大的缓冲区大小,它们可以与优化的 AVX 循环一样快。当现代 CPU 上的大小低于 128 或 256 字节或未对齐的指针时,AVX 复制循环通常会获胜。英特尔的优化手册中有一节对此进行了介绍。

但是 repne cmpsb 绝对不是实现 memcmp 的最快方法:使用 SSE2 或 AVX2 SIMD 比较 (pcmpeqb),因为微码一次仍然只比较一个字节。 (小心读取超过缓冲区末尾的内容,尤其是避免跨越页面(或最好是缓存行)边界。)无论如何,repne/repe 没有“快速”不幸的是,Intel 或 AMD CPU 中的字符串”优化。

关于汇编字符串指令在实模式下寄存器 DS 和 ES,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/47566416/

相关文章:

assembly - 如何使用 Gas ('as' ) 在 64 位 linux 上组装 32 位二进制文​​件?

linux - 如何编译 Intel x86 汇编代码以获取十六进制转储?

c - Linux asm ("int $0x0") 与除以零

performance - L1缓存命中的周期/成本与在x86上注册的周期/成本?

assembly - assembly NASM 中的随机数生成

assembly - 如何在 nasm 中启用 a20?

assembly - 在 MASM32 程序集中打印 unicode 字符

assembly - "conditional call"在 amd64 上的性能

assembly - 如何在 x86 程序集中将字符从一个内存位置复制到另一个内存位置?

assembly - 为什么在PUSHA指令中执行PUSH BX之前先执行PUSH CX