Пинтос - системные вызовы проект 2 - PullRequest
0 голосов
/ 04 октября 2018

Я работаю над проектом Pintos, чтобы узнать больше об операционных системах.Я закончил Проект 1 и начал второй проект.У меня уже есть проверенный и работающий стек установки (через hex_dump).Прямо сейчас у меня возникают проблемы с получением правильных аргументов системного вызова.

В user / syscall.c есть 4 сборочных заглушки (0 - 4 заглушки), которые переносит пользовательский системный вызов.

 #define syscall3(NUMBER, ARG0, ARG1, ARG2)                      \
    ({                                                      \
      int retval;                                           \
      asm volatile                                          \
        ("pushl %[arg2]; pushl %[arg1]; pushl %[arg0]; "    \
         "pushl %[number]; int $0x30; addl $16, %%esp"      \
           : "=a" (retval)                                  \
           : [number] "i" (NUMBER),                         \
             [arg0] "g" (ARG0),                             \
             [arg1] "g" (ARG1),                             \
             [arg2] "g" (ARG2)                              \
           : "memory");                                     \
      retval;                                               \
    }) (this code is given to us)

Внутри моего syscall_handler есть некоторый код, который вызывает правильную функцию внутри ядра.

static void syscall_handler (struct intr_frame *f) {

  uint32_t *args = f->esp;
  if (args[0] == SYS_WRITE) {
    f->eax = write(args);
  }

Внутри моей функции записи я печатаю FD и Size

int sysCallNumber = (int) args[0];
  int fd = (int) args[1];
  const char *buffer = (char *) args[2];
  unsigned size = (unsigned) args[3];

  printf("FD is %d\n", fd);
  printf("Size is %d\n", size);

Выполнение 'echo hello stack overflow 1 22 333' даст следующий результат.Заметьте, я добавил примечания в скобках.() <- Что-то напортачило, и FD переопределяется с размером (включая нулевой терминатор) </p>

FD is 6    (hello)
Size is 6
FD is 6     (stack)
Size is 6
FD is 9    (overflow)
Size is 9
FD is 2    (1)
Size is 2
FD is 3    (22)
Size is 3
FD is 4    (333)
Size is 4
FD is 1   (this is from the printf("\n") in echo.c)
Size is 1

Я выполнил это с установкой точек останова GDB и кадров дампа и не смог выяснить это,Кто-нибудь сталкивался с чем-нибудь подобным?Если да, то как ты это исправил?

Спасибо!

1 Ответ

0 голосов
/ 14 октября 2018

Недавно я обнаружил ошибку в user/syscall.c, которая может повлиять на вас.Попробуйте применить этот патч к user/syscall.c:

diff --git a/src/lib/user/syscall.c b/src/lib/user/syscall.c
index a9c5bc8..efeb38c 100644
--- a/src/lib/user/syscall.c
+++ b/src/lib/user/syscall.c
@@ -10,7 +10,7 @@
             ("pushl %[number]; int $0x30; addl $4, %%esp"       \
                : "=a" (retval)                                  \
                : [number] "i" (NUMBER)                          \
-               : "memory");                                     \
+               : "memory", "esp");                              \
           retval;                                               \
         })

@@ -24,7 +24,7 @@
                : "=a" (retval)                                           \
                : [number] "i" (NUMBER),                                  \
                  [arg0] "g" (ARG0)                                       \
-               : "memory");                                              \
+               : "memory", "esp");                                       \
           retval;                                                        \
         })

@@ -40,7 +40,7 @@
                : [number] "i" (NUMBER),                         \
                  [arg0] "g" (ARG0),                             \
                  [arg1] "g" (ARG1)                              \
-               : "memory");                                     \
+               : "memory", "esp");                              \
           retval;                                               \
         })

@@ -57,7 +57,7 @@
                  [arg0] "g" (ARG0),                             \
                  [arg1] "g" (ARG1),                             \
                  [arg2] "g" (ARG2)                              \
-               : "memory");                                     \
+               : "memory", "esp" );                             \
           retval;                                               \
         })

Вот длинная история ...

Например, в макросе syscall3 ожидаемый генерируемый код сборки выглядит примерно так:this

pushl ARG2
pushl ARG1
pushl ARG0
pushl NUMBER
int  $0x30
addl $16, %esp

Это должно работать до тех пор, пока стек выглядит точно так, как ожидается, просто нажмите инструкцию прерывания.Вот как выглядит дизассемблированная функция write в тестовых программах (сгенерированных objdump -d pintos/src/userprog/build/tests/userprog/args-many):

0804a1a5 <write>:
 804a1a5:       ff 74 24 0c             pushl  0xc(%esp)
 804a1a9:       ff 74 24 08             pushl  0x8(%esp)
 804a1ad:       ff 74 24 04             pushl  0x4(%esp)
 804a1b1:       6a 09                   push   $0x9
 804a1b3:       cd 30                   int    $0x30
 804a1b5:       83 c4 10                add    $0x10,%esp
 804a1b8:       c3                      ret

С этими инструкциями связана огромная проблема.Поскольку аргументы помещаются в стек относительно указателя стека %esp, неправильные аргументы помещаются в стек!Это связано с тем, что %esp меняется после каждой pushl инструкции.

После некоторого изучения расширенного синтаксиса asm для gcc, я думаю, что нашел правильное решение.Регистр %esp необходимо добавить в список Clobbers в расширенной инструкции asm для каждого syscall*.Это связано с тем, что каждая инструкция pushl изменяет %esp косвенно, поэтому мы должны сообщить gcc об этой модификации, чтобы она не использовала %esp неправильно в сгенерированных инструкциях.

...