8086如何反转寄存器中的字节

时间:2018-12-21 13:37:01

标签: assembly masm emu8086

如何在字节级别反转寄存器值?

UPDATE c
SET     XMLContent.modify('delete //account/correspondence/contact[1]')
FROM   [Customer].[CorrespondenceLog] c

这就是我尝试过的:

mov al,12  -----> how can i reverse al value
to 21

现在mov bx,4321 ;i want to make bx 1234 mov cl,04 ;cl for rotation value xchg bh,bl ; now bx will 2143 mov al,bh ;moving 21 to al rol al,cl ; rotate al 4 times to left now al is 12` mov bh,al ; bh is 12 setuped ,time for bl ;--------------------------- mov al,bl ;moving lower byte 43 to al rol al,cl ; rotate 4 times to left now al will 34 mov bl,al ; moving 34 to bl 必须包含一个反向数字1234;问题是十六进制数字是10e1h或4321。

当我反转时,它是1e01h,但是此值不表示1234。

1234是04d2。我得到的值是7681d。

3 个答案:

答案 0 :(得分:2)

对于您的问题,我也不清楚。您正在使用8086 OS并谈论反转一个字节,然后继续暗示您要反转一个(16位)数字,例如1234。

我的x64 nix上当前未安装EMU8086,但是以下代码可以深入了解实现目标的一种方法:

; ----------------------------------------------------------------------------
; foo.asm
; 
; build on nix with nasm:
;   nasm -f elf foo.asm && gcc -m32 -o dofoos foo.o
;
; ----------------------------------------------------------------------------  

extern  printf

SECTION .data   
fmt: db "ecx:%d", 10, 0  


SECTION .text                   

global main


main:    

mov   ax, 3121   ;initialize input register
mov   bx, 10     ;base10 shift multiplier
xor   ecx, ecx   ;zero-bomb output register (i is on x64 so nuke ecx to avoid garbage)

ADINFINITUM:
xor   dx, dx     ;zero bomb div remainder register 
div   bx         ;div puts quotient in ax and remainder in dx
push  ax         ;push div results to stack to free up registers
push  dx         ;push div results to stack to free up registers
mov   ax, cx     ;reset ax with current output value
mul   bx         ;base10 left-shift current output. result goes to ax 
pop   dx         ;pop back current remainder
add   ax, dx     ;add current remainder to current output
mov   cx, ax     ;update cx with current output
pop   ax         ;pop back current quotient
cmp   ax, 0      ;repeat unless current quotient is zero 
jnz   ADINFINITUM


push  ecx        ;display contents of cx output register
push  fmt
call  printf
add   esp, 8
ret    

如果只想反转一个字节,则略有不同。这样的事情可能会有帮助:

; ----------------------------------------------------------------------------
; foo.asm
; 
; build on nix with nasm:
;   nasm -f elf foo.asm && gcc -m32 -o dofoos foo.o
;
; ----------------------------------------------------------------------------  

extern  printf

SECTION .data   
fmt: db "ecx:%d", 10, 0  


SECTION .text                   

global main


main:    

mov   al, 13     ;initialize input register
mov   bl, 10     ;base10 shift multiplier
xor   ecx, ecx   ;zero-bomb output register (i is on x64 so nuke ecx to avoid garbage)

ADINFINITUM:
xor   ah, ah     ;zero bomb div remainder register 
div   bl         ;div puts 8bit quotient in al and remainder in ah
push  ax         ;push div results to stack to free up registers
mov   al, cl     ;reset al with current output value
mul   bl         ;base10 left-shift current output. result goes to ax 
pop   dx         ;pop back div results  
add   al, dh     ;add current remainder to current output
mov   cl, al     ;update cx with current output
mov   al, dl     ;reset al with current quotient
cmp   dl, 0      ;repeat unless current quotient is zero 
jnz   ADINFINITUM


push  ecx         ;display contents of ecx output register
push  fmt
call  printf
add   esp, 8
ret    

答案 1 :(得分:2)

要反转一个字节中的位,请使用查找表。要反转单词中的位,请使用查找表来反转最低的8位,然后依次rol ax,8,然后使用查询表来反转其他8位。

要反转一个字节中的(4位)半字节,请使用rol al,4。要反转单词中的半字节,请使用rol al,4; rol ax,8; rol al,4

用于反转字节或字中的十进制数字;别。而是,更改输出十进制数字的代码。原因是从整数(例如值1234)到字符串(例如字符“ 1234”)的转换通常会以相反的顺序生成字符,并且必须做额外的工作才能使字符反转。因此,“ print_reversed_decimal()”将减少工作量(以其他方式反转该数字,然后在打印时再次反转该数字,则无济于事!)。或者,您可以改用BCD(每个半字节包含一个十进制数字)。在这种情况下,您可以使用“反向半字节”方法来反转十进制数字,并且打印之后的数字会便宜得多(移位和掩码而不是除法和取模)。

请注意,用于反转整数中的十进制数字的数学运算类似于:

    k = 10000000;
    result = 0;
    while(value > 0) {
        digit = input % 10;
        result += digit * k;
        input /= 10;
        k /= 10;
    }

但是,您必须首先确定k的正确值(这取决于是否忽略前导零或将其取反-例如012变为210或021)。还要注意,这很昂贵(循环内的除法,模和乘法),这就是为什么您想尽一切可能避免这样做的原因。当然,如果数字范围足够小(例如,仅从000到199的值),则可以使用查找表来快速执行此操作。

答案 2 :(得分:2)

虽然其他答案可以为您提供直接解决问题的方法,但我还是想写一些有关该理论的知识,因为我认为这将对您下次有所帮助:

正如您已经写过的那样,在十六进制系统中,十进制数字1234被写为4D2,而在十六进制中被写为4321。

这意味着“返回数字”操作在不同的数字系统中导致不同的结果:

在十进制系统中,“还原” 1234导致4321。在十六进制系统中,“还原” 4D2导致2D4。使用固定长度的4个十六进制数字(16位寄存器!),但是“还原” 04D2将导致2D40 ...

如果某些操作仅在特定的基数(*)下起作用,则必须考虑以下几点:

使用处理字节的计算机,您可以轻松地在base-256系统中执行操作:xchg bh,bl将“恢复” base-256系统中数字的两位数。

通过移位和旋转,可以以2 ^ N为基数执行操作(例如二进制,八进制或十六进制)。

但是,在其他基数(例如十进制)上,您将需要计算一位数字,执行该操作并从这些数字计算(二进制)数字。

要还原十进制数字,可以使用以下伪代码:

  A = input (here: 1234)
  B = 0
mainLoop:
  digit =  A mod 10  (get the right digit of A)
  A = A/10           (remove the right digit from A)
  B = 10*B + digit   (append the digit to B)
  if A>0: jump to mainLoop

在汇编器中,代码可能如下所示:

    mov ax,1234   ; ax = "A" in the pseudo-code
    mov cx,0      ; cx = "B" in the pseudo-code
    mov bx,10     ; The base we are working in
mainLoop:
    xchg ax,cx    ; "mul" can only work with ax
    mul bx        ; Results: ax = "10*B"
                  ;          dx = overflow (typically 0)
    xchg ax,cx    ; Change ax and cx back: cx="10*B"
    mov dx,0      ; Prepare dx for "div"
    div bx        ; Perform division and modulo
                  ; Result:
                  ;   ax = "A/10"
                  ;   dx = "A MOD 10" = "digit"
    add cx,dx     ; "B = 10*B+digit"
    cmp ax,0
    ja mainLoop
                  ; Here cx will contain the "reverted" number

(*)您要执行的操作不是“还原数字”,而是“还原十进制数字”。