环境aarch64的交叉编译器
我们将C语言翻译成汇编代码,来看volatile关键字的作用
我们先看一段C语言代码
void udelay(uint64_t usec)
{
uint64_t start, cnt, delta,freq;
volatile uint64_t delta_us = 0; //------------------在这里定义了一个volatile变量
uint64_t reference_ratio = 16;
if(timer_start == 0)
{
generic_timer_start();
start = read_cntpct_el0();
delta_us = 1000; //------------------ 给这个变量赋值100
while(delta_us) //------------------ 使用这个变量,这里是判断该变量是否等于0,然后走相应逻辑
{
cnt = read_cntpct_el0();
if(cnt != start)
break;
delta_us--;
if(delta_us == 0)
{
base_frequency = 0;
}
}
INFO("base_frequency %ld\n",base_frequency);
}
......
}
翻译成汇编后,从汇编代码来看,delta_us=1000,直接将1000写道栈尾中了.
while(delta_us)代码,需要读出delta_us,也是种栈尾种读出来的
00000000002034b4 <udelay>:
2034b4: a9bd7bfd stp x29, x30, [sp,#-48]!
2034b8: 910003fd mov x29, sp
2034bc: a90153f3 stp x19, x20, [sp,#16]
2034c0: aa0003f3 mov x19, x0
2034c4: b00000c0 adrp x0, 21c000 <xxx_middle_mem_pool+0xa40>
2034c8: f90017bf str xzr, [x29,#40]
2034cc: 900000d4 adrp x20, 21b000 <buf+0xdb8>
2034d0: b94f9c00 ldr w0, [x0,#3996]
2034d4: 340000a0 cbz w0, 2034e8 <udelay+0x34>
2034d8: f9412a80 ldr x0, [x20,#592]
2034dc: b50003a0 cbnz x0, 203550 <udelay+0x9c>
2034e0: d37cee73 lsl x19, x19, #4
2034e4: 14000014 b 203534 <udelay+0x80>
2034e8: 97ffffdd bl 20345c <generic_timer_start>
2034ec: d53be022 mrs x2, cntpct_el0
2034f0: d2807d00 mov x0, #0x3e8 //------------------------ 0x3e8-#1000给x0赋值1000,x0就表示delta_us变量
2034f4: f90017a0 str x0, [x29,#40] //------------------------ 将这个变量写到栈尾内存(其实可能是main-memory,也可能写入到了cache中)
2034f8: f9412a80 ldr x0, [x20,#592]
2034fc: f94017a1 ldr x1, [x29,#40] //------------------------ 将这个变量从栈尾内存读出来,放到X1中
203500: b4000161 cbz x1, 20352c <udelay+0x78> //------------------------ 比较x1是否等于0,然后走相应的分支
203504: d53be021 mrs x1, cntpct_el0
203508: eb02003f cmp x1, x2
20350c: 54000101 b.ne 20352c <udelay+0x78>
203510: f94017a1 ldr x1, [x29,#40] //----------------------- 在操作(delta_us--)时,再次从内存中去读
203514: d1000421 sub x1, x1, #0x1 // 这样对应 delta_us--
203518: f90017a1 str x1, [x29,#40]
20351c: f94017a1 ldr x1, [x29,#40]
203520: eb1f003f cmp x1, xzr
203524: 9a9f1000 csel x0, x0, xzr, ne
我们去除volatile关键字后,再翻译成汇编:
uint64_t delta_us = 0; //------------------在这里定义了一个volatile变量
翻译成汇编后,从汇编代码来看,delta_us=1000,只是将1000写入到了x0寄存器中
0000000002034b4 <udelay>:
2034b4: a9be7bfd stp x29, x30, [sp,#-32]!
2034b8: 910003fd mov x29, sp
2034bc: f9000bf3 str x19, [sp,#16]
2034c0: aa0003f3 mov x19, x0
2034c4: b00000c0 adrp x0, 21c000 <xxx_middle_mem_pool+0xa40>
2034c8: b94f9c00 ldr w0, [x0,#3996]
2034cc: 35000160 cbnz w0, 2034f8 <udelay+0x44>
2034d0: 97ffffe3 bl 20345c <generic_timer_start>
2034d4: d53be021 mrs x1, cntpct_el0
2034d8: d2807d00 mov x0, #0x3e8 //------------------------ 0x3e8-#1000给x0赋值100,x0就表示delta_us变量
2034dc: d53be022 mrs x2, cntpct_el0
2034e0: eb01005f cmp x2, x1
2034e4: 540000a1 b.ne 2034f8 <udelay+0x44>
2034e8: f1000400 subs x0, x0, #0x1 //------------------ 这行对应的delta_us--
2034ec: 54ffff81 b.ne 2034dc <udelay+0x28>
2034f0: 900000c0 adrp x0, 21b000 <buf+0xdb8>
2034f4: f901281f str xzr, [x0,#592]
2034f8: 900000c0 adrp x0, 21b000 <buf+0xdb8>
2034fc: f9412801 ldr x1, [x0,#592]
总结volatile关键字的作用:其实就算告诉编译器,我要读写的数据,不要从X0-X30通用寄存器中读取,每次都要从内存中去读取,这里说的内存可能是主内存(main-memory)、也可能是各级cache等