生活充满了有趣的谜题,与他们搏斗让我咯咯地笑......
最近我从vm(vmware)中运行实例x86-64 linux获得了一个有趣的段故障核心转储。
mov 0x18(%rdi) %rax // move a pointer to %rax, trick things happens here
it seems rax did not get expected value at all
...// 2 instructions later
mov %r8,0x10(%rax) // load some value to offset of the pointer in memory
Segment fault
Dump of assembler code for function timer_delink:
// Function: boolean timer_delink(timer_t *timer), where timer is a cycle link list(prev/next never NULL)
0x42e0f0 <+0>: mov (%rdi),%rcx rdi <= timer; rcx <= timer->parent
0x42e0f3 <+3>: xor %eax,%eax eax <= update_parent <= 0; eax stores return value
0x42e0f5 <+5>: test %rcx,%rcx if (!timer->parent) return(FALSE);
0x42e0f8 <+8>: je 0x42e138 <timer_delink+72> return eax(update_parent);
0x42e0fa <+10>: mov 0x18(%rdi),%rax rax <= timer->prev //rax should contain timer->prev, which is
0x42e0fe <+14>: mov 0x10(%rdi),%r8 r8 <= timer->next
0x42e102 <+18>: mov 0x8(%rcx),%rdx rdx <= timer->parent->down
=>0x42e106 <+22>: mov %r8,0x10(%rax) timer->rev->next = timer->next;//info register said rax = 0;
0x42e10a <+26>: mov 0x10(%rdi),%rsi rsi <= timer->next
0x42e10e <+30>: mov %rax,0x18(%rsi) timer->next->prev = timer->prev;
0x42e112 <+34>: xor %eax,%eax eax <= update_parent <= 0
在违规指令(0x42e106)中尝试将%r8的内容移动到%rax中包含的地址偏移16,这导致了段错误
信息寄存器说rax = 0,难怪为什么段故障:),但是......
(gdb) info register
rax 0x0 0
..
rdi 0x20103ff0 ==> stores timer pointer
但是根据指令0x42e0fa,rax应该包含timer-&gt; prev,在每个内存转储下面不是0
(gdb) p *timer
$8 = {parent = 0x2f379e0 <root_timer>, down = 0x0, next = 0x201027c0, prev = 0x20103b28 ...}
难题是,%rax的内容与mov指令后的第3条指令的内存有何不同(0x42e0fa)
可能是缓存问题吗? 这可能是竞争条件吗?
此函数调用的上下文发生在linux上的ukernel中,当ukernel重新调度线程时会发生段错误。 只有一个硬件CPU线程可用。