Ada*_*icz 2 x86 gcc gnu-assembler inline-assembly
我正在尝试用gcc汇编程序扩展做一个非常简单的事情:
在编译我的解决方案时:
#include <stdio.h>
#define inf_int volatile unsigned long long
int main(int argc, char *argv[]){
inf_int zero = 0;
inf_int one = 1;
inf_int infinity = ~0;
printf("value of zero, one, infinity = %llu, %llu, %llu\n", zero, one, infinity);
__asm__ volatile (
"addq $1, %0"
: "=r" (infinity)
);
__asm__ volatile (
"addq $1, %0"
: "=r" (zero)
);
__asm__ volatile (
"addq $1, %0"
: "=r" (one)
);
printf("value of zero, one, infinity = %llu, %llu, %llu\n", zero, one, infinity);
return 0;
}
Run Code Online (Sandbox Code Playgroud)
使用以下开关:
gcc -std=c99 --pedantic -Wall -c main.c -o main.o
gcc -std=c99 --pedantic -Wall main.o -o main
Run Code Online (Sandbox Code Playgroud)
我希望运行以下结果main:
值为零,一,无穷大= 0,1,18446744073709551615
值为零,一,无穷大= 1,2,0
但我得到的结果是这样的:
值为零,一,无穷大= 0,1,18446744073709551615
值为零,一,无穷大= 60,61,59
有趣的是,如果我向第一个添加一个字符,printf我会得到以下内容,逐个输出:
zerao的值,1,无穷大= 0,1,18446744073709551615
值为零,一,无穷大= 61,62,60
更有趣的是,我可以通过添加(可选)输出寄存器来修复行为.但是这会因为使用2个以上的寄存器而浪费,并且无法理解为什么前一个部分表现出未定义的行为.
#include <stdio.h>
#define inf_int volatile unsigned long long
int main(int argc, char *argv[]){
inf_int zero = 0;
inf_int one = 1;
inf_int infinity = ~0;
printf("value of zerao, one, infinity = %llu, %llu, %llu\n", zero, one, infinity);
__asm__ volatile (
"addq $1, %0 \n\t"
"movq %0, %1"
: "=r" (zero)
: "r" (zero)
);
__asm__ volatile (
"addq $1, %0 \n\t"
"movq %0, %1"
: "=r" (one)
: "r" (one)
);
__asm__ volatile (
"addq $1, %0 \n\t"
"movq %0, %1"
: "=r" (infinity)
: "r" (infinity)
);
printf("value of zero, one, infinity = %llu, %llu, %llu\n", zero, one, infinity);
return 0;
}
Run Code Online (Sandbox Code Playgroud)
编辑
使用相同选项的clang进行编译也会产生未定义的行为:
zerao的值,1,无穷大= 0,1,18446744073709551615
值为零,一,无穷大= 2147483590,2147483591,2147483592
编辑2
通过奥拉夫的建议,我试着uint64_t从stdint.h.运行程序的结果仍未定义.
#include <stdio.h>
#include <stdint.h>
//#define inf_int volatile unsigned long long
#define inf_int uint64_t
int main(int argc, char *argv[]){
inf_int zero = 0;
inf_int one = 1;
inf_int infinity = ~0;
printf("value of zerao, one, infinity = %lu, %lu, %lu\n", zero, one, infinity);
__asm__ volatile (
"addq $1, %0 \n\t"
: "=r" (zero)
);
__asm__ volatile (
"addq $1, %0 \n\t"
: "=r" (one)
);
__asm__ volatile (
"addq $1, %0 \n\t"
: "=r" (infinity)
);
printf("value of zero, one, infinity = %lu, %lu, %lu\n", zero, one, infinity);
return 0;
}
Run Code Online (Sandbox Code Playgroud)
您的第一个代码未指定asm语句的任何输入,因此所选寄存器具有未定义的值(在本例中最初是返回值printf).第二个示例重复使用未定义值的错误,并通过用输出覆盖输入寄存器来添加进一步的未定义行为.
你可以使用两个寄存器,如:
__asm__ (
"movq %1, %0 \n\t"
"addq $1, %0"
: "=r" (zero)
: "r" (zero)
);
Run Code Online (Sandbox Code Playgroud)
您可以使用输入/输出参数:
__asm__ (
"addq $1, %0"
: "+r" (zero)
);
Run Code Online (Sandbox Code Playgroud)
哪个可以在内存和寄存器中:
__asm__ (
"addq $1, %0"
: "+rm" (zero)
);
Run Code Online (Sandbox Code Playgroud)
或者您可以将输入绑定到输出:
__asm__ (
"addq $1, %0"
: "=rm" (zero)
: "0" (zero)
);
Run Code Online (Sandbox Code Playgroud)
最后,不需要任何volatile修饰符.
| 归档时间: |
|
| 查看次数: |
3878 次 |
| 最近记录: |