Tag: 内联汇编

32位到64位内联汇编移植

我有一段C ++代码(在GNU / Linux环境下用g ++编译)加载一个函数指针(它是如何做的无关紧要),用一些内联汇编将一些参数压入堆栈然后调用该函数,代码如下: unsigned long stack[] = { 1, 23, 33, 43 }; /* save all the registers and the stack pointer */ unsigned long esp; asm __volatile__ ( “pusha” ); asm __volatile__ ( “mov %%esp, %0″ :”=m” (esp)); for( i = 0; i < sizeof(stack); i++ ){ unsigned long val = stack[i]; […]

如何编写内联gnu扩展程序集的短块来交换两个整数变量的值?

为了娱乐,我正在使用带有32位Linux目标的x86的AT&T语法学习gnu扩展汇编。 我花了最后三个小时编写了两个可能的解决方案来解决我交换两个整数变量a和b的值的挑战,我的解决方案都没有完全解决我的问题。 首先,让我们更详细地看一下我的TODO障碍: int main() { int a = 2, b = 1; printf(“a is %d, b is %d\n”, a, b); // TODO: swap a and b using extended assembly, and do not modify the program in any other way printf(“a is %d, b is %d\n”, a, b); } 在阅读本HOWTO之后 ,我编写了以下内联扩展汇编代码。 这是我第一次尝试交换整数: asm volatile(“movl %0, […]

使用FPU和C内联汇编

我写了一个像这样的矢量结构: struct vector { float x1, x2, x3, x4; }; 然后我创建了一个函数,它使用向量使用内联汇编执行一些操作: struct vector *adding(const struct vector v1[], const struct vector v2[], int size) { struct vector vec[size]; int i; for(i = 0; i < size; i++) { asm( "FLDL %4 \n" //v1.x1 "FADDL %8 \n" //v2.x1 "FSTL %0 \n" "FLDL %5 \n" //v1.x2 "FADDL %9 […]

告知clang内联汇编读取特定的内存区域

GCC(我可以方便地测试的所有版本)可以告诉内联汇编语句读取一个特定的内存区域(表示为指针p和大小为n ),这个结构非常难以理解: asm (“…” : : “m” (*(struct { char x[n]; } *)p)); 但是,这在clang中不起作用(3. [45]),你得到一个很难的错误: error: fields must have a constant size: ‘variable length array in structure’ extension will never be supported asm (“…” : : “m” (*(struct {char x[n];} *)p)); ^ 是否(理想情况下)是一个不同的构造,它将在两个编译器中产生相同的效果,或者(不这样)一个不同的构造,只会在clang中产生相同的效果? 请注意,在我关心的情况下,我没有插入实际的assembly说明; 构造的要点是指示编译器不要删除明显死的memset 。 因此,“不同构造”完全不能完全涉及内联组装。 但是,请建议读取任意内存或生成其他代码的构造,只有在没有其他选择的情况下。 另外,不要建议memset_s , explicit_bzero或类似的; 这是尝试在不必破解编译器的情况下实现这些函数的回退。 随后是全面的演示程序 – #include […]

GCC INLINE ASSEMBLY不会让我覆盖$ esp

我正在编写代码暂时使用我自己的堆栈进行实验。 当我使用文字内联汇编时,这很有效。 我将变量位置硬编码为ebp的偏移量。 但是,我希望我的代码可以在不使用硬编码内存地址的情况下工作,所以我一直在研究GCC的扩展内联汇编。 我所拥有的是以下内容: volatile intptr_t new_stack_ptr = (intptr_t) MY_STACK_POINTER; volatile intptr_t old_stack_ptr = 0; asm __volatile__(“movl %%esp, %0\n\t” “movl %1, %%esp” : “=r”(old_stack_ptr) /* output */ : “r”(new_stack_ptr) /* input */ ); 这一点是首先将堆栈指针保存到变量old_stack_ptr中。 接下来,堆栈指针(%esp)将被我在new_stack_ptr中保存的地址覆盖。 尽管如此,我发现GCC将%esp保存到old_stack_ptr中,但是没有用new_stack_ptr替换%esp。 经过深入检查,我发现它实际上扩展了我的程序集并添加了它自己的指令,如下所示: mov -0x14(%ebp),%eax mov %esp,%eax mov %eax,%esp mov %eax,-0x18(%ebp) 我认为GCC正试图保留%esp,因为我没有将它明确声明为“输出”操作数……我可能完全错了… 我真的很想使用扩展的内联汇编来实现这一点,因为如果没有,似乎我必须将%ebp的位置偏移“硬编码”到程序集中,我宁愿使用像这样的变量名。特别是因为这段代码需要在几个不同的系统上运行,这些系统似乎都以不同的方式抵消了我的变量,因此使用扩展的内联汇编可以让我明确地说出变量位置……但是我不明白它为什么会这样做额外的东西,不要让我像以前一样覆盖堆栈指针,自从我开始使用扩展程序集以来,它一直在这样做。 我感谢任何帮助!

C / C ++中的简单“Hello World”内联汇编语言程序

我用devcpp和borland c编译器…. asm { mov ax,4 // (I/O Func.) mov bx,1 // (Output func) mov cx,&name // (address of the string) mov dx,6 // (length of the string) int 0x21 // system call } 在上面的代码片段中,我想在汇编语言的帮助下打印一个字符串…但是如何将字符串的地址放在寄存器cx …. 代码中有什么问题???

如何制作一个可以运行x86hex代码的C程序

我有一个hex代码数组转换成汇编指令,我想在C中创建可以执行这些的程序。 unsigned char rawData[5356] = { 0x4C, 0x01, 0x0A, 0x00, 0x00, 0x00, 0x00, 0x00, 0x64, 0x0C, 0x00, 0x00, 0x3D, 0x00, 0x00, 0x00, 0x00, 0x00, 0x04, 0x01, 0x2E, 0x74, 0x65, 0x78, 0x74, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xB4, 0x05, 0x00, 0x00, 0xA4, 0x01, 0x00, 0x00, 0x68, 0x08, 0x00, 0x00, 0x00, […]

gcc删除内联汇编程序代码

似乎gcc 4.6.2删除了它认为从函数中未使用的代码。 test.c的 int main(void) { goto exit; handler: __asm__ __volatile__(“jmp 0x0”); exit: return 0; } main()拆卸 0x08048404 : push ebp 0x08048405 : mov ebp,esp 0x08048407 : nop # <– This is all whats left of my jmp. 0x08048408 : mov eax,0x0 0x0804840d : pop ebp 0x0804840e : ret 编译器选项 没有启用优化,只有gcc -m32 -o test test.c […]

使用GCC的内联汇编直接调用

如果要从内联汇编调用C / C ++函数,可以执行以下操作: void callee() {} void caller() { asm(“call *%0” : : “r”(callee)); } 然后GCC将发出如下所示的代码: movl $callee, %eax call *%eax 这可能会有问题,因为间接调用会破坏旧CPU上的管道。 由于callee的地址最终是常量,因此可以想象可以使用i约束。 引自GCC在线文档 : ‘我” 允许立即整数操作数(具有常量值的操作数)。 这包括符号常量,其值仅在汇编时或以后知道。 如果我尝试像这样使用它: asm(“call %0” : : “i”(callee)); 我从汇编程序中收到以下错误: 错误:后缀或操作数对`call’无效 这是因为GCC会发出代码 call $callee 代替 call callee 所以我的问题是是否可以使GCC输出正确的call 。

如何在GCC x86内联汇编中使用地址常量

GCC工具链默认使用AT&T汇编语法,但可通过.intel_syntax指令获得对Intel语法的支持。 此外,AT&T和Intel语法都有prefix和noprefix版本,不同之处在于它们是否需要使用% sigil为寄存器名称添加前缀。 根据存在的指令,地址常量的格式会发生变化。 我们考虑以下C代码 *(int *)0xdeadbeef = 0x1234; 使用objdump -d ,我们发现它被编译为以下汇编程序指令 movl $0x1234,0xdeadbeef 由于没有涉及寄存器,这是.att_syntax prefix和.att_syntax noprefix的正确语法,即。 嵌入在C代码中,它们看起来像这样 __asm__(“.att_syntax prefix”); __asm__(“movl $0x1234,0xdeadbeef”); __asm__(“.att_syntax noprefix”); __asm__(“movl $0x1234,0xdeadbeef”); 您可以选择用括号括起地址常量,即。 __asm__(“movl $0x1234,(0xdeadbeef)”); 也会奏效。 将sigil添加到普通地址常量时,代码将无法复制 __asm__(“movl $0x1234,$0xdeadbeef”); // won’t compile 当用paranthesis围绕这个表达式时,编译器会在没有警告的情况下发出错误的代码,即 __asm__(“movl $0x1234,($0xdeadbeef)”); // doesn’t warn, but doesn’t work! 这将错误地发出指令 movl $0x1234,0x0 在Intel模式下,如果可能存在歧义,则地址常量必须以段寄存器为前缀,并且必须以操作数大小和PTR标志为前缀。 在我的机器上(采用Windows XP和当前MinGW和Cygwin GCC版本的英特尔双核笔记本电脑),默认情况下使用寄存器ds 。 常量周围的方括号是可选的。 如果省略段寄存器但是括号存在,则也可以正确识别地址常量。 […]