Tag: x86 64

在C或C ++链接器中是否有任何类型检查?

我正确地说连接器没有进行function参数检查。 它们不检查函数调用的数量或类型,也不检查全局数据引用的类型。 这对所有连接体都是如此吗? 我在x86-64上使用Clang定位Linux。 链接器是否检查引用是否在正确的段中? 或者就链接器而言,外部引用实际上只是一个void *? 我来自高级语言背景C#和Scala,所以对于那些沉浸在低级别世界中的人来说,这似乎是显而易见的。 我在汇编程序中写了几个函数(系统调用),我注意到汇编程序中没有外部函数的参数原型。 上下文:我实际上是在编写一个编译器。 目前我的目标是使用汇编程序函数进行系统调用的预处理C .i文件,但替代方案是C ++,汇编程序甚至机器代码,所以我试图权衡成本和收益,特别是类型检查,汇编器/编译器/ 链接器我可以用来检查我自己的程序及其函数原型生成的正确性。

在C中使用内联汇编进行位奇偶校验?

我正在尝试计算大量uint64的位奇偶校验 。 比特奇偶校验是指接受uint64的函数,如果设置的比特数是偶数则输出0,否则为1。 目前我正在使用以下function(@Troyseph,在这里找到): uint parity64(uint64 n){ n ^= n >> 1; n ^= n >> 2; n = (n & 0x1111111111111111) * 0x1111111111111111; return (n >> 60) & 1; } 相同的SO页面具有以下汇编例程(由@papadp提供): .code ; bool CheckParity(size_t Result) CheckParity PROC mov rax, 0 add rcx, 0 jnp jmp_over mov rax, 1 jmp_over: ret CheckParity ENDP END […]

为什么printf使用float和integer格式说明符打印随机值

我在64位机器上写了一个简单的代码 int main() { printf(“%d”, 2.443); } 所以,这就是编译器的行为方式。 它将识别第二个参数为double,因此它将在堆栈上推送8个字节,或者可能只是在调用之间使用寄存器来访问变量。 %d需要一个4字节的整数值,因此它会输出一些垃圾值。 有趣的是,每次执行此程序时,打印的值都会发生变化。 那么发生了什么? 我希望它每次打印相同的垃圾值,而不是每次都不同。

如何在x86-64上优化C和C ++中的函数返回值?

x86-64 ABI指定两个返回寄存器: rax和rdx ,大小均为64位(8字节)。 假设x86-64是唯一的目标平台,这两个function中的哪一个: uint64_t f(uint64_t * const secondReturnValue) { /* Calculate a and b. */ *secondReturnValue = b; return a; } std::pair g() { /* Calculate a and b, same as in f() above. */ return { a, b }; } 考虑到针对x86-64的C / C ++编译器的当前状态,会产生更好的性能吗? 使用一个版本或其他版本在性能方面是否有任何陷阱? 编译器(GCC,Clang)总是能够优化在rax和rdx返回的std::pair吗? 更新:通常,如果编译器优化了std::pair方法(使用GCC 5.3.0和Clang 3.8.0的二进制输出示例),则返回一对更快。 如果没有内联f() ,编译器必须生成代码以将值写入内存,例如: movq […]

Python ctypes和函数调用

