内核空间C代码中简单指针算术中的意外行为

时间:2018-03-24 22:38:22

标签: c assembly kernel x86-64 osdev

我正在尝试关注thisthis教程进行学习。我遇到了一种奇怪的行为,我仍然不理解。

我有以下C代码:

void print(const char* str, char* vidptr, TerminalColor color){
    for (unsigned i = 0; str[i] != '\0'; ++i){
        unsigned int j = i*2;
        vidptr[j] = str[i];
        vidptr[j+1] = color;
    }
    return;
}

当我使用以下参数调用它时:

const char* str = "My string";
char* vidptr = (char*) 0xb8000;
print(str, vidptr, GREY); // GREY is equal to 7
在第一次执行body时,

内存看起来像这样:

0xb8000: 0x07  0x00  0x00  0x00  0x00  0x00  0x00  0x00

我的预期:

0xb8000: 0x4D  0x07  0x00  0x00  0x00  0x00  0x00  0x00

使用连接到qemu-system-x86_64 gdbserver的gdb运行程序我发现在vidptr[j] = str[i];一切正常运行之前,vidptr[j+1] = color;的执行会覆盖第一个,就好像vidptr [j]相等到vidptr [j + 1]。 代码反汇编(如分区布局中的gdb所示)如下:

; vidptr[j] = str[i]
0x100144 <print+35>     mov    edx,DWORD PTR [rbp-0x8]
0x100147 <print+38>     mov    rax,QWORD PTR [rbp-0x18]
0x10014b <print+42>     add    rax,rdx
0x10014e <print+45>     mov    ecx,DWORD PTR [rbp-0x4]
0x100151 <print+48>     mov    rdx,QWORD PTR [rbp-0x20]
0x100155 <print+52>     add    rdx,rcx
0x100158 <print+55>     movzx  eax,BYTE PTR [rax]
0x10015b <print+58>     mov    BYTE PTR [rdx],al
; vidptr[j+1] = color
0x10015d <print+60>     mov    eax,DWORD PTR [rbp-0x4]
0x100160 <print+63>     add    eax,0x1
0x100163 <print+66>     mov    edx,eax  ;eax = 0x1
0x100165 <print+68>     mov    rax,QWORD PTR [rbp-0x20] ;rax = 0xb8000
0x100169 <print+72>     add    rax,rdx ;here I observe the following: after I give the ni command to gdb the pc goes to the 
                                       ;equivalent instruction `add eax,edx` but I oddly see the value of rax going to 0xb7fff. 
                                       ;Then I send another ni command to gdb which shows again the instruction pointer to the 
                                       ;next instruction (print+75).
0x10016c <print+75>     mov    edx,DWORD PTR [rbp-0x24] ; here the value of rax is again 0xb8000 instead of 0xb8001
0x10016f <print+78>     mov    BYTE PTR [rax],dl ; here the value written in the previous instruction is overwritten
0x100171 <print+80>     add    DWORD PTR [rbp-0x8],0x1
0x100175 <print+84>     mov    edx,DWORD PTR [rbp-0x8]
0x100178 <print+87>     mov    rax,QWORD PTR [rbp-0x18]
0x10017c <print+91>     add    rax,rdx
0x10017f <print+94>     movzx  eax,BYTE PTR [rax]
0x100182 <print+97>     test   al,al
0x100184 <print+99>     jne    0x100139 <print+24>  

有关为何发生这种情况的任何线索?

作为参考,遵循gdb的输出:

1: x/i $pc
=> 0x100166 <print+69>: add    rax,rdx
2:x/8xb 0xb8000
0xb8000:        0x71    0x00    0x20    0x00    0x20    0x00    0x20    0x00
4: i = 0
5: j = 0
6: /x $rax = 0xb8000
(gdb) ni
1: x/i $pc
=> 0x100167 <print+70>: add    eax,edx
2:x/8xb 0xb8000
0xb8000:        0x71    0x00    0x20    0x00    0x20    0x00    0x20    0x00
6: /x $rax = 0xb7fff
(gdb) p/x $eax
$3 = 0xb7fff
(gdb) p/x $edx
$4 = 0x1
(gdb) ni
1: x/i $pc
=> 0x100169 <print+72>: mov    edx,DWORD PTR [rbp-0x24]
2:x/8xb 0xb8000
0xb8000:        0x71    0x00    0x20    0x00    0x20    0x00    0x20    0x00
6: /x $rax = 0xb8000
(gdb) ni
1: x/i $pc
=> 0x10016c <print+75>: mov    BYTE PTR [rax],dl
2:x/8xb 0xb8000
0xb8000:        0x71    0x00    0x20    0x00    0x20    0x00    0x20    0x00
6: /x $rax = 0xb8000
(gdb) ni
1: x/i $pc
=> 0x10016e <print+77>: add    DWORD PTR [rbp-0x8],0x1
2:x/8xb 0xb8000
0xb8000:        0x07    0x00    0x20    0x00    0x20    0x00    0x20    0x00
6: /x $rax = 0xb8000

0 个答案:

没有答案