Для чего предназначен регистр «FS» / «GS»?

103

Итак, я знаю, какими должны быть следующие регистры и их использование:

  • CS = сегмент кода (используется для IP)

  • DS = сегмент данных (используется для MOV)

  • ES = целевой сегмент (используется для MOVS и т. Д.)

  • SS = сегмент стека (используется для SP)

Но для чего предназначены следующие регистры?

  • FS = "Сегмент файла"?

  • GS = ???

Примечание: я не спрашиваю о какой-либо конкретной операционной системе - я спрашиваю о том, для чего они предназначены для использования процессором, если что-то еще.

пользователь541686
источник
24
Насколько я знаю, F и G в этих двух ничего не означают. Просто в ЦП (и в наборе команд) было место для шести определяемых пользователем сегментных регистров, и кто-то заметил, что помимо сегмента «S», буквы «C» и «D» (код и данные) были последовательно, так что «E» был «дополнительным» сегментом, а затем «F» и «G» просто следовали.
torek
3
Могло быть, всегда трудно понять, что происходит в чьей-то голове, если только вы не были там в то время (а я был на другом берегу, совсем рядом с командой разработчиков Intel).
torek
20
Только подумайте, сколько удовольствия мы могли бы повеселить с регистрацией BS: -}
Ира Бакстер
5
Я всегда использовал GS как «Графический сегмент». :-)
Брайан Кноблауч
2
Как насчет "G" eneral "S" egment?
SS Anne

Ответы:

110

Вот для чего они предназначены и для чего используются Windows и Linux.

Первоначальная цель регистров сегмента состояла в том, чтобы позволить программе получить доступ ко многим различным (большим) сегментам памяти, которые должны были быть независимыми и являться частью постоянного виртуального хранилища. Идея была взята из операционной системы Multics 1966 года , которая рассматривала файлы как просто адресуемые сегменты памяти. Нет BS «Открыть файл, записать запись, закрыть файл», просто «Сохранить это значение в этот виртуальный сегмент данных» с очисткой грязной страницы.

Наши текущие операционные системы 2010 года - это гигантский шаг назад, поэтому их называют «евнухами». Вы можете адресовать только один сегмент вашего пространства процессов, давая так называемое «плоское (ИМХО тупое) адресное пространство». Сегментные регистры на машине x86-32 все еще можно использовать для реальных сегментных регистров, но это никого не беспокоило (Энди Гроув, бывший президент Intel, в прошлом веке имел довольно известную общественную поддержку, когда понял, что все эти инженеры Intel потратили энергию и его деньги на реализацию этой функции, что никто не собирался ее использовать. Вперед, Энди!)

AMD, перейдя на 64-битную версию, решила, что им все равно, исключат ли они Multics в качестве выбора (это благотворительная интерпретация; недоброжелательная - они ничего не знали о Multics) и поэтому отключили общую возможность сегментных регистров в 64-битном режиме. По-прежнему существовала потребность в потоках для доступа к локальному хранилищу потока, и каждому потоку требовался указатель ... где-то в немедленно доступном состоянии потока (например, в регистрах) ... на локальное хранилище потока. Поскольку Windows и Linux использовали для этой цели FS и GS (спасибо Нику за разъяснения) в 32-битной версии, AMD решила разрешить использование 64-битных сегментных регистров (GS и FS) только для этой цели (я думаю, вы можете сделать так, чтобы они указывали в любом месте вашего процесса; не знаю, может ли код приложения их загружать или нет).

Было бы архитектурно красивее IMHO, чтобы карта памяти каждого потока имела абсолютный виртуальный адрес (например, 0-FFF), который был его локальным хранилищем потока (не нужен указатель на регистр [сегмент]!); Я сделал это в 8-битной ОС еще в 1970-х годах, и это было чрезвычайно удобно, например, иметь еще один большой стек регистров для работы.

Итак, сегментные регистры теперь похожи на ваше приложение. Они служат рудиментарной цели. К нашей коллективной потере.

Те, кто не знает истории, не обречены ее повторять; они обречены на глупые поступки.

