Показаны сообщения с ярлыком Win64. Показать все сообщения
Показаны сообщения с ярлыком Win64. Показать все сообщения

понедельник, 4 декабря 2023 г.

Что такое указатель статической цепочки в контексте соглашения о вызовах ABI?

Это перевод What is a static chain pointer in the context of calling convention ABI? Автор: Реймонд Чен.

Глубоко в руководстве Application Binary Interface из System V для архитектуры AMD64 есть сноска на странице 24, в которой говорится: "%r10 используется для передачи указателя статической цепочки функции". Что такое "указатель статической цепочки"?

среда, 27 октября 2010 г.

Объясняем 64 бита

Это перевод 64 Bit Explained. Автор: piers7.

Слушайте, на самом деле это не так сложно.

воскресенье, 4 апреля 2010 г.

Так называемый стек Itanium-а

Это перевод The Itanium's so-called stack. Автор: Реймонд Чен.

В прошлом году я говорил о том, что процессоры Itanium имеют два стека. Первый из них - обычный "стек" (тот самый, на который ссылается регистр sp): блок памяти, управляемый вручную, из которого функции могут брать память для себя. Например, если вы объявите локальную переменную вроде
var
  szBuffer: array[0..MAX_PATH] of Char;
то этот буфер будет размещён в "стеке".

Но не все локальные переменные хранятся в "стеке".

четверг, 18 февраля 2010 г.

Как программно определить, запущены ли мы на 64-разрядной Windows?

Это перевод How to detect programmatically whether you are running on 64-bit Windows. Автор: Реймонд Чен.

Чтобы программно определить, запущены ли вы на 64-разрядной Windows, вы можете использовать функцию IsWow64Process, которая показывает, не запущен ли ваш 32-разрядный процесс в режиме эмуляции.

среда, 17 февраля 2010 г.

Почему команда Win64 выбрала модель LLP64?

Это перевод Why did the Win64 team choose the LLP64 model? Автор: Реймонд Чен.

Участник Beer28 написал на Channel 9: "Я не могу себе представить, что у многих программ могут быть проблемы с изменением размерности типов". Я усмехнулся и сделал пометку, чтобы написать пост о модели данных Win64.

Команда Win64 выбрала модель данных LLP64, в которой все целочисленные типы остаются 32-х разрядными и только указатели расширяются до 64-х бит. Почему?

В дополнении к причинам, данными на той странице, другой причиной было сохранение совместимости хранимых (persistence) форматов данных. Например, часть заголовка bitmap-файла определяется такой записью:
type
PBitmapInfoHeader = ^TBitmapInfoHeader;
{$EXTERNALSYM tagBITMAPINFOHEADER}
tagBITMAPINFOHEADER = packed record
biSize: DWORD;
biWidth: Longint;
biHeight: Longint;
biPlanes: Word;
biBitCount: Word;
biCompression: DWORD;
biSizeImage: DWORD;
biXPelsPerMeter: Longint;
biYPelsPerMeter: Longint;
biClrUsed: DWORD;
biClrImportant: DWORD;
end;
TBitmapInfoHeader = tagBITMAPINFOHEADER;
{$EXTERNALSYM BITMAPINFOHEADER}
BITMAPINFOHEADER = tagBITMAPINFOHEADER;
Если бы Longint расширился с 32-х бит до 64-х, то для 64-х разрядных программ стало бы невозможным чтение bitmap-файлов (прим.пер.: напомню, пост идёт о Windows; в Delphi мы пока не имеем 64-х разрядного компилятора, хотя всё идёт к тому, что в Delphi будет так же).

Кроме файлов у нас есть и других форматы. В дополнение к очевидным вещам типа RPC и DCOM, для передачи информации между процессами могут также использоваться двоичные BLOB реестра и блоки разделяемой памяти. Если процесс-источник и процесс-назначение будут различной разрядности, то любое изменение размерности целых приведёт к несовпадению форматов.

Заметьте, что в этих сценариях с обменом информации между процессами, нам не нужно волноваться об изменившемся размере указателя (Pointer). Никто в здравом уме на станет передавать указатель через границы процессов: раздельные адресные пространства означают, что значение указателя из чужого процесса бесполезно в нашем и наоборот - так зачем же тогда их передавать?

пятница, 30 января 2009 г.

Преодолевая пределы Windows: физическая память

Это перевод Pushing the Limits of Windows: Physical Memory. Автор: Марк Руссинович.

Это первый пост в блоге из серии "Pushing the Limits of Windows", которую я буду писать ближайшие месяцы и в которой буду описывать как Windows и приложения используют конкретный ресурс, лицензионные и реализационные ограничения ресурса, как измерить использование ресурса и как диагностировать его утечки. Чтобы эффективно управлять своими Windows системами вам нужно понимать как Windows управляет физическими ресурсами, такими как процессоры (CPUs) и память (memory), а также логическими ресурсами, такими как виртуальная память (virtual memory), дескрипторы (handles) и объекты оконного менеджера (window manager objects). Знание пределов и ограничений этих ресурсов и методы слежения за ними позволит вам соотносить использование ресурсов с приложениями, которые их используют, эффективно изменять систему для определённой нагрузки и идентифицировать приложения с утечкой ресурсов.

вторник, 9 декабря 2008 г.

ia64 - неверное объявление данных near и far

