未定义的行为是否适用于asm代码?

假设您知道您的软件只能在两个补码机器上运行,其中已经很好地定义了带符号的溢出行为。 签名溢出仍然是C和C ++中未定义的行为,编译器可以自由地用“ret”替换你的整个程序,开始核战争,格式化你的驱动器,或让恶魔飞出你的鼻子。

假设您已在内联asm中签名溢出,您的程序是否仍然调用UB?

如果是,那么单独编译和链接汇编程序呢?

“未定义的行为”是指C和。 C ++标准没有定义程序的行为。 如果你的程序包含内联汇编,那么很明显它的行为通常不会被C或C ++标准描述。 其他一些标准甚至可能定义行为,但这仍然不代表C或C ++标准上下文中的“定义行为”。

也就是说,C标准确实需要支持扩展的文档。 如果您的程序的行为可以从您的实现文档中推断出来,并且您的实现使您的程序行为不同,那么您的实现将无法符合标准:

4.一致性

8实现应附带一个文档,该文档定义所有实现定义的和特定于语言环境的特征以及所有扩展。

对于C ++,此要求已被削弱:

1.4实施合规[intro.compliance]

9每个实现都应包括标识其不支持的所有条件支持的构造的文档,并定义所有特定于语言环境的特征。

1.9程序执行[intro.execution]

2抽象机的某些方面和操作在本国际标准中描述为实施定义[…]每个实施应包括描述其在这些方面的特征和行为的文件。 […]

我无法找到要记录扩展的要求,如果记录在案,则需要正确记录。 这表明在C ++中,即使你的实现将程序的行为定义为扩展,如果事实certificate文档是错误的,那就太糟糕了。

对于C ++半标准asm语句(如评论中所述,“ asm声明是有条件支持的;其含义是实现定义的。”),如果您的实现支持它,则需要记录,但当然这是常见的实现以不同于C ++标准暗示的方式支持内联汇编的实现,因此这不会给你额外的帮助。

一旦你说你在内联asm中签名溢出,就意味着你说的是一个特定的编译器(或一组编译器),因为在C和C ++中,对asm声明及其含义的支持是编译器定义的

如果编译器通过允许在其输出中直接包含汇编代码来定义asm关键字,并且如果机器允许有符号溢出,则内联asm中的有符号溢出完全定义为该编译器和该机器 :它是处理器将给出的内容结果。 您仍然应该控制它是否可以导致有符号整数的陷阱表示,但无论如何它都已定义 。 在UB中结束的唯一情况是编译器表示有符号整数中的某些表示将导致未定义的行为。 但我知道没有这样做,而且你已经处于一组定义的有限的编译器和机器的环境中。

对于那组编译器和机器,汇编模块和C和/或C ++代码的单独编译将是相同的:结果是实现定义的 ,与UB不同。

标准(C和C ++)中定义的明确实现的另一个例子是char类型是否被签名:如果你不知道你使用什么编译器,你不能依赖它,但是一旦你选择了编译器实现 ,该实现需要说明它是有符号还是无符号,并且它不是未定义的行为,这意味着编译器不能用ret替换完整代码。