Ира Бакстер
источник
11
@supercat: более простая и блестящая схема, которая позволила бы им адресовать в 65536 раз больше памяти, заключалась бы в том, чтобы рассматривать сегментные регистры как полное верхнее 16-битное расширение нижних 16 бит, что, по сути, является тем, что 286, 386 и Multics сделали.
Ира Бакстер
4
@IraBaxter: Проблема с этим подходом заключается в том, что сегменты в стиле 80286 имеют достаточно высокие накладные расходы, чем в конечном итоге приходится хранить много объектов в каждом сегменте и, таким образом, сохранять сегмент и смещение для каждого указателя. Напротив, если кто-то желает округлить выделение памяти до значений, кратных 16 байтам, сегментация в стиле 8086 позволяет использовать только сегмент как средство идентификации объекта. Округление распределения до 16 байт могло быть немного утомительным в 1980 году, но сегодня стало бы победой, если бы размер каждой ссылки на объект уменьшился с 8 до четырех.
supercat
3
Эти регистры будут использованы в современных операционных системах. В основном они предназначены для указания информации о блоках управления задачами, по крайней мере, в двух основных операционных системах, доступных сейчас для чипов x86. А поскольку они больше не являются «универсальными» даже по своему первоначальному замыслу, вы не сможете использовать их много. В системах x86-64 лучше делать вид, что их просто не существует, пока вам не понадобится информация, к которой они позволяют получить доступ в блоках управления потоками.
Ира Бакстер
5
Аналогия с приложением действительно плохая, основанная на устаревшей науке; это связано с иммунной системой, поэтому определенно не является «рудиментарным». Это отвлекает от фактического сообщения. Кроме этого, это хороший ответ.
code_dredd 06
5
Спасибо за забавное, беспрепятственное обращение с сегментированной и плоской памятью :) Я также написал код на 6809 (с выгружаемой памятью и без нее), 6502, z80, 68k и 80 [123]? 86, моя точка зрения такова. память - это шоу ужасов, и я рад, что его отправили на свалку истории. Использование FS и GS для эффективного доступа к данным thread_local - счастливое непреднамеренное последствие исторической ошибки.
Ричард Ходжес
44

Регистры FSи GSявляются сегментными регистрами. У них нет цели, определяемой процессором, но вместо этого цель задается операционной системой, в которой они запущены. В 64-разрядной версии Windows GSрегистр используется для указания структур, определенных операционной системой. FSи GSобычно используются ядрами ОС для доступа к памяти, зависящей от потока. В Windows GSрегистр используется для управления памятью, зависящей от потока. Ядро linux использует GSдля доступа к памяти, зависящей от процессора.

Cytinus
источник
1
Были ли они предназначены для использования в целях, определенных ОС, или для облегчения кода, который должен делать что-то подобное, *dest++ = lookup[*src++];что в противном случае было бы довольно неудобным, если бы dest, lookup и src находились в трех несвязанных местах.
supercat
8
В Windows FS действительно предназначена для хранилища, специфичного для потока. См. Документированную карту блока, указанного ФС здесь en.wikipedia.org/wiki/Win32_Thread_Information_Block
Недко
2
Дело не только в Windows. GS также используется для TLS в OS X. GS также используется 64-битными ядрами для отслеживания системных структур во время переключения контекста. Для этого ОС будет использовать SWAPGS.
ET
13

FS используется для указания на блок информации о потоках (TIB) в процессах Windows.

одним из типичных примеров является ( SEH ), который хранит указатель на функцию обратного вызова в FS:[0x00].

GS обычно используется как указатель на локальное хранилище потока (TLS). и один пример, который вы, возможно, видели раньше, - это защита стека канареек (stackguard), в gcc вы можете увидеть что-то вроде этого:

mov    eax,gs:0x14
mov    DWORD PTR [ebp-0xc],eax
Zerocool
источник
2
На самом деле это не отвечает на вопрос. В вопросе говорится : Примечание: я не спрашиваю о какой-либо конкретной операционной системе - я спрашиваю о том, для чего они были предназначены для использования процессором, если что-либо.
Майкл Петч
10
@MichaelPetch, да, я знаю, я просто хочу добавить это как полезную информацию для тех, кто читает эти вопросы в SO
zerocool
3

