Почему эта программа предоставляет следующие канареечные значения и ассемблерный код?

Итак, в следующей программе intlen (), написанной в этой книге, когда я читаю язык ассемблера, соответствующий этой программе, intlen () предоставляет защищенное значение Canary, а также несколько значений, которые ВСЕ помещаются в стек.

Моя проблема с этим состоит в том, что в книге очень ясно указано, что у вас есть шесть регистров, в которые можно поместить шесть переменных, и как только вы поместите эти переменные в регистры и когда вы пройдете мимо 6 регистров, ЗАТЕМ все попадает в стек.

Мне нужно знать, почему программа intlen () помещает все свои значения в стек и понимает, почему канареечное значение помещается там, где оно есть.

Я уже пробовал искать ответ в Google, а также подсчитывать переменные и аргументы в предыдущих программах, потому что «вызов» все еще актуален, верно? Дело в том, что эти переменные в предыдущих программах учитываются только до четырех.

Изменить: я также хотел бы знать, сколько len выделяет указатель стека при защите с помощью значения Canary. Вот как, я думаю, работает len. аргумент * s имеет значение 8 бит, защитник стека - это еще 8 бит, поскольку мы находимся в 64-битной системе, а кадр стека при возврате составляет 8 бит, поэтому для этого требуется всего 24 бита, верно?

/* C Code */ 
int len(char *s){
  return strlen(s);
}

void iptoa(char *s, long *p){
  long val = *p; 
  sprintf(s, "%ld", val); 
}

int intlen(long x){
  long v; 
  char buf[12]; 
  v = x; 
  iptoa(buf, &v); 
  return len(buf); 
}

===== сборочный аналог =======

без протектора стека

1. intlen: 
2. subq  $40, %rsp 
3. movq %rdi, 24(rsp) 
4. leaq 24(%rsp), %rsi
5. movq %rsp, %rdi 
6. call iptoa 

С протектором

0. intlen:
1. subq $56, %rsp  
2. movq %fs:40, %rax  < Canary Value
3. movq %rax, 40(%rsp)  < Where the Canary goes (Why does this go here?) 
4. xorl %eax, %eax 
5. movq %rdi, 8(%rsp)
6. leaq 8(%rsp), %rsi
7. leaq 16(%rsp), %rdi 
8. call iptoa 

Я ожидаю, что большинство переменных будут в регистрах, но все помещается в указатель стека, как вы можете видеть, и я пока не совсем понимаю, почему. Спасибо за уделенное время.

# gcc assembly x86-64
Источник
  • 2
    Предполагается, что канарейка входит в стек, в этом весь смысл канарейки стека. Это простая защита от атак разбиения стека, когда адрес возврата перезаписывается.
  • 0
    Итак, если я правильно это читаю, он идет прямо над обратным адресом? В этом есть смысл, так какого же размера канарейка?
  • 0
    Да, чтобы в случае переполнения оно было перезаписано, и перед возвратом из функции вызывается stk_chck_fail, если введенное значение не совпадает с прочтением, чтобы можно было вызвать прерывание и выход.
  • 0
    Хорошо, вот почему он занимает 8 бит, потому что для защиты возвращаемого значения требуется указатель на фрейм?
  • 0
    Требуется 32 бита для x86 и 64 бита для x86-64. Итак, 4 байта или 8 байтов в зависимости от архитектуры.
  • 0
    Хорошо, я работаю с архитектурой x86-64, поэтому 8 байт. :)
  • 0
    @Matthew_J_Barnes Несогласованность в вашем вопросе: это 8 байтов , а не 8 бит . Не следует путать два - это может быть очень опасно.
  • 1
    Вы должны прочитать базовое руководство по ассемблеру или чему-то еще, прежде чем пытаться что-либо расшифровать. Любой, кто прочитал базовое руководство по 64-битной x86 asm, сразу же узнает, что %rax - это 64-битная версия, и та же информация передается префиксом q mov .
  • 0
    @ Антти Хаапала. . Да, я знаю, что% rax - это 64 бита. . . Прочитал главу. . . Мне хорошо известно, что movq - это 64-битный носитель. . . . Так же, как movl - 32 бита, movw - 16, а movb - 8. Почему это вообще ставится под сомнение?
Codelisting
за 0 против
Лучший ответ

Stack canary - это метод защиты от атак разбивания стека, которые, как правило, оставляют комментарии, если остается переполнение. Вот почему по умолчанию gcc будет вставлять канареечные проверки, есть ли у функции внутренний буфер, выделенный из стека.

Это можно отключить, используя-fno-stack-protector .

Также размер, который запускает gcc для добавления канарейки, выбираетсяssp-buffer-size .

Узнайте больше здесь

А почему локальные переменные хранятся в стеке? - ну а где бы еще вы их хранили. Вы можете указать, что переменная будет оптимизирована как регистр сregister ключевое слово, но это не гарантия. Количество ваших регистров ограничено, намного меньше, чем может обрабатывать стек. Хранение их в регистрах оправдано только для оптимизации скорости.

  • 0
    Хранение их в регистрах оправдано только для оптимизации скорости. Но OP сделал компилировать с поддержкой оптимизации. Переменные хранятся в регистрах или оптимизировано прочь, за исключением, конечно , для массива, и переменная , которая должна быть в памяти , когда его адрес передается в другую функцию.
  • 0
    Я вообще не компилировал, это был буквально пример из книги «Операционные системы» с точки зрения программиста.
Codelisting
Популярные категории
На заметку программисту