Задний план
Я собрал qemu-system-x86_64.exe на компьютере с Windows, используя MSYS2 (x86_64), и я устраняю ошибку сегментации, которая возникает при попытке запустить его.
На самом деле я не думаю, что проблема связана с QEMU или MSYS2, это проблема отладки ошибки сегментации и, возможно, неправильной генерации кода.
Отладка ошибки сегментации
Программа вылетает с ошибкой segmentation fault
в самом начале.
При запуске с gdb обнаружил следующее:
Starting program: C:\msys64\home\Administrator\qemu\x86_64-softmmu\qemu-system-x86_64.exe
[New Thread 4656.0x1194]
Program received signal SIGSEGV, Segmentation fault.
0x00000000007d3254 in getpagesize () at util/oslib-win32.c:535
535 {
(gdb) bt
#0 0x00000000007d3254 in getpagesize () at util/oslib-win32.c:535
#1 0x000000000086dd39 in init_real_host_page_size () at util/pagesize.c:16
#2 0x00000000007ea1b2 in __do_global_ctors ()
at C:/repo/mingw-w64-crt-git/src/mingw-w64/mingw-w64-crt/crt/gccmain.c:67
#3 0x00000000007ea20f in __main ()
at C:/repo/mingw-w64-crt-git/src/mingw-w64/mingw-w64-crt/crt/gccmain.c:83
#4 0x000000000040137f in __tmainCRTStartup ()
at C:/repo/mingw-w64-crt-git/src/mingw-w64/mingw-w64-crt/crt/crtexe.c:329
#5 0x00000000004014db in WinMainCRTStartup ()
at C:/repo/mingw-w64-crt-git/src/mingw-w64/mingw-w64-crt/crt/crtexe.c:195
Это странно.
Программа аварийно завершает работу при запуске __do_global_ctors и вызове init_real_host_page_size()
, который вызывает getpagesize()
. Это действительно простые функции:
uintptr_t qemu_real_host_page_size;
intptr_t qemu_real_host_page_mask;
static void __attribute__((constructor)) init_real_host_page_size(void)
{
qemu_real_host_page_size = getpagesize();
qemu_real_host_page_mask = -(intptr_t)qemu_real_host_page_size;
}
...
int getpagesize(void)
{
SYSTEM_INFO system_info;
GetSystemInfo(&system_info);
return system_info.dwPageSize;
}
getpagesize()
вылетает в самом начале функции, еще до того, как вызовет GetSystemInfo
.
Вот дизассемблирование этого фрагмента кода и значения регистров:
(gdb) disassem
Dump of assembler code for function getpagesize:
0x00000000007d3250 <+0>: sub $0x68,%rsp
=> 0x00000000007d3254 <+4>: mov %fs:0x0,%rax
0x00000000007d325d <+13>: mov %rax,0x58(%rsp)
0x00000000007d3262 <+18>: xor %eax,%eax
0x00000000007d3264 <+20>: lea 0x20(%rsp),%rcx
0x00000000007d3269 <+25>: callq *0x68e8b9(%rip) # 0xe61b28 <__imp_GetSystemInfo>
0x00000000007d326f <+31>: mov 0x24(%rsp),%eax
0x00000000007d3273 <+35>: mov 0x58(%rsp),%rdx
0x00000000007d3278 <+40>: xor %fs:0x0,%rdx
0x00000000007d3281 <+49>: jne 0x7d3288 <getpagesize+56>
0x00000000007d3283 <+51>: add $0x68,%rsp
0x00000000007d3287 <+55>: retq
0x00000000007d3288 <+56>: callq 0x85bde0 <__stack_chk_fail>
0x00000000007d328d <+61>: nop
End of assembler dump.
(gdb) info registers
rax 0x6f4b868 116701288
rbx 0x86ec10 8842256
rcx 0x6f4b8b8 116701368
rdx 0xe5a780 15050624
rsi 0x86e220 8839712
rdi 0x6f4ad50 116698448
rbp 0x6f4ad10 0x6f4ad10
rsp 0x22fd80 0x22fd80
r8 0x0 0
r9 0x0 0
r10 0x5000016b 1342177643
r11 0x22f9d8 2292184
r12 0x0 0
r13 0x10 16
r14 0x0 0
r15 0x0 0
rip 0x7d3254 0x7d3254 <getpagesize+4>
eflags 0x10202 [ IF RF ]
cs 0x33 51
ss 0x2b 43
ds 0x2b 43
es 0x2b 43
fs 0x53 83
gs 0x2b 43
Похоже, что-то не так с доступом к памяти mov %fs:0x0,%rax
.
Кто ставит FS на 83?
(gdb) starti
Starting program: C:\msys64\home\Administrator\qemu\x86_64-softmmu\qemu-system-x86_64.exe
[New Thread 3508.0x14b0]
Program stopped.
0x00000000778b6fb1 in ntdll!CsrSetPriorityClass ()
from C:\Windows\SYSTEM32\ntdll.dll
(gdb) p $fs
$1 = 83
(gdb) watch $fs
Watchpoint 1: $fs
(gdb) c
Continuing.
Program received signal SIGSEGV, Segmentation fault.
0x00000000007d3254 in getpagesize () at util/oslib-win32.c:535
535 {
ФС никто не ставит!
Вопросы
- Сгенерированный GCC код, использующий неинициализированный регистр. Что может быть причиной этого? Был ли какой-то код инициализации, который должен был запуститься, но не запустился?
- Любые идеи, как я могу отладить эту проблему?
fs
в каждой точке останова, чтобы точно определить, когда эта переменная установлена. - person user3629249   schedule 19.11.2018gdb
показывает, что код выполнялся некоторое время, прежде чем был остановлен. Так что установкаfs
давно прошла - person user3629249   schedule 19.11.2018starti
, которая запускает код, но останавливается на первой инструкции. Затем я установил точку наблюдения для FS. С этого момента каждое изменение в FS будет останавливать прогон. Затем я выдаю командуc
. gdb запускает код, но проверяет каждую инструкцию, которая выполняется, на предмет изменения FS. Требуется некоторое время, пока он не достигнет ошибки сегментации. Тот факт, что gdb не остановился в точке наблюдения до ошибки сегментации, доказывает, что FS не изменилась с начала выполнения до ошибки. - person Amir Gonnen   schedule 19.11.2018fs
является одним из сегментных регистров. он устанавливается перед запуском программы - person user3629249   schedule 20.11.2018