Согласно руководству Intel, в 64-битном режиме эти регистры предназначены для использования в качестве дополнительных базовых регистров в некоторых вычислениях линейных адресов. Я взял это из раздела 3.7.4.1 (стр. 86 в наборе из 4 томов). Обычно, когда ЦП находится в этом режиме, линейный адрес совпадает с эффективным адресом, потому что сегментация часто не используется в этом режиме.

Таким образом, в этом плоском адресном пространстве FS и GS играют роль в адресации не только локальных данных, но и определенных структур данных операционной системы (стр. 2793, раздел 3.2.4), таким образом, эти регистры предназначались для использования операционной системой, однако эти конкретные конструкторы определить.

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

С точки зрения «первоначальных намерений» сложно сказать, кроме того, что это просто дополнительные регистры. Когда ЦП находится в режиме реального адреса , это похоже на то, что процессор работает как высокоскоростной 8086, и эти регистры должны быть явно доступны программе. Ради настоящей эмуляции 8086 вы должны запустить ЦП в режиме виртуального 8086, и эти регистры не будут использоваться.

Роберт Хоутон
источник
2

TL; DR;

Для чего предназначен регистр «FS» / «GS»?

Просто для доступа к данным за пределами сегмента данных по умолчанию (DS). Точно как ES.


Долгое чтение:

Итак, я знаю, какими должны быть следующие регистры и их использование:

[...]

Ну, почти, но DS - это не «какой-то» сегмент данных, а сегмент по умолчанию. Все ли операции выполняются по умолчанию (* 1). Здесь расположены все переменные по умолчанию - по сути dataи bss. В некотором роде это одна из причин, по которой код x86 довольно компактен. Все важные данные, к которым чаще всего обращаются (плюс код и стек), находятся в пределах 16-битного сокращенного расстояния.

ES используется для доступа ко всему остальному (* 2), за пределами 64 KiB DS. Как текст текстового редактора, ячейки электронной таблицы или графические данные графической программы и так далее. В отличие от часто предполагаемого, к этим данным не так часто обращаются, поэтому необходимость в префиксе вредит меньше, чем использование более длинных полей адреса.

Похоже, это лишь незначительное раздражение, что DS и ES, возможно, придется загружать (и перезагружать) при выполнении строковых операций - это, по крайней мере, компенсируется одним из лучших наборов инструкций по обработке символов того времени.

Что действительно больно, так это когда пользовательские данные превышают 64 КиБ и нужно начинать операции. Хотя некоторые операции просто выполняются с одним элементом данных за раз (подумайте A=A*2), для большинства требуется два ( A=A*B) или три элемента данных ( A=B*C). Если эти элементы находятся в разных сегментах, ES будет перезагружен несколько раз за операцию, что приведет к значительным накладным расходам.

Вначале, с небольшими программами из 8-битного мира (* 3) и такими же небольшими наборами данных, это не было большой проблемой, но вскоре стало основным узким местом в производительности - и, тем более, настоящей головной болью для программисты (и компиляторы). В 386 Intel наконец-то облегчила задачу, добавив еще два сегмента, так что любая последовательная унарная , двоичная или троичная операция с элементами, распределенными в памяти, могла выполняться без постоянной перезагрузки ES.

Для программирования (по крайней мере, в сборке) и проектирования компилятора это было большим преимуществом. Конечно, могло быть и больше, но с тремя горлышками бутылки практически не было, так что не нужно перебарщивать.

В названии буквы F / G - это просто буквенные продолжения после E. По крайней мере, с точки зрения дизайна процессора ничего не связано.


* 1 - Использование ES для назначения строки является исключением, поскольку необходимы просто два сегментных регистра. Без них не было бы много пользы - или всегда нужен префикс сегмента. Это могло убить одну из удивительных особенностей - использование (неповторяющихся) строковых инструкций, что привело бы к экстремальной производительности из-за их однобайтовой кодировки.

* 2 - Итак, оглядываясь назад, «Сегмент всего остального» было бы лучше, чем «Дополнительный сегмент».

* 3 - Всегда важно помнить, что 8086 предназначалась только как временная мера, пока 8800 не была закончена, и в основном предназначалась для мира встраиваемых систем, чтобы поддерживать клиентов 8080/85.

Raffzahn
источник
1
Вау, спасибо, что объяснили все это! Это многое объясняет и имеет такой смысл! +1
user541686