Tag: assembly

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 ])) […]

为什么编译器在编译的汇编代码中生成额外的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 […]

“C变量类型的大小取决于机器。”这是真的吗? 已签名和未签名的号码;

我被告知C类型取决于机器。 今天我想validation它。 void legacyTypes() { /* character types */ char k_char = ‘a’; //Signedness –> signed & unsigned signed char k_char_s = ‘a’; unsigned char k_char_u = ‘a’; /* integer types */ int k_int = 1; /* Same as “signed int” */ //Signedness –> signed & unsigned signed int k_int_s = -2; unsigned int k_int_u […]

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上的浮点运算的人都有用。

如何在Windows上的64位应用程序运行时在程序集中设置函数参数?

我试图使用generics函数中使用的汇编代码设置参数。 这个generics函数的参数 – 驻留在dll中 – 在编译期间是未知的。 在运行期间,使用GetProcAddress函数确定指向此函数的指针。 然而,其论点尚不清楚。 在运行时,我可以使用数据文件(不是头文件或任何可以包含或编译的内容)来确定参数 – 值和类型。 我找到了一个很好的例子,说明如何解决32位的这个问题( C Pass参数作为从LoadLibrary()导入函数的void-pointer-list ),但对于64位这个例子不起作用,因为你无法填充堆栈但你必须填写登记册。 所以我尝试使用汇编代码填充寄存器,但直到现在都没有成功。 我使用C代码来调用汇编代码。 我使用VS2015和MASM(64位)。 下面的C代码工作正常,但汇编代码没有。 那么汇编代码出了什么问题呢? 提前致谢。 C代码: … void fill_register_xmm0(double); // proto of assembly function … // code determining the pointer to a func returned by the GetProcAddress() … double dVal = 12.0; int v; fill_register_xmm0(dVal); v = func->func_i(); // […]

为什么将char传递给函数会改变它在c中的值?

我目前正在关注构建操作系统的这本工作簿 。 我的目的是编写一个64位内核。 在文本模式下,我已经加载了“内核”代码并将单个字符写入帧缓冲区。 当我通过将代码包装在函数中来添加一个间接级别来将单个字符写入帧缓冲区时,我的问题出现了。 看来传递给函数的char值在某种程度上被破坏了。 我有三个文件: bootloader.asm ; bootloader.asm [org 0x7c00] KERNEL_OFFSET equ 0x1000 mov bp, 0x9000 mov sp, bp ; load the kernel from boot disk mov bx, KERNEL_OFFSET mov dl, dl ; boot drive is set to dl mov ah, 0x02 ; bios read sector mov al, 15 ; read 15 sectors […]

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中)的正确方法是什么?

具有Core 2 CPU(SSSE3)的大缓冲区的位popcount

我正在寻找在512或更多字节的大缓冲区上popcount的最快方法。 我可以保证任何所需的对齐,缓冲区大小始终是2的幂。缓冲区对应于块分配,因此通常位是全部设置,没有设置,或者大多数设置有利于缓冲区的“左”,偶尔出洞。 我考虑过的一些解决方案是: 海湾合作委员会的__builtin_popcount Bitslice popcount_24words 计算位数,Brian Kernighan的方式 我对最快的解决方案感兴趣,它必须适用于属于core2或更新版本的32位x86芯片组。 SSE和SIMD引起了极大的兴趣。 我将在以下四核CPU上进行测试: matt@stanley:~/anacrolix/public/stackoverflow$ cat /proc/cpuinfo processor : 0 vendor_id : GenuineIntel cpu family : 6 model : 15 model name : Intel(R) Core(TM)2 Quad CPU Q6600 @ 2.40GHz stepping : 11 cpu MHz : 1600.000 cache size : 4096 KB physical id : 0 siblings : […]

英特尔的时间戳读取asm代码示例是否使用了两个以上的寄存器?

我正在研究使用x86 CPU中的时间戳寄存器(TSR)来测量基准性能。 它是一个有用的寄存器,因为它以单调时间单位测量,不受时钟速度变化的影响。 很酷。 这是一份英特尔文档,显示了使用TSR进行可靠基准测试的asm片段,包括使用cpuid进行管道同步。 见第16页: http://www.intel.com/content/www/us/en/embedded/training/ia-32-ia-64-benchmark-code-execution-paper.html 要读取开始时间,它说(我注释了一下): __asm volatile ( “cpuid\n\t” // writes e[abcd]x “rdtsc\n\t” // writes edx, eax “mov %%edx, %0\n\t” “mov %%eax, %1\n\t” // :”=r” (cycles_high), “=r” (cycles_low) // outputs : // inputs :”%rax”, “%rbx”, “%rcx”, “%rdx”); // clobber 我想知道为什么使用临时寄存器来获取edx和eax的值。 为什么不删除mov并从edx和eax读取TSR值? 像这样: __asm volatile( “cpuid\n\t” “rdtsc\n\t” // : “=d” (cycles_high), “=a” (cycles_low) […]

从C执行二进制机器代码

按照这个说明,我设法只产生528字节的大小a.out(当gcc main.c最初给我8539字节的大文件时)。 main.c是: int main(int argc, char** argv) { return 42; } 但我已经从这个汇编文件中构建了一个a.out: 电源: ; tiny.asm BITS 64 GLOBAL _start SECTION .text _start: mov eax, 1 mov ebx, 42 int 0x80 有: me@comp# nasm -f elf64 tiny.s me@comp# gcc -Wall -s -nostartfiles -nostdlib tiny.o me@comp# ./a.out ; echo $? 42 me@comp# wc -c a.out 528 […]