Это перевод ia64 - misdeclaring near and far data. Автор: Реймонд Чен.

Как я сказал вчера, ia64 - это очень требовательная архитектура. Сегодня я буду обсуждать ещё один способ наврать компилятору так, что ему потом придётся вас за это стукнуть.

Неинициализированный мусор на ia64 может быть смертелен

Это перевод Uninitialized garbage on ia64 can be deadly. Автор: Реймонд Чен.

В прошлый раз мы говорили о некоторых плохих вещах, которые могут произойти, если вы вызываете функцию с неверной сигнатурой. Архитектура ia64 привносит ещё одну возможность столкнуться с плохими последствиями в, казалось бы, безобидной ситуации.

История соглашений вызова, часть 5: amd64

Это перевод The history of calling conventions, part 5: amd64. Автор: Реймонд Чен.
Четвёртая часть.
Последней архитектурой, которую мы рассмотрим будет архитектура AMD64 (также известная как x86-64).

AMD64 берёт традиционную архитектуру x86 и увеличивает регистры до 64-х бит, именуя их rax, rbx и т.д. И также добавляет восемь дополнительных регистров, называя их просто как R8-R15.

- Первые четыре параметры в функцию передаются в rcx, rdx, r8 и r9. Все другие параметры передаются в стеке. Более того, для параметров в регистре резервируется место в стеке, на случай если вызываемая функция захочет сбросить регистры в стек; это также важно для функций с переменным числом аргументов.
- Параметры меньше 64-бит не дополняются нулями; верхние биты содержат мусор, поэтому не забывайте обнулять их явно, если вы собираетесь их использовать. Параметры размером больше 64-х бит передаются по ссылке.
- Возвращаемое значение помещается в rax. Если возвращаемое значение больше 64-х бит, то в функцию будет передан неявный секретный параметр, который содержит адрес, по которому нужно записать результат.
- Все регистры обязаны сохраняться во всемя вызова, кроме регистров rax, rcx, rdx, r8, r9, r10 и r11, которые свободны.
- Вызываемый не чистит стек. Это работа вызывающего.
- Стек должен быть всё время выровненным на границу 16-ти байт. Поскольку инструкция "call" записывает в стек 8-ми байтовый адрес возврата, то это значит, что каждая не листовая функция должна подправлять стек на значение вида 16n + 8 для восстановления выравнивания на 16 байт.

Вот пример:
void SomeFunction(int a, int b, int c, int d, int e);

void CallThatFunction()
{
SomeFunction(1, 2, 3, 4, 5);
SomeFunction(6, 7, 8, 9, 10);
}
После входа в CallThatFunction стек выглядит примерно так:
xxxxxxx0  .. данные на стеке .. 
xxxxxxx8 адрес возврата <- RSP
Из-за наличия в нём адреса возврата стек оказывается не выровненным. Функция CallThatFunction настраивает свой фрейм примерно так:
    sub    rsp, 0x28
Заметим, что размер локального стекового фрейма равен 16n + 8, так что в результате у нас получается выравненный стек:
xxxxxxx0  .. данные на стеке ..
xxxxxxx8 адрес возврата
xxxxxxx0 (arg5)
xxxxxxx8 (место для arg4)
xxxxxxx0 (место для arg3)
xxxxxxx8 (место для arg2)
xxxxxxx0 (место для arg1) <- RSP
Теперь мы готовим первый вызов:
        mov     dword ptr [rsp+0x20], 5     ; параметр 5
mov r9d, 4 ; параметр 4
mov r8d, 3 ; параметр 3
mov edx, 2 ; параметр 2
mov ecx, 1 ; параметр 1
call SomeFunction ; Вперёд, Спиди-Гонщик!
Когда функция SomeFunction возвращает управление, стек ещё не очищен и поэтому выглядит так же, как и выше. Тогда для второго вызова нам просто нужно занести новые значения в уже подготовленное место:
        mov     dword ptr [rsp+0x20], 10    ; параметр 5
mov r9d, 9 ; параметр 4
mov r8d, 8 ; параметр 3
mov edx, 7 ; параметр 2
mov ecx, 6 ; параметр 1
call SomeFunction ; Вперёд, Спиди-Гонщик!
Теперь CallThatFunction завершена и она должна очистить стек и вернуть управление:
        add     rsp, 0x28
ret
Заметьте, что вы практичеси не встречаете инструкций "push" в коде amd64, поскольку парадигмой вызывающего является резервирование пространства и повторное использование его.

История соглашений вызова, часть 4: ia64

Это перевод The history of calling conventions, part 4: ia64. Автор: Реймонд Чен.

Третья часть.

Архитектура ia-64 (Itanium) и архитектура AMD64 (AMD64) относительно новые, так что маловероятно, чтобы многие из вас имели дело с соглашениями вызова на этих платформах, но я включу их обзор в эту серию, потому что, кто знает, может однажды у вас появится такая машина.

четверг, 27 ноября 2008 г.

Почему гранулярность выделения адресного пространства равна 64 Кб?

Это перевод Why is address space allocation granularity 64K? Автор: Реймонд Чен. Альтернативный перевод.

Возможно, вы задумывались, почему VirtualAlloc выделяет память, выравненную на границу 64 Кб, хотя гранулярность страниц памяти всего 4 Кб.