Итак, в следующей программе 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
Я ожидаю, что большинство переменных будут в регистрах, но все помещается в указатель стека, как вы можете видеть, и я пока не совсем понимаю, почему. Спасибо за уделенное время.
Stack canary - это метод защиты от атак разбивания стека, которые, как правило, оставляют комментарии, если остается переполнение. Вот почему по умолчанию gcc будет вставлять канареечные проверки, есть ли у функции внутренний буфер, выделенный из стека.
Это можно отключить, используя-fno-stack-protector
.
Также размер, который запускает gcc для добавления канарейки, выбираетсяssp-buffer-size
.
Узнайте больше здесь
А почему локальные переменные хранятся в стеке? - ну а где бы еще вы их хранили. Вы можете указать, что переменная будет оптимизирована как регистр сregister
ключевое слово, но это не гарантия. Количество ваших регистров ограничено, намного меньше, чем может обрабатывать стек. Хранение их в регистрах оправдано только для оптимизации скорости.
%rax
- это 64-битная версия, и та же информация передается префиксомq
mov
. Antti Haapala