生活充满了有趣的谜题,与他们搏斗让我闲扯...
最近我得到1个有趣段故障核心转储从正在运行的实例在虚拟机的x86-64 Linux操作系统(VMware的)。
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)尝试MOV%R8的内容从包含在%RAX地址,这引起故障段偏移16
信息寄存器表示RAX = 0,难怪段故障:),但是.....
(gdb) info register
rax 0x0 0
..
rdi 0x20103ff0 ==> stores timer pointer
但是,每指令0x42e0fa,RAX应包含timer->分组,这是不为0每下面存储器转储
(gdb) p *timer
$8 = {parent = 0x2f379e0 <root_timer>, down = 0x0, next = 0x201027c0, prev = 0x20103b28 ...}
所以让人不解的是,怎么可能RAX%的内容从存储在不同MOV指令后的第三个指令(0x42e0fa)
难道是缓存的问题? 难道是竞争状态?
这个函数调用的背景是发生在一个ukernel在Linux上,当ukernel被重新安排线程段发生故障。 只有一个硬件CPU线程可用。