我的朋友制作了一个适用于x86的小型概念validation汇编程序。 我决定将它移植到x86_64,但我立即遇到了问题。 我在C中编写了一小段程序,然后编译并objdumped代码。 之后我将它插入到我的python脚本中,因此x86_64代码是正确的: from ctypes import cast, CFUNCTYPE, c_char_p, c_long buffer = ”.join(map(chr, [ #0000000000000000 : 0x55, # push %rbp 0x48, 0x89, 0xe5, # mov %rsp,%rbp 0x48, 0x89, 0x7d, 0xf8, # mov %rdi,-0x8(%rbp) 0x48, 0x8b, 0x45, 0xf8, # mov -0x8(%rbp),%rax 0x48, 0x83, 0xc0, 0x0a, # add $0xa,%rax 0xc9, # leaveq 0xc3, # retq ])) […]

如何让`gcc`从标准C生成x86-64的`bts`指令?

受最近一个问题的启发,我想知道是否有人知道如何让gcc在Linux x86-64平台上生成x86-64 bts指令(位测试和设置), 而无需求助于内联汇编或非标准编译器内部函数。 相关问题: 为什么gcc没有为简单的|=操作执行此操作,右侧是否正好设置了1位? 如何使用编译器内在函数或asm指令获取bts 可移植性对我来说比bts更重要,所以我不会使用和asm指令,如果有另一个解决方案,我宁愿不使用编译器instrinsics。 编辑 :C源语言不支持primefaces操作,所以我对获得primefaces测试和设置并不特别感兴趣(尽管这是测试和设置首先存在的原始原因)。 如果我想要一些primefaces,我知道我没有机会使用标准C源:它必须是内在的,库函数或内联汇编。 (我在支持multithreading的编译器中实现了primefaces操作。)

基于CPU周期计算的C / C ++ Linux x86_64中的分析

我正在使用以下代码来分析我的操作,以优化我的函数中的cpu周期。 static __inline__ unsigned long GetCC(void) { unsigned a, d; asm volatile(“rdtsc” : “=a” (a), “=d” (d)); return ((unsigned long)a) | (((unsigned long)d) << 32); } 我不认为这是最好的,因为即使连续两次通话也给我带来“33”的差异。 有什么建议 ?

为什么编译器在编译的汇编代码中生成额外的sqrts

我正在尝试使用以下简单的C代码来分析计算sqrt所需的时间,其中readTSC()是一个读取CPU循环计数器的函数。 double sum = 0.0; int i; tm = readTSC(); for ( i = 0; i < n; i++ ) sum += sqrt((double) i); tm = readTSC() – tm; printf("%lld clocks in total\n",tm); printf("%15.6e\n",sum); 但是,当我使用打印出汇编代码时 gcc -S timing.c -o timing.s 在英特尔机器上,结果(如下所示)令人惊讶? 为什么汇编代码中有两个sqrts,一个使用sqrtsd指令而另一个使用函数调用? 它是否与循环展开和尝试在一次迭代中执行两个sqrts相关? 以及如何理解这条线 ucomisd %xmm0, %xmm0 为什么将%xmm0与自身进行比较? //—————-start of for loop—————- call readTSC movq […]

SSE指令MOVSD(扩展:x86上的浮点标量和向量运算,x86-64)

我莫名其妙地被MOVSD汇编指令搞糊涂了。 我写了一些计算一些矩阵乘法的数字代码,简单地使用没有SSE内在函数的普通C代码。 我甚至没有包含用于编译的SSE2内在函数的头文件。 但是当我检查汇编器输出时,我看到: 1)使用128位向量寄存器XMM; 2)调用SSE2指令MOVSD。 我知道MOVSD基本上是在单双精度浮点上运行。 它只使用XMM寄存器的低64位并设置高64位0.但我只是不明白两件事: 1)我从不给编译器任何使用SSE2的提示。 另外,我使用GCC而不是英特尔编译器。 据我所知,intel编译器会自动寻找矢量化的机会,但GCC不会。 那么GCC如何知道使用MOVSD? 或者,这个x86指令是否早在SSE指令集之前就已存在,而SSE2中的_mm_load_sd()内在函数只是为了提供向后兼容性来使用XMM寄存器进行标量计算? 2)为什么编译器不使用其他浮点寄存器,无论是80位浮点堆栈还是64位浮点寄存器? 为什么必须使用XMM寄存器(通过设置高64位0并基本上浪费该存储)来收费? XMM是否提供更快的访问? 顺便说一句,我有另外一个关于SSE2的问题。 我只是看不到_mm_store_sd()和_mm_storel_sd()之间的区别。 两者都将较低的64位值存储到地址。 有什么不同? 性能差异?? 对齐差异?? 谢谢。 更新1: 好的,显然当我第一次提出这个问题时,我缺乏一些关于CPU如何管理浮点运算的基本知识。 所以专家倾向于认为我的问题是无意义的。 由于我没有包括最短的样本C代码,人们可能会认为这个问题也很模糊。 在这里,我将提供一个回答作为答案,希望对任何不清楚现代CPU上的浮点运算的人都有用。

C unsigned long long和imulq

作为一个刚接触组装的人,我使用gcc进行逆向工程。 但是现在我遇到了一个有趣的问题:我尝试将两个64位整数乘以x86-64。 C代码如下: unsigned long long val(unsigned long long a, unsigned long long b){ return a*b; } 并使用gcc编译: val: movq %rdi, %rax imulq %rsi, %rax ret 将有符号乘法用于无符号整数可能违反直觉,但它适用于C. 但是,我想检查溢出的乘法。 现在,如果结果大于2^63-1则设置溢出标志(我猜是因为它毕竟是带符号的乘法)。 但是对于无符号64位,只要结果不大于2^64-1这仍然可以。 在这种情况下,进行乘法(在assembly中)的正确方法是什么?