组装保险箱和钥匙 - 为什么它不起作用?
Assembly safes and keys- why it won't work?
所以我们在组装中遇到了这样的保险箱挑战,您需要创建保险箱和钥匙来破坏它们并结束无限循环。
这是一个保险箱的例子:
loopy:
mov ax, [1900]
cmp ax,1234
jne loopy
和一把钥匙:
loopy2:
mov ax, 1234
mov [1900],ax
jmp loopy2
所以我有一个保险箱和一把钥匙,但我不明白为什么它不起作用:
这是我的保险箱:
org 100h
mySafe:
mov dx,5
mov ax, [5768h]
mov bx,7
mov word [180h],2
mul word [180h]
mov [180h],bx
push ax
dec bx
mov cx,dx
mov ax,dx
loopy1:
add bx,ax
loop loopy1
dec bx
pop ax
add ax,bx
mul word [180h]
cmp ax,350
jne mySafe
这是我的钥匙:
org 100h
loopy:
mov word [5768h],10
jmp loopy
ret
打破循环的正确答案应该是 10 并且当我放入保险箱时它可以工作,但不知何故用钥匙它不起作用而且我不明白为什么..
(nasm 需要 "word")
dx
中用作 loop
指令计数器的值来自第一个 mul
指令。
这个乘法只是将密钥加倍,所以 dx
要么是 0 要么是 1(理解这一点的一种简单方法是将乘法视为左移一位,或者记住两个n位数最多有n+1位)
如果 dx
为零,整个 loopy1
块什么都不做(因为 dx
也设置 ax
)并且 ax
中的值在保险箱的末端是 7*(5 +2k),其中 k 是钥匙(请参阅下面的注释代码)。
那么很容易看出 350 = 7*(5+2k) => 2k = 45 无解。因此 dx
为零的钥匙无法打开保险箱。
如果一个键的值小于 32768,则它的值为 dx
0(同样,当将乘法视为左移一位时,这很容易看出)。
推论:10 不是解。
safe:
mov dx,5
mov ax, [k] ;ax = k (key)
mov bx,7
mov word [aux],2
mul word [aux] ;dx = 0 ax = 2k
mov [aux],bx ;aux = 7
push ax ;ax = 2k
dec bx ;bx = 6
dec bx ;bx = 5
pop ax ;ax = 2k
add ax,bx ;ax = 5 + 2k
mul word [aux] ;ax = 7*(5 +2k)
cmp ax,350
ret
如果有一把钥匙可以打开保险箱,那么它必须大于或等于 32768,以便 dx
在第一次乘法后为 1。
在这种情况下,safe 末尾 ax
中的值可以写为 7*(6 + (2k & 0xffff)) => k & 0x7fff = 22.
添加本节开头所述的条件,k 的最终值为 32768 + 22 = 32790 或十六进制的 0x8016。
在处理方程式和形成结果时,我已经跨越了相当多的逻辑步骤,但是,再一次,将 2k
视为一个转变可能有助于形象化它们。
推论:由于涉及代数结构,这是唯一的解决方案。
safe:
mov dx,5
mov ax, [k] ;ax = k
mov bx,7
mov word [aux],2
mul word [aux] ;dx:ax = 2k
mov [aux],bx ;[aux] = 7
push ax ;dx = 1 ax = 2k & 0xffff
dec bx ;bx = 6
mov cx,dx ;cx = 1
mov ax,dx ;ax = 1
loopy1:
add bx,ax ;bx = 6 + 1
dec cx
jnz loopy1
dec bx ;bx = 6
pop ax ;ax = 2k & 0xffff
add ax,bx ;ax = 6 + (2k & 0xffff)
mul word [aux] ;ax = 7*(6 + (2k & 0xffff))
cmp ax,350
ret
考虑到你在第一次乘法之前有一个mov dx, 5
,你(或保险箱的作者)是否忘记了mul
影响dx
?
如果您将第一个 mul
包裹在 push dx / pop dx
中(或者只是在其后移动 mov dx, 5
),您将在保险箱的末尾得到 ax
中的一个值等于7*(30 +2k) 这意味着确实 k = 10。
所以我们在组装中遇到了这样的保险箱挑战,您需要创建保险箱和钥匙来破坏它们并结束无限循环。 这是一个保险箱的例子:
loopy:
mov ax, [1900]
cmp ax,1234
jne loopy
和一把钥匙:
loopy2:
mov ax, 1234
mov [1900],ax
jmp loopy2
所以我有一个保险箱和一把钥匙,但我不明白为什么它不起作用:
这是我的保险箱:
org 100h
mySafe:
mov dx,5
mov ax, [5768h]
mov bx,7
mov word [180h],2
mul word [180h]
mov [180h],bx
push ax
dec bx
mov cx,dx
mov ax,dx
loopy1:
add bx,ax
loop loopy1
dec bx
pop ax
add ax,bx
mul word [180h]
cmp ax,350
jne mySafe
这是我的钥匙:
org 100h
loopy:
mov word [5768h],10
jmp loopy
ret
打破循环的正确答案应该是 10 并且当我放入保险箱时它可以工作,但不知何故用钥匙它不起作用而且我不明白为什么.. (nasm 需要 "word")
dx
中用作 loop
指令计数器的值来自第一个 mul
指令。
这个乘法只是将密钥加倍,所以 dx
要么是 0 要么是 1(理解这一点的一种简单方法是将乘法视为左移一位,或者记住两个n位数最多有n+1位)
如果 dx
为零,整个 loopy1
块什么都不做(因为 dx
也设置 ax
)并且 ax
中的值在保险箱的末端是 7*(5 +2k),其中 k 是钥匙(请参阅下面的注释代码)。
那么很容易看出 350 = 7*(5+2k) => 2k = 45 无解。因此 dx
为零的钥匙无法打开保险箱。
如果一个键的值小于 32768,则它的值为 dx
0(同样,当将乘法视为左移一位时,这很容易看出)。
推论:10 不是解。
safe:
mov dx,5
mov ax, [k] ;ax = k (key)
mov bx,7
mov word [aux],2
mul word [aux] ;dx = 0 ax = 2k
mov [aux],bx ;aux = 7
push ax ;ax = 2k
dec bx ;bx = 6
dec bx ;bx = 5
pop ax ;ax = 2k
add ax,bx ;ax = 5 + 2k
mul word [aux] ;ax = 7*(5 +2k)
cmp ax,350
ret
如果有一把钥匙可以打开保险箱,那么它必须大于或等于 32768,以便 dx
在第一次乘法后为 1。
在这种情况下,safe 末尾 ax
中的值可以写为 7*(6 + (2k & 0xffff)) => k & 0x7fff = 22.
添加本节开头所述的条件,k 的最终值为 32768 + 22 = 32790 或十六进制的 0x8016。
在处理方程式和形成结果时,我已经跨越了相当多的逻辑步骤,但是,再一次,将 2k
视为一个转变可能有助于形象化它们。
推论:由于涉及代数结构,这是唯一的解决方案。
safe:
mov dx,5
mov ax, [k] ;ax = k
mov bx,7
mov word [aux],2
mul word [aux] ;dx:ax = 2k
mov [aux],bx ;[aux] = 7
push ax ;dx = 1 ax = 2k & 0xffff
dec bx ;bx = 6
mov cx,dx ;cx = 1
mov ax,dx ;ax = 1
loopy1:
add bx,ax ;bx = 6 + 1
dec cx
jnz loopy1
dec bx ;bx = 6
pop ax ;ax = 2k & 0xffff
add ax,bx ;ax = 6 + (2k & 0xffff)
mul word [aux] ;ax = 7*(6 + (2k & 0xffff))
cmp ax,350
ret
考虑到你在第一次乘法之前有一个mov dx, 5
,你(或保险箱的作者)是否忘记了mul
影响dx
?
如果您将第一个 mul
包裹在 push dx / pop dx
中(或者只是在其后移动 mov dx, 5
),您将在保险箱的末尾得到 ax
中的一个值等于7*(30 +2k) 这意味着确实 k = 10。