将flags寄存器用作布尔返回值被认为是不好的做法吗?

Tra*_*rap 5 x86 assembly coding-style

我正在x86汇编程序中编写一些程序来修改ZF作为返回布尔值的方法,所以我可以这样做:

call is_value_correct
jz not_correct
Run Code Online (Sandbox Code Playgroud)

我想知道这是否被认为是不好的做法,因为一些编码标准说应该在AX寄存器中返回简单的值.

Pet*_*des 8

是的,如果它使您的代码运行更快和/或整体更小,那就去做吧.

手动编写asm的一个优点是能够使用自定义调用约定函数,即使它们不是私有辅助函数或宏.这包括能够在不同的寄存器中"返回"多个值,并基本上做任何你想做的事情.

与任何自定义调用约定一样,您需要做的就是用注释记录它.下面是一个如何编写此类注释的示例,其中包含特定且有意的非标准事物.

# inputs:   foo in EAX (zero-extended into RAX), bar in EDI
# pre-requisites: DF=0
# clobbers: RCX, RDX, AL (but not the rest of EAX)
# returns:  AL = something,  ZF = something else
my_func:
   ...
   setc al
   ...
   something that sets ZF
   ret
Run Code Online (Sandbox Code Playgroud)

如果你愿意为了风格或可读性而牺牲效率,你可能不应该在2018年首次编写asm,因为编译器大多数时候都能生成好的asm,你很少需要编写自己的启动部门或其他什么.(即性能是手写asm的主要用例,只有你全力以赴才能获得性能.)

是的,手写的asm可能成为一个难以理解/不可维护的混乱,但如果它具有合理的语义含义,那么这种优化不会使你的代码变得混乱.


甚至有这样的先例:x86-64 OS X系统调用使用CF作为错误/无错误状态,与rax返回值分开.与Linux不同的是,RAX从-4095到-1指示错误,但是它们使用相同的x86-64 System V ABI /调用约定.

一些DOS int 0x21系统调用和PC BIOS int 0x10功能具有类似的标志返回系统.它允许调用程序分支出错,因此它可以节省代码大小(测试或cmp)并避免需要带内错误信号.

  • @PSkocik:那会很有趣。许多函数需要“add”或“sub”来清理堆栈帧,但它们可以 LEA。或者将实际的标志设置操作推迟到运行析构函数之后返回之前。但最大的问题是:你会选择哪面旗帜?CF 是显而易见的选择(因为它有特殊的指令来使用它,例如 `adc` / `sbb`),并且一些特殊的指令设置它(`bt` / `bts` 等,`rdrand`)。但是,如果您的“_Bool”来自 ZF,来自“bsr”或“bsr”等指令或“==”比较,或 SF + OF 带符号比较,则您可能会出现这种情况。需要 sete/le + cmp。 (3认同)
  • 我想知道为什么 ABI 不通过设置标志来返回“_Bool”。对我来说,使用寄存器来返回“_Bool”似乎是一种浪费。 (2认同)