ARM内联汇编

gcc ARM内联汇编 与 预处理

预处理

define 编译预处理时,对程序中所有出现的“宏名”,都用宏定义中的字符串去代换

#开头都是预编译指令

#ifndef HEADER_FILE
#define HEADER_FILE
the entire header file file
#endif

这种结构就是通常所说的包装器 #ifndef。当再次引用头文件时,条件为假,因为 HEADER_FILE 已定义。此时,预处理器会跳过文件的整个内容,编译器会忽略它。


您可以使用 typedef 为一个已有的类型取一个新的名字。下面是使用 typedef 定义一个新类型的语法:

typedef struct config *config_t; //将config* 重新定为 config_t
typedef type newname; 

ARM内联汇编

GCC编译器支持直接在C或者C++代码中,嵌入ARM汇编代码。其基本格式非常简单,大致如下:

__asm__ [__volatile__] ( assembler template 
           : [output operand list]                  /* optional */
           : [input operand list]                   /* optional */
           : [clobbered register list]              /* optional */
           );

每一个操作数由下列组成

[name]"[modifier]constraint"(C expression)

name 表示别名

限定符constraint

   "a”将输入变量放入eax
   "b”将输入变量放入ebx
 “c”将输入变量放入ecx
 “d”将输入变量放入edx
 “s”将输入变量放入esi
 “d”将输入变量放入edi

GCC中定义了三个修改符modifier,分别是:
修改符 含义

=    只写操作数,通常用于输出操作数中
+    可读且可写操作数,必须要列在输出操作数中
&    寄存器只能用于输出

编译器并不会分析你的汇编代码,找出这种被你修改过,需要恢复的寄存器,因此你必须显式的告诉编译器,被你修改过的寄存器有哪些。这就是修改寄存器列表所起到的作用。
clobbered register list

示例__flush and reload

/*SFENCE——串行化发生在SFENCE指令之前的写操作但是不影响读操作。 
   LFENCE——串行化发生在SFENCE指令之前的读操作但是不影响写操作。 
   MFENCE——串行化发生在MFENCE指令之前的读写操作。
sfence:在sfence指令前的写操作当必须在sfence指令后的写操作前完成。
lfence:在lfence指令前的读操作当必须在lfence指令后的读操作前完成。 no instruction fol-lowing it executes before thelfenceinstruction
mfence:在mfence指令前的读写操作当必须在mfence指令后的读写操作前完成。
*/
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
unsigned long gettime() {
volatile unsigned long tl;
asm __volatile__("lfence\nrdtsc" : "=a" (tl): : "%edx"); //“__volatile__”关键字,这个是可选的,
//其作用是禁止编译器对后面编写的汇编指令再进行优化
return tl;
}

int probe(char *adrs) {
volatile unsigned long time;
//gcc arm
asm __volatile__ (
" mfence \n" //cpuid (intel) 虚拟机会模拟该指令,导致时间增加
" lfence \n"
" rdtsc \n"
" lfence \n" //reads the 64-bitcounter, returning the low 32 bits of the counter in%eax and the high 32 bits in%edx
" movl %%eax, %%esi \n" //把rdtsc返回的时间传入ESI保存
" movl (%1), %%eax \n" //%1表示adrs reads 4 bytes from the memory address in%ecx
" lfence \n" //()表示指针
" rdtsc \n"
" subl %%esi, %%eax \n" //rdtsc返回值保存在eax.相减,结果保存在eax
" clflush 0(%1) \n" //()剔除缓存中的值
: "=a" (time)
: "c" (adrs) //c infer edc
: "%esi", "%edx");
return time; /*Loads shorter than the threshold are presumed tobe served from the cache,
indicating that another processhas accessed the memory line since it was last flushed5 from the cache*/
}