未定义的行为是否适用于 asm 代码?
Does undefined behavior apply to asm code?
假设您知道您的 software 只会 运行 在二进制补码机器上,其中已很好地定义了带符号的溢出行为。有符号溢出在 C 和 C++ 中仍然是未定义的行为,编译器可以自由地用 "ret" 替换你的整个程序,启动核 war,格式化你的驱动器,或者让恶魔从你的鼻子里飞出来。
假设您在内联 asm 中有签名溢出,您的程序是否仍会调用 UB?
如果是,那么单独编译和链接的汇编程序呢?
“未定义的行为”是指 C 语言。 C++ 标准不定义程序的行为。如果您的程序包含内联汇编,那么很明显,它的行为通常不会由 C 或 C++ 标准描述。一些其他标准甚至可能定义了行为,但这在 C 或 C++ 标准的上下文中仍然不意味着“定义的行为”。
也就是说,C 标准确实需要支持扩展的文档。如果您的程序的行为可以从您的实现文档中推断出来,并且您的实现使您的程序表现不同,那么您的实现不符合标准:
4. Conformance
8 An implementation shall be accompanied by a document that defines all implementation-defined and locale-specific characteristics and all extensions.
对于 C++,此要求已被削弱:
1.4 Implementation compliance [intro.compliance]
9 Each implementation shall include documentation that identifies all conditionally-supported constructs that it does not support and defines all locale-specific characteristics.
和
1.9 Program execution [intro.execution]
2 Certain aspects and operations of the abstract machine are described in this International Standard as implementation-defined [...] Each implementation shall include documentation describing its characteristics and behavior in these respects. [...]
我找不到对扩展进行记录的要求,如果记录了,则正确记录。这表明在 C++ 中,即使您的实现将程序的行为定义为扩展,如果发现文档是错误的,那就太糟糕了。
对于 C++ 半标准 asm
语句(如评论中所述,“asm
声明是有条件支持的;其含义是实现定义的。”),如果您的实现支持它需要记录下来,但是当然,实现以不同于 C++ 标准暗示的方式支持内联汇编是常见的做法,所以这不会给你太多额外的东西。
一旦你说你已经签署了内联汇编中的溢出,这意味着你在谈论一个特定的编译器(或一组编译器),因为在 C 和 C++ 中对 asm 声明的支持及其含义编译器定义。
如果编译器通过允许在其输出中直接包含汇编代码来定义 asm 关键字,并且如果机器允许有符号溢出,那么内联 asm 中的有符号溢出是为该编译器完美定义的并且那台机器:这是处理器将给出的结果。您仍然应该控制它是否会导致有符号整数的陷阱表示,但无论如何它是 defined。唯一以 UB 结尾的情况是编译器说某些有符号整数表示将导致未定义的行为。但我知道 none 确实如此,而且您已经处于定义的有限编译器和机器集的上下文中。
单独编译汇编模块和 C and/or C++ 代码对于那组编译器和机器来说是相同的:结果是 实现定义 这不是与 UB 相同。
标准(C 和 C++)中明确定义的另一个例子是 char
类型是否有符号:如果你不知道你使用的是什么编译器,你不能依赖它,但是一旦你选择了一个编译器实现,这个实现就需要说明它是有符号的还是无符号的,而且它是不是未定义的行为,这意味着编译器无法用 ret 替换完整代码。
假设您知道您的 software 只会 运行 在二进制补码机器上,其中已很好地定义了带符号的溢出行为。有符号溢出在 C 和 C++ 中仍然是未定义的行为,编译器可以自由地用 "ret" 替换你的整个程序,启动核 war,格式化你的驱动器,或者让恶魔从你的鼻子里飞出来。
假设您在内联 asm 中有签名溢出,您的程序是否仍会调用 UB?
如果是,那么单独编译和链接的汇编程序呢?
“未定义的行为”是指 C 语言。 C++ 标准不定义程序的行为。如果您的程序包含内联汇编,那么很明显,它的行为通常不会由 C 或 C++ 标准描述。一些其他标准甚至可能定义了行为,但这在 C 或 C++ 标准的上下文中仍然不意味着“定义的行为”。
也就是说,C 标准确实需要支持扩展的文档。如果您的程序的行为可以从您的实现文档中推断出来,并且您的实现使您的程序表现不同,那么您的实现不符合标准:
4. Conformance
8 An implementation shall be accompanied by a document that defines all implementation-defined and locale-specific characteristics and all extensions.
对于 C++,此要求已被削弱:
1.4 Implementation compliance [intro.compliance]
9 Each implementation shall include documentation that identifies all conditionally-supported constructs that it does not support and defines all locale-specific characteristics.
和
1.9 Program execution [intro.execution]
2 Certain aspects and operations of the abstract machine are described in this International Standard as implementation-defined [...] Each implementation shall include documentation describing its characteristics and behavior in these respects. [...]
我找不到对扩展进行记录的要求,如果记录了,则正确记录。这表明在 C++ 中,即使您的实现将程序的行为定义为扩展,如果发现文档是错误的,那就太糟糕了。
对于 C++ 半标准 asm
语句(如评论中所述,“asm
声明是有条件支持的;其含义是实现定义的。”),如果您的实现支持它需要记录下来,但是当然,实现以不同于 C++ 标准暗示的方式支持内联汇编是常见的做法,所以这不会给你太多额外的东西。
一旦你说你已经签署了内联汇编中的溢出,这意味着你在谈论一个特定的编译器(或一组编译器),因为在 C 和 C++ 中对 asm 声明的支持及其含义编译器定义。
如果编译器通过允许在其输出中直接包含汇编代码来定义 asm 关键字,并且如果机器允许有符号溢出,那么内联 asm 中的有符号溢出是为该编译器完美定义的并且那台机器:这是处理器将给出的结果。您仍然应该控制它是否会导致有符号整数的陷阱表示,但无论如何它是 defined。唯一以 UB 结尾的情况是编译器说某些有符号整数表示将导致未定义的行为。但我知道 none 确实如此,而且您已经处于定义的有限编译器和机器集的上下文中。
单独编译汇编模块和 C and/or C++ 代码对于那组编译器和机器来说是相同的:结果是 实现定义 这不是与 UB 相同。
标准(C 和 C++)中明确定义的另一个例子是 char
类型是否有符号:如果你不知道你使用的是什么编译器,你不能依赖它,但是一旦你选择了一个编译器实现,这个实现就需要说明它是有符号的还是无符号的,而且它是不是未定义的行为,这意味着编译器无法用 ret 替换完整代码。