Tag: x86

内联assembly破坏了红色区域

我正在编写一个加密程序,并且核心(一个广泛的乘法例程)是用x86-64汇编编写的,既速度又因为它广泛使用了不容易从C访问的adc指令。我不想内联这个函数,因为它很大,并且在内循环中被调用了好几次。 理想情况下,我还想为此函数定义一个自定义调用约定,因为在内部它使用所有寄存器( rsp除外),不破坏其参数,并在寄存器中返回。 现在,它适应了C调用约定,但当然这使它变慢(大约10%)。 为了避免这种情况,我可以用asm(“call %Pn” : … : my_function… : “cc”, all the registers);调用它asm(“call %Pn” : … : my_function… : “cc”, all the registers); 但有没有办法告诉GCC调用指令与堆栈混淆? 否则GCC会将所有这些寄存器放在红色区域中,而顶部的寄存器将被破坏。 我可以使用-mno-red-zone编译整个模块,但我更喜欢告诉GCC,比方说,红色区域的前8个字节将被破坏,以便它不会放任何东西。

x86上的有符号和无符号算术实现

C语言有签名和无符号类型,如char和int。 我不确定,它是如何在汇编级别实现的,例如在我看来,有符号和无符号的乘法会带来不同的结果,所以汇编是做无符号和有符号算术还是只有一个,这在某种程度上是模拟的不同的情况?

为什么整数除以-1(负一)导致FPE?

我的任务是表达一些看似奇怪的C代码行为(在x86上运行)。 我可以很容易地完成其他所有事情,但是这个让我很困惑。 代码段1输出-2147483648 int a = 0x80000000; int b = a / -1; printf(“%d\n”, b); 代码片段2不输出任何内容,并提供Floating point exception int a = 0x80000000; int b = -1; int c = a / b; printf(“%d\n”, c); 我很清楚代码片段1( 1 + ~INT_MIN == INT_MIN )的结果的原因,但我不太明白整数除法-1如何生成FPE,也不能在我的Android手机上重现它(AArch64 ,海湾合作委员会7.2.0)。 代码2只输出与代码1相同,没有任何例外。 它是x86处理器的隐藏bugfunction吗? 该任务没有告诉任何其他内容(包括CPU架构),但由于整个课程基于桌面Linux发行版,您可以放心地假设它是一个现代的x86。 编辑 :我联系了我的朋友,他在Ubuntu 16.04(Intel Kaby Lake,GCC 6.3.0)上测试了代码。 结果与所指定的任何内容一致(代码1输出所述内容,代码2与FPE崩溃)。

AVX标量操作要快得多

我测试了以下简单的function void mul(double *a, double *b) { for (int i = 0; i<N; i++) a[i] *= b[i]; } 具有非常大的数组,因此它是内存带宽限制。 我使用的测试代码如下。 当我用-O2编译时需要1.7秒。 当我用-O2 -mavx编译时,它只需要1.0秒。 非vex编码的标量操作慢了70%! 为什么是这样? 这是-O2和-O2 -mavx的程序集。 <img src="http://sofzh.miximages.com/c/otliN.png" alt=" -O2 和 -O2 -mavx 的vimddif”> https://godbolt.org/g/w4p60f 系统:i7-6700HQ@2.60GHz(Skylake)32 GB内存,Ubuntu 16.10,GCC 6.3 测试代码 //gcc -O2 -fopenmp test.c //or //gcc -O2 -mavx -fopenmp test.c #include #include #include #include […]

如何从独立环境中关闭计算机电源?

我正在制作一个基于英特尔x86架构的保护模式操作系统,并且正在寻找有关如何通过汇编代码关闭计算机电源的一些信息。 你能帮我解决这个问题吗?

使用SSE获取__m128i向量中的最大值?

我刚开始使用SSE,我很困惑如何获得__m128i的最大整数值( max )。 例如: __m128i t = _mm_setr_ps(0,1,2,3); // max(t) = 3; 搜索引导我到MAXPS指令,但我似乎无法找到如何使用”xmmintrin.h” 。 另外,您是否会建议使用”xmmintrin.h”文档,而不是查看头文件本身?

使用进位标志添加多字

GCC具有128位整数。 使用这些我可以让编译器使用mul (或只有一个操作数的imul )指令。 例如 uint64_t x,y; unsigned __in128 z = (unsigned __int128)x*y; 生产多 我用它来创建一个128×128到256的函数(在更新之前,请参阅此问题的结尾,如果您感兴趣,请参阅此代码)。 现在我想要进行256位加法,除了使用汇编之外,我还没有找到让编译器使用ADC的方法。 我可以使用汇编程序,但我想要内联函数以提高效率。 编译器已经生成了一个有效的128×128到256函数(因为我在这个问题的开头解释了)所以我不明白为什么我应该在汇编中重写它(或者编译器已经有效实现的任何其他函数) 。 这是我提出的内联汇编函数: #define ADD256(X1, X2, X3, X4, Y1, Y2, Y3, Y4) \ __asm__ __volatile__ ( \ “addq %[v1], %[u1] \n” \ “adcq %[v2], %[u2] \n” \ “adcq %[v3], %[u3] \n” \ “adcq %[v4], %[u4] \n” \ : […]

这个memcpy实现中缺少什么/次优?

我对编写memcpy()作为一种教育练习感兴趣。 我不会写一篇关于我做了什么和没想过的论文,但这里有一些人的实现 : __forceinline //因为通常Size已知,内联后编译器可以优化掉大部分无用代码void* myMemcpy(char* Dst, const char* Src, size_t Size) { void* start = Dst; for ( ; Size >= sizeof(__m256i); Size -= sizeof(__m256i) ) { __m256i ymm = _mm256_loadu_si256(((const __m256i* &)Src)++); _mm256_storeu_si256(((__m256i* &)Dst)++, ymm); } #define CPY_1B *((uint8_t * &)Dst)++ = *((const uint8_t * &)Src)++ #define CPY_2B *((uint16_t* &)Dst)++ = *((const uint16_t* […]

在不是地址/指针的值上使用LEA?

我试图理解地址计算指令是如何工作的,特别是使用leaq命令。 当我看到使用leaq进行算术运算的例子时,我感到困惑。 例如,以下C代码, long m12(long x) { return x*12; } 在组装中, leaq (%rdi, %rdi, 2), %rax salq $2, $rax 如果我的理解是正确的,leaq应该移动任何地址(%rdi, %rdi, 2) ,这应该是2*%rdi+%rdi ,评估为%rax 。 我感到困惑的是因为值x存储在%rdi ,这只是存储器地址,为什么%rdi乘以3然后左移这个存储器地址 2等于x乘以12? 是不是当我们将%rdi乘以3时,我们跳转到另一个不保持值x的内存地址?

x86的MOV真的可以“免费”吗? 为什么我不能重现这个呢?

我一直看到人们声称MOV指令可以在x86中免费,因为寄存器重命名。 对于我的生活,我无法在一个测试用例中validation这一点。 每个测试用例我尝试揭穿它。 例如,这是我用Visual C ++编译的代码: #include #include #include int main(void) { unsigned int k, l, j; clock_t tstart = clock(); for (k = 0, j = 0, l = 0; j < UINT_MAX; ++j) { ++k; k = j; // <– comment out this line to remove the MOV instruction l += j; } […]