如何在字节级别反转寄存器值?
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。
答案 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
(*)您要执行的操作不是“还原数字”,而是“还原十进制数字”。