Как определить значения, сохраненные в стеке?

Я провожу некоторые эксперименты и хотел бы видеть, что сохраняется в стеке во время системного вызова (сохраненное состояние пользовательского процесса). Согласно http://lxr.linux.no/#linux+v2.6.30.1/arch/x86/kernel/entry_32.S показывает, что различные значения регистров сохраняются по этим конкретным смещениям относительно указателя стека. Вот код, который я пытался использовать для проверки того, что сохраняется в стеке (это в пользовательском системном вызове, который я создал):

asm("movl 0x1C(%esp), %ecx");
asm("movl %%ecx, %0" : "=r" (value));

где значение является беззнаковым длинным.

На данный момент это значение не соответствует ожидаемому (оно показывает, что 0 сохраняется для пользовательского значения ds).

Правильно ли я обращаюсь к смещению указателя стека?

Другая возможность может заключаться в том, могу ли я использовать отладчик, такой как GDB, для проверки содержимого стека в ядре? Я не слишком активно использую отладку и не знаю, как отлаживать код внутри ядра. Любая помощь горячо приветствуется.


person Brian    schedule 06.04.2010    source источник


Ответы (3)


Нет необходимости в встроенной сборке. Сохраненное состояние, которое entry_32.S помещает в стек для системного вызова, представлено как struct pt_regs, и вы можете получить указатель на него следующим образом (вам нужно будет включить <asm/ptrace.h> и/или <asm/processor.h> прямо или косвенно):

struct pt_regs *regs = task_pt_regs(current);

person Matthew Slattery    schedule 09.04.2010

Встроенный ассемблер сложнее, чем кажется. Попытка кратко осветить проблемы GCC:

  1. Если он модифицирует регистры процессора, необходимо поместить эти регистры в список затирания. Важно отметить, что список блокировки должен содержать ВСЕ регистры, которые вы изменили напрямую (читай явно) или косвенно (читай неявно);
  2. Чтобы усилить (1), условные и математические операции также изменяют регистры, более известные как флаги состояния (ноль, перенос, переполнение и т. д.), поэтому вы должны информировать об этом, добавляя "cc" к клоберу. список;
  3. Добавить "память", если она изменяет разные (случайные) позиции памяти;
  4. Добавьте ключевое слово volatile, если оно изменяет память, не упомянутую в аргументах ввода/вывода;

Затем ваш код становится:

asm("movl 0x1C(%%esp), %0;"
    : "=r" (value)
    : /* no inputs :) */
    /* no modified registers */
);

Выходной аргумент не обязательно должен быть в списке уничтожения, потому что GCC уже знает, что он будет изменен.

В качестве альтернативы, поскольку все, что вам нужно, это значение регистра ESP, вы можете избежать всей этой боли:

register int esp asm("esp");
esp += 0x1C;

Это может не решить вашу проблему, но это путь. Для справки проверьте это, это и это.

person jweyrich    schedule 06.04.2010

Имейте в виду, что код x86_64 часто будет передавать значения в регистры (поскольку их так много), поэтому в стеке ничего не будет. Проверьте промежуточный вывод gcc (-S IIRC) и найдите push в сборке.

Я не знаком с отладкой кода ядра, но gdb определенно удобнее для интерактивного изучения стека.

person Nathan Kidd    schedule 06.04.2010