【发布时间】:2019-02-25 17:53:24
【问题描述】:
我正在尝试编写一些代码,以了解更多关于汇编和 JIT 编译器之类的知识。到目前为止,我已经能够提出一个 XOR 函数,理论上它应该可以在 Windows 和 Linux 环境中的 x86 或 x64 机器上工作。
假设我理解正确,[RE]AX 寄存器用于保存整数返回值,而[RE]DX 是用于在函数之间传递整数的可用寄存器之一。我选择不严格遵循 ABI 并使用 [RE]AX 传递第一个参数,因为它保存了 MOV 指令而不影响结果。
是否有更好(更优雅或更高效)的方式来生成跨平台程序集,或者我在开发此程序时是否犯了任何错误?
#include <cstdint>
#include <iostream>
template<typename TInput>
static auto Xor(TInput const highPart, TInput const lowPart) {
constexpr bool is16Bit = (std::is_same<TInput, int16_t>::value || std::is_same<TInput, uint16_t>::value);
constexpr bool is32Bit = (std::is_same<TInput, int32_t>::value || std::is_same<TInput, uint32_t>::value);
static_assert(is16Bit || is32Bit, "type must be a member of the type family: [u]int{16, 32}_t");
if constexpr (is16Bit) {
uint16_t result;
#if (defined(__linux__) || defined(__unix__) || defined(_WIN32))
asm volatile ("xorw %%dx, %%ax;" : "=a" (result) : "a" (highPart), "d" (lowPart));
#else
#error "Unsupported platform detected."
#endif
return result;
}
else if constexpr (is32Bit) {
uint32_t result;
#if (defined(__linux__) || defined(__unix__) || defined(_WIN32))
asm volatile ("xorl %%edx, %%eax;" : "=a" (result) : "a" (highPart), "d" (lowPart));
#else
#error "Unsupported platform detected."
#endif
return result;
}
}
#define HIGH_PART 4;
#define LOW_PART 8;
int main() {
int16_t const a = HIGH_PART;
int16_t const b = LOW_PART;
int16_t const c = Xor(a, b);
uint32_t const x = HIGH_PART;
uint32_t const y = LOW_PART;
uint32_t const z = Xor(x, y);
std::cout << c << "\n";
std::cout << z << "\n";
getchar();
return 0;
}
以下是如何改进的示例;通过“提升”result 变量和if defined(...) 检查在constexpr 检查之上,我们可以使事情更通用。
template<typename T>
static auto Xor(T const highPart, T const lowPart) {
constexpr bool is16Bit = (std::is_same<T, int16_t>::value || std::is_same<T, uint16_t>::value);
constexpr bool is32Bit = (std::is_same<T, int32_t>::value || std::is_same<T, uint32_t>::value);
static_assert(is16Bit || is32Bit, "type must be a member of the type family: [u]int{16, 32}_t");
#if !(defined(__linux__) || defined(__unix__) || defined(_WIN32))
#error "Unsupported platform detected."
#endif
T result;
if constexpr (is16Bit) {
asm volatile ("xorw %%dx, %%ax;" : "=a" (result) : "a" (highPart), "d" (lowPart));
}
else if constexpr (is32Bit) {
asm volatile ("xorl %%edx, %%eax;" : "=a" (result) : "a" (highPart), "d" (lowPart));
}
return result;
}
【问题讨论】:
-
int16_t c = a^b;和 gcc 用于目标平台。我的意思是我不确定你在问什么:a)在处理算术的原始机器代码中,win / linux之间没有区别,那是在ABI和服务调用中(这里无关)b)不清楚64b在哪里进入这个以及如何,到目前为止,Q.c)xorw的编码方式因当前 CPU 模式(16b 模式与 32b/64b 模式)不同而不同,我认为没有明智的方法可以同时满足这两种模式......尝试同时满足 32 和 64 目标平台时会出现类似问题,那么您的目标是什么? -
@Ped7g 使用哪些寄存器的机器没有区别,但如果我希望我生成的程序“与其他人一起玩”,那么我应该坚持目标平台的 ABI,不?这里的目标是最终发出机器代码,而不是使用 GCC 编译 XOR 表达式。标题中列出了我的潜在目标:x64、x86、Linux 和 Windows。
-
@Ped7g 正如第一句话所述,我正在获得知识和理解;不是试图击败现代编译器(还没有!),只是想体验他们处理的所有不同的复杂性。
-
我也不确定那些 if 16b else if 32b ...为什么不简单地定义两个具有适当参数类型的函数并让编译器根据使用的类型选择正确的一个...在现代 x86 世界中,即使使用 16b 值,执行
xorl也更有意义(从性能的角度来看),这取决于它们的来源以及将它们读入寄存器的方式以及在xor之后如何继续计算。 .. 但在现代 x86 中,每个单个操作编译的整个概念没有多大意义,这将带来整体解决方案的解释器级性能。 -
对不起,我离开这里,我不明白你的问题..也许其他人会更好地理解你。 :)
标签: c++ gcc assembly cross-platform abi