Что такое% gs в сборке

void return_input (void)
{ 
   char array[30]; 

   gets (array); 
   printf("%s\n", array); 
}

После компиляции в gcc эта функция преобразуется в следующий ассемблерный код:

push   %ebp
mov    %esp,%ebp
sub    $0x28,%esp
mov    %gs:0x14,%eax
mov    %eax,-0x4(%ebp)
xor    %eax,%eax
lea    -0x22(%ebp),%eax
mov    %eax,(%esp)
call   0x8048374 
lea    -0x22(%ebp),%eax
mov    %eax,(%esp)
call   0x80483a4 
mov    -0x4(%ebp),%eax
xor    %gs:0x14,%eax
je     0x80484ac 
call   0x8048394 
leave  
ret  

Я не понимаю двух строк:

mov    %gs:0x14,%eax
xor    %gs:0x14,%eax

Что такое% gs и что именно делают эти две строки?

Это команда компиляции:

cc -c -mpreferred-stack-boundary=2 -ggdb file.c

person Alex F    schedule 12.02.2012    source источник
comment
Полагаю, это SS, DS, CS, ES, FS, GS - сегментные регистры. Если я правильно понял.   -  person Sergey Benner    schedule 12.02.2012
comment
Возможный дубликат Для чего предназначен регистр FS / GS?   -  person Ciro Santilli 新疆再教育营六四事件ۍ    schedule 07.11.2015


Ответы (3)


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

mov    %gs:0x14,%eax
xor    %gs:0x14,%eax

этот код используется для проверки того, что стек не взорвался или не был поврежден, с использованием канареечного значения, хранящегося в GS + 0x14, см. this.

gcc -fstack-protector=strong включен по умолчанию во многих современных дистрибутивах; вы можете использовать gcc -fno-stack-protector, чтобы не добавлять эти проверки. (На x86 локальное хранилище потока стоит дешево, поэтому GCC сохраняет в нем рандомизированное канареечное значение, что несколько затрудняет утечку.)

person Necrolis    schedule 12.02.2012
comment
привет, твоя ссылка не работает. - person CallMarl; 14.10.2020

ES, FS, GS: регистры дополнительных сегментов. Могут использоваться как регистры дополнительных сегментов; также используется в специальных инструкциях, которые охватывают сегменты (например, копии строк). взято отсюда

http://www.hep.wisc.edu/~pinghc/x86AssmTutorial.htm


Надеюсь, это поможет

person Sergey Benner    schedule 12.02.2012

В языках ассемблера в стиле AT&T знак процента обычно указывает регистр. В процессорах семейства x86 начиная с 386 года GS является одним из так называемых сегментных регистров. Однако в средах с защищенным режимом регистры сегментов работают как регистры селектора.

Селектор виртуальной памяти представляет собой собственное отображение виртуального адресного пространства вместе со своим собственным режимом доступа. На практике %gs:0x14 можно рассматривать как ссылку на массив, источник которого хранится в% gs (хотя ЦП выполняет небольшое дополнительное разыменование). В современных системах GNU / Linux %gs обычно используется для указания на локальную область хранения потока. Однако в коде, о котором вы спрашиваете, имеет значение только один элемент TLS - канарейка стека.

Идея состоит в том, чтобы попытаться обнаружить ошибку переполнения буфера, поместив случайное, но постоянное значение - оно называется канарейкой стека в память о канарейках, которые шахтеры использовали для сигнализации увеличения уровня ядовитых газов за счет dying - в стек перед вызовом gets(), над его фреймом стека, и проверьте, остается ли он там после того, как gets() вернется. gets() не имеет права перезаписывать эту часть стека - она ​​находится за пределами своего собственного фрейма стека, и ей не дается указатель на нее - поэтому, если канарейка стека умерла, что-то пошло не так опасным образом. (C как среда программирования особенно подвержена такого рода ошибкам, и исследователи безопасности научились использовать многие из них за последние двадцать лет или около того. Кроме того, gets() оказывается функцией, которая по своей природе подвержена риску для переполнения целевого буфера.) Вы не предложили адреса своим кодом, но 0x80484ac, скорее всего, является адресом leave, а call 0x8048394, который выполняется в случае несоответствия (то есть перепрыгивает je 0x80484ac в случае совпадения), является вероятно, вызов __stack_chk_fail(), предоставляемый libc для обработки повреждения стека, спасаясь от метафорической ядовитой шахты.

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

person dig    schedule 01.04.2018