如何将x86汇编中的UP(方向)标志更改为1?

问题描述 投票:0回答:1

我想将标志 UP 更改为 1,现在它是 UP = 0。我正在使用 Visual Studio 64 位程序集。
(英特尔称之为“方向标志”,DF)。

我试过这个:

.data
source DB 'Hello, world!', 0
byte_to_find DB 'o'
.code
MyProc1 proc
    std                     ; Set Direction Flag to 1 (backward direction)
    lea rdi, source         ; Load address of source string

    mov al, byte_to_find    ; Load byte to find into AL
    mov rcx, 13             ; Length of the source string

SearchLoop:
    scasb                   ; Compare AL with byte at [RSI]
    jne NotFound            ; Jump if not equal (byte not found)
    jmp ByteFound           ; Jump if equal (byte found)

NotFound:
    mov rax, 0              ; Set RAX to 0 (byte not found)
    jmp Done

ByteFound:
    mov rax, rdi            ; Store the address of the found byte in RAX
    dec rax                 ; Adjust RAX to point to the byte before the found byte
    jmp Done

Done:
    ret
MyProc1 endp
end

但是当我调试时没有任何变化,仍然是 UP = 1。之后我也尝试仅使用 std 和 mov,但出现了同样的问题。

assembly x86-64 flags eflags
1个回答
0
投票

使用

scasb
向前搜索需要将方向标志DF设置为0。
cld
指令可以做到这一点。它还需要将要查找的字符加载到 AL 寄存器,并将字符串的第一个字符的地址加载到 RDI 寄存器。

使用

scasb

向后搜索需要将方向标志DF设置为1。
std指令可以做到这一点。它还需要将要查找的字符加载到 AL 寄存器,并将字符串的最后一个字符的地址加载到 RDI 寄存器。那么要使用的公式是:
RDI = AddressFirstChar + LengthString - 1

如果我们计划使用 

repne
 前缀,我们还需要向 RCX 寄存器加载字符串的长度。你可以写:

std ; Set DF to 1 (backward direction) mov al, byte_to_find ; Load byte to find in AL mov ecx, 13 ; Load length of the string in RCX lea rdi, [source + rcx - 1] ; Load address of last character in RDI


jne NotFound ; Jump if not equal (byte not found) jmp ByteFound ; Jump if equal (byte found)
未找到:
您不需要这两个跳跃。因为零标志 ZF 只有两个状态,要么是 0,要么是 1,所以如果 ZF=1,您可以跳转到 

ByteFound

,如果 ZF=0,则直接跳转到
NotFound

SearchLoop: scasb ; Compare AL with byte at [RSI] jne NotFound ; Jump if not equal (byte not found) jmp ByteFound ; Jump if equal (byte found)

虽然您将其命名为“Search
Loop
”,但这里没有实际的循环!在
scasb

完成 AL 中的单个字节与内存中 es:[rdi] 处的字节的比较后,您立即跳转到过程中两个可能的出口之一。您需要通过在该指令前添加

scasb
前缀来重复
repne
指令(不等于时重复):
  repne scasb
  je   ByteFound
NotFound:
或者通过编写一个正常的循环:

SearchLoop:
  scasb
  je   ByteFound
  dec  rcx
  jnz  SearchLoop
NotFound:

NotFound: mov rax, 0 ; Set RAX to 0 (byte not found) jmp Done ByteFound: mov rax, rdi ; Store the address of the found byte in RAX dec rax ; Adjust RAX to point to the byte before the found byte jmp Done Done: ret

这里需要进行一些清理,但特别值得注意的是您的评论“调整 RAX 以指向字节
之前
找到的字节”。
我不知道为什么你想返回找到之前

之前的地址,但如果这确实是你需要的,那么就知道RDI已经指向找到的字节之前,所以你不需要那个dec rax !如果您需要指向查找本身,您宁愿增加该值:
NotFound: xor eax, eax ; Set RAX to 0 (byte not found) ret ByteFound: lea rax, [rdi + 1] ; Set RAX to point to the found byte ret

总结

  std                          ; Set DF to 1 (backward direction)
  mov  al, byte_to_find        ; Byte to find in AL
  mov  ecx, 13                 ; Length of the string in RCX
  lea  rdi, [source + rcx - 1] ; Address of last character in RDI
  repne scasb
  cld                          ; (*)
  je   ByteFound
NotFound:
  xor  eax, eax                ; Set RAX to 0 (byte not found)
  ret
ByteFound:
  lea  rax, [rdi + 1]          ; Set RAX to point to the find
  ret

(*) 每当您需要在本地使用 DF=1 时,您应该始终将方向标志返回到清除状态。每个人都希望找到 DF=0,所以我们不必一直使用

cld

    

© www.soinside.com 2019 - 2024. All rights reserved.