я изучаю сборку x86, используя приведенный ниже код для тестирования, я вижу в консоли gdb, что регистр rsp, который указывает на вершину стека, начинается с 0x7FFFFFFFFDFD0, если я правильно понимаю, в коде я не использовал push или pop, который изменяет rsp, поэтому 0x7FFFFFFFDFD0 является значением по умолчанию, это означает, что у нас одинаковое количество байтов в стеке, но я использую Linux, где размер стека составляет 8 МБ.
section .text
global _start
_start:
mov rcx, 2
add rcx, 8
mov rax, 0x1
mov rbx, 0xff
int 0x80
Смотрите ASLR
@dimich: GDB по умолчанию отключает ASLR; вот почему OP каждый раз видит одно и то же значение и почему оно так близко к верхней странице нижней канонической половины виртуального адресного пространства. ASLR изменит больше битов, чем то, где находится верхняя часть отображения 8M, а также сместит случайную величину на странице. (На самом деле не начинается с отображения 8M, но может расти до этого.)
Пожалуйста, используйте заглавные буквы как обычно.
Для 64-бит 80x86; обычно (см. примечание 1) можно использовать только 48 бит виртуального адреса. Чтобы упростить увеличение количества битов, которые можно использовать в будущих процессорах, не нарушая работу старого программного обеспечения; AMD решила, что неиспользуемые старшие 16 бит 64-битного виртуального адреса должны совпадать. Адреса, которые соответствуют этому, называются «каноническими адресами», а адреса, которые не соответствуют, называются «неканоническими адресами». Обычно (см. примечание 2) любая попытка доступа к чему-либо по неканоническому адресу вызывает исключение (общий сбой защиты).
Это дает виртуальное адресное пространство, например:
0x0000000000000000 to 0x00007FFFFFFFFFFF = canonical (often "user space")
0x0000800000000000 to 0xFFFF7FFFFFFFFFFF = non-canonical hole
0xFFFF800000000000 to 0xFFFFFFFFFFFFFFFF = canonical (often "kernel space")
Это делает достаточно очевидным, что без рандомизации адресного пространства стек начального потока процесса (см. примечание 3) начинается с адреса, немного более низкого, чем самый высокий адрес, который может использовать процесс.
Разница между самым высоким адресом, который может использовать процесс, и адресом, который вы видите (0x7FFFFFFFDFD0), составляет всего 2030 байт; который (как упоминалось в комментарии Fuz) используется такими вещами, как вспомогательные векторы ELF, аргументы командной строки и переменные среды, которые потребляют часть стека до запуска вашего кода.
Примечание 1: Intel недавно (около 2 лет назад?) создала расширение, которое (если поддерживается ЦП и ОС) позволяет использовать 57 бит виртуального адреса. В этом случае «неканоническая дыра» сокращается, а самый высокий виртуальный адрес, который может использовать процесс, будет увеличен до 0x00FFFFFFFFFFFFFFFF.
Примечание 2. Совсем недавно (около 6 месяцев назад?) Intel создала расширение, которое (если оно поддерживается ЦП и ОС и включено для процесса) может игнорировать неиспользуемые старшие биты адреса ЦП; так что программное обеспечение может упаковывать другую информацию в эти биты (например, может быть «тип данных») без явного маскирования перед использованием.
Примечание 3. Поскольку операционные системы обычно не обеспечивают изоляцию между потоками (например, любой поток может повредить стек любого другого потока или «локальные данные потока» любого другого потока); если вы создадите больше потоков, они не смогут использовать один и тот же адрес «верхней части стека».
Когда ваша программа запускается, в стеке находится куча вещей (вспомогательные векторы ELF, аргументы командной строки, переменные среды). Это занимает место. Фактическая вершина стека, вероятно,
0x7FFFFFFFFFFFFFFF
.