gpt4 book ai didi

程序集跳转/分支/查找表而不是大量的 cmp/je?

转载 作者:行者123 更新时间:2023-12-02 15:35:13 24 4
gpt4 key购买 nike

我刚刚开始学习汇编,并正在制作一个简单的引导加载程序作为我的操作系统类(class)的一部分。我正在努力使我的代码更加高效,也就是说,我认为到目前为止我所做的并不是实现我想要的目标的特别好的方法。也就是说,我一直在努力寻找任何在线资源来记录跳转/分支/查找表,我相信这将是最有效的方法。

为了解释我想要实现的目标,我正在调用一个函数,该函数返回 dx 寄存器中的一个值,从 0 到 4。目前我正在使用 cmp 指令依次比较值,如果值相同则进行条件 je 跳转。如果我用一种更高级的语言编写此代码,我实际上会依次执行多个 if 语句,而不是使用更高效的 switch 语句。

这就是我现在正在做的事情:

cmp dx, 1          
je .F_1
cmp dx, 2
je .F_2
cmp dx, 3
je .F_3
cmp dx, 4
je .F_4
cmp dx, 0
je .F_5
jmp RangeError_Handler

.F1:
mov si, msg1
jmp F_Exit
.F2:
mov si, msg2
jmp F_Exit
... ; .F3 and .F4 follow the pattern

.F5: ; special case
mov si, msg_error
call PrintLn
hlt

F_Exit:
call PrintLn
... ; and do something else


msg1: db 'Message 1', 0
msg2: ...
...

必须有更好的方法来做到这一点。我的导师暗示跳转表是理想的,但没有时间给我任何关于它如何在汇编中工作的进一步解释,所以如果有人可以在上下文中提供某种示例,我将非常感激我的情况。

理论上,我会有一个函数检查 dx 的值,然后跳转到特定函数,而不是单独检查 5 次,我只是不知道如何在汇编中实现它。使用字符串查找表会更有效吗?即返回值 1 表示表中的字符串 1?

最佳答案

您的大多数情况都有相同的指令和不同的数据,因此您甚至不需要跳转表。只需使用一个字符串表,并且只跳转到需要运行不同指令的条件,而不是相同的指令具有不同的数据。

    mov  si, dx                   ; SI can be used in addressing modes, DX can't
shl si ; 16-bit doesn't allow scaled indices, so we can't just do [table + si*2]. And shl sets flags
cmp dx, 4
ja RangeError_Handler

mov si, [F_messages + si]
; call PrintLn could be here, if it preserves DX or SI for us to test after

test dx,dx ; detect the one special case.
jnz .F_Exit

;; fall through only in the dx==0 case
call PrintLn
RangeError_Handler:
hlt ; Are interrupts disabled? if not, execution will continue after hlt

.F_exit
call PrintLn
... ; and do whatever else your code needs to do


F_messages: # char* F_messages[]
dw msg1,
msg2
...

使用表代替条件跳转链的适用性非常广泛。如果这是 64 位 x86 代码,甚至是 ARM 或 MIPS 汇编,逻辑将几乎相同。甚至是 C。(一个好的 C 编译器可能会将您的switch 转换为数据表查找而不是跳转表)。

<小时/>

您可以将 call PrintLn 从分支的两侧分解出来,但前提是它保留 DX 或 SI。如果您必须 PUSH/POP 输入值以便能够再次测试它,那么这是不值得的。由于特殊情况是 DX==0(而不是像此答案的前一版本那样的 DX==5),我们无法使用一个 CMP 中的 FLAGS 来执行两个 JCC。

<小时/>

如果您确实想制作跳转表:

jmp  [jump_table + si]


jump_table:
dw .F_1, .F_2, ...

然后使用 DW 代替字符串地址,在内存中制作一个代码地址表。如果每个情况的大小相同(以机器代码字节为单位),您可以避免使用指针表,而只需计算相对于第一个情况的地址的跳转距离。

<小时/>

在使用绝对地址之前,请确保您了解 CS 设置的内容。普通跳转是相对的,但间接跳转/调用使用绝对地址。正如 @MichaelPetch 的评论所指出的,代码中某个时刻的 FAR JMP 将为您设置 CS。

关于程序集跳转/分支/查找表而不是大量的 cmp/je?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/39875452/

24 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com