Почему член orig_eax
включен в sys/user.h
struct user_regs_struct
?
Почему orig_eax предоставляется в дополнение к eax?
Ответ 1
Потому что это было в struct pt_regs
, что... http://tomoyo.sourceforge.jp/cgi-bin/lxr/source/arch/x86/include/asm/user_32.h#L77
73 * is still the layout used by user mode (the new
74 * pt_regs doesn't have all registers as the kernel
75 * doesn't use the extra segment registers)
Итак, многие утилиты для пользовательского пространства ожидают здесь поле orig_eax
, поэтому оно также включено в user_regs_struct
(чтобы быть совместимым со старыми отладчиками и ptrace
rs)
Следующий вопрос: "Почему член orig_eax
включен в struct pt_regs
?".
Он был добавлен в linux 0.95 http://lxr.linux.no/#linux-old+v0.95/include/sys/ptrace.h#L44.
Я предполагаю, что это было сделано после некоторого другого unix с pt_regs
struct. Комментарий в 0,95 говорит
29 * this struct defines the way the registers are stored on the
30 * stack during a system call.
Таким образом, место orig_eax
определяется интерфейсом syscall. Здесь http://lxr.linux.no/#linux-old+v0.95/kernel/sys_call.s
17 * Stack layout in 'ret_from_system_call':
18 * ptrace needs to have all regs on the stack.
19 * if the order here is changed, it needs to be
20 * updated in fork.c:copy_process, signal.c:do_signal,
21 * ptrace.c ptrace.h
22 *
23 * 0(%esp) - %ebx
...
29 * 18(%esp) - %eax
...
34 * 2C(%esp) - orig_eax
Почему нам нужно дважды сохранить старый eax
? Поскольку eax
будет использоваться для возвращаемого значения syscall (тот же файл, бит ниже):
96_system_call:
97 cld
98 pushl %eax # save orig_eax
99 push %gs
...
102 push %ds
103 pushl %eax # save eax. The return value will be put here.
104 pushl %ebp
...
117 call _sys_call_table(,%eax,4)
Ptrace должен иметь возможность считывать состояние всех регистров перед syscall и возвращаемое значение syscall; но возвращаемое значение записывается в %eax
. Тогда исходный eax
, используемый перед тем, как syscall будет потерян. Чтобы сохранить его, есть поле orig_eax
.
UPDATE: Благодаря R.. и отличному LXR, я выполнил полный поиск orig_eax
в linux 0.95.
Он используется не только в ptrace, но и в do_signal при перезапуске syscall (если есть syscall, заканчивающийся ERESTARTSYS
)
158 *(&eax) = orig_eax;
UPDATE2: Linus сказал что-то интересное:
Важно, чтобы для ORIG_EAX было задано некоторое значение, которое не является действительный номер системного вызова, так что логика перезапуска системного вызова (см. код обработки сигнала) не запускается.
UPDATE3: ptrace
r приложение (отладчик) может изменить orig_eax
, чтобы изменить номер вызываемого вызова: http://lkml.org/lkml/1999/10/30/82 (в некоторых версиях ядра, было ли EIO изменено в ORTI_EAX)