OberonCore https://forum.oberoncore.ru/ |
|
NEW для структур без метки (untagged) https://forum.oberoncore.ru/viewtopic.php?f=29&t=5664 |
Страница 4 из 4 |
Автор: | Иван Денисов [ Пятница, 06 Май, 2016 10:32 ] |
Заголовок сообщения: | Re: NEW для структур без метки (untagged) |
Воспользовался приемом, который придумал kekc_leader и в Linux теперь текстуры для вывода шрифтов генерирую так! Сначала избавляемся от любых данных переменной длины в аргументах, у моем случае это вызов RendBlended, а потом вычисляем (подбираем экспериментально) на сколько надо сдвинуть данные, чтобы вызов библиотечной функции попал на кратный 16 адрес... Код: PROCEDURE RendBlended0 (f: Font; string: ARRAY 64 OF CHAR; c: Color): Sdl2Video.Surface;
VAR s: Sdl2CTypes.PSurface; BEGIN s := Win.RenderUNICODE_Blended( f(Font).f, SYSTEM.VAL(Sdl2CTypes.PUint16, SYSTEM.ADR(string)), SYSTEM.VAL(Sdl2CTypes.PColor, SYSTEM.ADR(c))); RETURN Sdl2StdLin.NewSurface(s) END RendBlended0; PROCEDURE RendBlended1 (f: Font; string: ARRAY 64 OF CHAR; c: Color): Sdl2Video.Surface; VAR pad1: INTEGER; s: Sdl2CTypes.PSurface; BEGIN s := Win.RenderUNICODE_Blended( f(Font).f, SYSTEM.VAL(Sdl2CTypes.PUint16, SYSTEM.ADR(string)), SYSTEM.VAL(Sdl2CTypes.PColor, SYSTEM.ADR(c))); RETURN Sdl2StdLin.NewSurface(s) END RendBlended1; PROCEDURE RendBlended2 (f: Font; string: ARRAY 64 OF CHAR; c: Color): Sdl2Video.Surface; VAR pad1, pad2: INTEGER; s: Sdl2CTypes.PSurface; BEGIN s := Win.RenderUNICODE_Blended( f(Font).f, SYSTEM.VAL(Sdl2CTypes.PUint16, SYSTEM.ADR(string)), SYSTEM.VAL(Sdl2CTypes.PColor, SYSTEM.ADR(c))); RETURN Sdl2StdLin.NewSurface(s) END RendBlended2; PROCEDURE RendBlended3 (f: Font; string: ARRAY 64 OF CHAR; c: Color): Sdl2Video.Surface; VAR pad1, pad2, pad3: INTEGER; s: Sdl2CTypes.PSurface; BEGIN s := Win.RenderUNICODE_Blended( f(Font).f, SYSTEM.VAL(Sdl2CTypes.PUint16, SYSTEM.ADR(string)), SYSTEM.VAL(Sdl2CTypes.PColor, SYSTEM.ADR(c))); RETURN Sdl2StdLin.NewSurface(s) END RendBlended3; PROCEDURE RendBlended (f: Font; string: ARRAY 64 OF CHAR; c: Color): Sdl2Video.Surface; VAR sp: INTEGER; BEGIN CASE SYSTEM.ADR(sp) MOD 16 OF 0: RETURN RendBlended0 (f, string$, c) | 4: RETURN RendBlended1 (f, string$, c) | 8: RETURN RendBlended2 (f, string$, c) | 12: RETURN RendBlended3 (f, string$, c) END END RendBlended; PROCEDURE (f: Font) RenderUNICODE_Blended (string: ARRAY OF CHAR; color: INTEGER): Sdl2Video.Surface; VAR sp: INTEGER; c: Color; s: Sdl2CTypes.PSurface; BEGIN FillColor(color, c); RETURN RendBlended (f, string$, c) END RenderUNICODE_Blended; |
Автор: | prospero78 [ Пятница, 06 Май, 2016 10:46 ] |
Заголовок сообщения: | Re: NEW для структур без метки (untagged) |
Ну, лезть в System, я стараюсь от слова "никогда". Слишком это скользкий путь. А что касается массивов переменной длины, так это вообще мина замедленного действия. Начиная от управления памятью, заканчивая контролем целостности. Ноль в конце в строках Си -- уродское решение. Строки в стиле Паскаля (первый байт-два-четыре -- длина строки) мне нравится куда больше. Числовые массивы в виде каких-либо данных (файл, поток и всё-такое) просто требуют со страшной силой какой-то абстракции уровнем глубже. Иначе чревата полная потеря контроля. |
Автор: | kekc_leader [ Суббота, 07 Май, 2016 02:34 ] |
Заголовок сообщения: | Re: NEW для структур без метки (untagged) |
Иван Денисов писал(а): Воспользовался приемом, который придумал kekc_leader и в Linux теперь текстуры для вывода шрифтов генерирую так! Очень рад, что моя находка пригодилась.Кстати, статья на Хабре ведь не о выравнивании начального адреса части стека при вызове процедуры (которое производится иногда по 4, а иногда - по 16 байт), а о выравнивании элементов внутри записи. Или с этим тоже возникают проблемы несовместимости в случае работы со шрифтами? Насчёт включения такого выравнивания в линуксовскую версию ядра Блэкбокса. Возможно, я не знаю всех подробностей, но пока что склоняюсь к тому, что линуксовский Блэкбокс всегда должен выравнивать стековые блоки при вызовах процедур по 16 байт. Потому что: 1) Когда мы пишем программу, используя какую-нибудь стороннюю библиотеку, то сталкиваемся с тем, что в документации к библиотекам как правило не указываются особенности отдельных экспортируемых процедур, связанные с выравниванием начальных адресов. Например в документации к SDL2 нигде не указано про такую особенность процедуры SDL_FillRect, а также некоторых других процедур. 2) При попытке экспериментальным путём установить, какие из процедур нуждаются в особом выравнивании, мы сталкиваемся с необходимостью тестировать каждую процедуру отдельно, а также, что более существенно, с тем, что какая-либо процедура может при определённых обстоятельствах не требовать особого выравнивания, а при других - требовать. Например, в SDL2 это зависит от режима, в котором был создан прорисовщик (SDL_Renderer): аппаратный режим или программный. Программный режим использует особые инструкции процессора, для которых и необходимо выравнивание. С другой стороны, требования той или иной процедуры могут зависеть не только от программного контекста, но и от марки процессора, на которой происходит работа программы. Таким образом, нормально разрабатывать на линуксовской версии Блэкбокса программы, использующие сторонние библиотеки, принципиально не представляется возможным. Имеется в виду разработка программ в обероновском смысле, настоящая разработка, с возможностью верификации, а не механической проверки на всех возможных компьютерах, "работает или нет". 3) Проблема, изложенная в пункте №2, в GCC на Линуксе (начиная с определённой версии, с которой сама проблема и возникает) решается следующим образом: отрезок стека для любой процедуры выравнивается по 16 байт. На Линуксе практически все сторонние библиотеки компилируются с помощью GCC, а значит Блэкбокс (в своей версии для Линукса) должен быть совместим библиотеками, скомпилированными на GCC, то есть должен использовать такое выравнивание для всех процедур. Надеюсь, что сумел убедить если не в необходимости изложенного решения, то в степени существенности данной неисправности как таковой. |
Автор: | kekc_leader [ Суббота, 07 Май, 2016 02:36 ] |
Заголовок сообщения: | Re: NEW для структур без метки (untagged) |
prospero78 писал(а): Ну, лезть в System, я стараюсь от слова "никогда". Я не понял, к чему это? Просто так или это ответ на какое-то сообщение?
Слишком это скользкий путь. А что касается массивов переменной длины, так это вообще мина замедленного действия. Начиная от управления памятью, заканчивая контролем целостности. Ноль в конце в строках Си -- уродское решение. Строки в стиле Паскаля (первый байт-два-четыре -- длина строки) мне нравится куда больше. Числовые массивы в виде каких-либо данных (файл, поток и всё-такое) просто требуют со страшной силой какой-то абстракции уровнем глубже. Иначе чревата полная потеря контроля. |
Автор: | Иван Денисов [ Суббота, 07 Май, 2016 09:02 ] |
Заголовок сообщения: | Re: NEW для структур без метки (untagged) |
kekc_leader писал(а): Таким образом, нормально разрабатывать на линуксовской версии Блэкбокса программы, использующие сторонние библиотеки, принципиально не представляется возможным. Имеется в виду разработка программ в обероновском смысле, настоящая разработка, с возможностью верификации, а не механической проверки на всех возможных компьютерах, "работает или нет". Отлично сказано.kekc_leader писал(а): Кстати, статья на Хабре ведь не о выравнивании начального адреса части стека при вызове процедуры (которое производится иногда по 4, а иногда - по 16 байт), а о выравнивании элементов внутри записи. Или с этим тоже возникают проблемы несовместимости в случае работы со шрифтами? С хабровской статьей я похоже напутал. Подумал, что эта проблема связана в том числе с выравниванием аргументов передаваемых функциям. Собственно я думал, что и ваша проблема именно в этом. Поэтому рекомендовал разные [union] и т.п. А потом, когда сам для генератора текстур делал этот выравнивающий прием, понял что суть проблемы именно в "выравнивании начального адреса части стека при вызове процедуры".
|
Автор: | kekc_leader [ Суббота, 07 Май, 2016 12:43 ] |
Заголовок сообщения: | Re: NEW для структур без метки (untagged) |
Иван Денисов писал(а): Подумал, что эта проблема связана в том числе с выравниванием аргументов передаваемых функциям. Кстати, насколько я пока успел заметить, ни на Линуксе, ни на Виндоусе не возникают проблемы с выравниванием полей записей. Кажется, они и в GCC, и в Блэкбоксе выравниваются по 4 байта. Точнее, не просто по 4 байта, а немного хитрее. Наверное, это происходит точно также, как описано в «Построении Компиляторов» Н. Вирта (см. здесь, стр. 43). Надо бы проверить. Или кто-то, может быть, уже знает?
|
Автор: | prospero78 [ Суббота, 07 Май, 2016 14:22 ] |
Заголовок сообщения: | Re: NEW для структур без метки (untagged) |
В БлекБоксе, если я правильно понимаю, Вирт специально ровнял всё по 4 байта для 32битного кода. GCC через pragma может заравнять что угодно, и как угодно. Но не надо. |
Автор: | kekc_leader [ Воскресенье, 08 Май, 2016 23:18 ] |
Заголовок сообщения: | Re: NEW для структур без метки (untagged) |
prospero78 писал(а): В БлекБоксе, если я правильно понимаю, Вирт специально ровнял всё по 4 байта для 32битного кода. GCC через pragma может заравнять что угодно, и как угодно. Но не надо. GCC тоже по умолчанию ровняет всё по 4 байта, если я не ошибаюсь.
|
Автор: | Иван Денисов [ Пятница, 20 Май, 2016 21:28 ] |
Заголовок сообщения: | Re: NEW для структур без метки (untagged) |
Еще один пример. Вот так приходится тоже делать для RenderClear. Код: (* RenderClear *)
PROCEDURE RenderClear0 (this: Renderer); BEGIN this.res := Sdl2Lin.RenderClear(this.r) END RenderClear0; PROCEDURE RenderClear1 (this: Renderer); VAR pad1: INTEGER; BEGIN this.res := Sdl2Lin.RenderClear(this.r) END RenderClear1; PROCEDURE RenderClear2 (this: Renderer); VAR pad1, pad2: INTEGER; BEGIN this.res := Sdl2Lin.RenderClear(this.r) END RenderClear2; PROCEDURE RenderClear3 (this: Renderer); VAR pad1, pad2, pad3: INTEGER; BEGIN this.res := Sdl2Lin.RenderClear(this.r) END RenderClear3; PROCEDURE (this: Renderer) RenderClear (); VAR sp: INTEGER; BEGIN CASE SYSTEM.ADR(sp) MOD 16 OF 0: RenderClear0(this) | 4: RenderClear1(this) | 8: RenderClear2(this) | 12: RenderClear3(this) END END RenderClear; |
Автор: | Иван Денисов [ Суббота, 21 Май, 2016 00:14 ] |
Заголовок сообщения: | Re: NEW для структур без метки (untagged) |
Удалось тут заменить на Код: PROCEDURE (this: Renderer) RenderClear (); VAR sp: INTEGER; BEGIN SYSTEM.GETREG(4, sp); SYSTEM.PUTREG(4, sp DIV 16 * 16 + 4); this.res := Sdl2Lin.RenderClear(this.r) END RenderClear; Системы пока не понял, но теперь буду искать закономерность. |
Автор: | Иван Денисов [ Суббота, 21 Май, 2016 10:10 ] |
Заголовок сообщения: | Re: NEW для структур без метки (untagged) |
Александр меня поправил, что так корректнее. Код: PROCEDURE (this: Renderer) RenderClear (); VAR sp: INTEGER; BEGIN SYSTEM.GETREG(4, sp); SYSTEM.PUTREG(4, sp DIV 16 * 16 - 12); this.res := Sdl2Lin.RenderClear(this.r) END RenderClear; Так работает с этой процедурой. А вот со второй не хочет, там другое число переменных в функции и любое число 0,4,8,12 не помогает пока. Разбираюсь дальше. |
Автор: | Иван Денисов [ Суббота, 21 Май, 2016 10:19 ] |
Заголовок сообщения: | Re: NEW для структур без метки (untagged) |
Код: PROCEDURE (this: Renderer) RenderClear (); VAR sp: INTEGER; BEGIN SYSTEM.GETREG(4, sp); Log.String("SP: "); Log.Int(sp); Log.Int(sp MOD 16); Log.Ln; SYSTEM.GETREG(5, sp); Log.String("FP: "); Log.Int(sp); Log.Int(sp MOD 16); Log.Ln; SYSTEM.GETREG(4, sp); SYSTEM.PUTREG(4, sp DIV 16 * 16 - 12); this.res := Sdl2Lin.RenderClear(this.r) END RenderClear; FP тоже не выровнен по 16. SP: -3332748 4 FP: -3332744 8 |
Автор: | Иван Денисов [ Суббота, 21 Май, 2016 15:34 ] |
Заголовок сообщения: | Re: NEW для структур без метки (untagged) |
Подобрал для шрифтов тоже константу N, тут она не 12, а 4. Код: PROCEDURE (f: Font) RenderUNICODE_Blended (string: ARRAY OF CHAR; color: INTEGER): Sdl2Video.Surface; VAR sp: INTEGER; c: Color; s: Sdl2CTypes.PSurface; BEGIN FillColor(color, c); SYSTEM.GETREG(4, sp); SYSTEM.PUTREG(4, sp DIV 16 * 16 - 4); s := Win.RenderUNICODE_Blended( f(Font).f, SYSTEM.VAL(Sdl2CTypes.PUint16, SYSTEM.ADR(string)), SYSTEM.VAL(Sdl2CTypes.PColor, SYSTEM.ADR(c))); RETURN Sdl2StdLin.NewSurface(s) END RenderUNICODE_Blended; Закономерность пока установить сложно. Все мои попытки поменять Kernel.Call пока не привели к успеху. Важно видимо какой у функции задается адрес (adr) при вызове в Meta, а также как то задается FP (frame pointer), а это происходит до вызова Kernel.Call, если я правильно понимаю. Пробовал в Meta ставить этот сдвиг стека перед Kernel.Call, тоже не годится. Frame Pointer пробовал менять в Kernel.Call тоже, но это ни к чему хорошему тоже не привело. Пока буду так пользоваться, подбирая параметр N. |
Автор: | Иван Денисов [ Суббота, 21 Май, 2016 21:44 ] |
Заголовок сообщения: | Re: NEW для структур без метки (untagged) |
Еще две функции пролечил таком образом и теперь вроде все работает. Код: PROCEDURE (this: Renderer) RenderFillRect (IN r: Sdl2Video.Rect); BEGIN SYSTEM.GETREG(4, sp); SYSTEM.PUTREG(4, sp DIV 16 * 16 - 8); this.res := Sdl2Lin.RenderFillRect(this.r, SYSTEM.VAL(Sdl2CTypes.PRect, SYSTEM.ADR(r))) END RenderFillRect; PROCEDURE (this: Renderer) RenderFillRects (IN r: ARRAY OF Sdl2Video.Rect; count: INTEGER); BEGIN SYSTEM.GETREG(4, sp); SYSTEM.PUTREG(4, sp DIV 16 * 16 - 4); this.res := Sdl2Lin.RenderFillRects(this.r, SYSTEM.VAL(Sdl2CTypes.PRect, SYSTEM.ADR(r)), count) END RenderFillRects; Опубликовал результаты тут: http://gitlab.molpit.org/bindings/sdl2 |
Автор: | Иван Денисов [ Пятница, 11 Август, 2017 18:06 ] |
Заголовок сообщения: | Re: NEW для структур без метки (untagged) |
Проблема решена путем модификации компилятора. За доработку компилятора искренне благодарю luowy! Он добавил поддержку флага [ccall16], который обеспечивает выравнивание стека по 16-байтной границе, как того требуют библиотеки откомпилированные GCC версии больше 4.5 (https://en.wikipedia.org/wiki/X86_calli ... ions#cdecl). Вложение: Исправление внесено в хранилище Freenix, так что новая функциональность доступна в сборках на сайте ОберТон: https://blackbox.obertone.ru/download В итоге я заменил все [ccall] в сборке Sdl2 на [ccall16], и "хаки" с ручным выравниванием стека удалил. http://comp.molpit.org/bindings/sdl2.txt Мои модели нормально компилируются и работают с новым исправлением. Александр Ширяев тоже поглядел код, предложенный Luowy, и был исправлен недочет в одном месте. Так что мы решили включить это усовершенствование компилятора в основное хранилище и сборку. Все это сильно облегчает дальнейшее развитие Блэкбокса в сторону использования SDL2 и других "выровненных" стороннних библиотек. |
Автор: | kekc_leader [ Суббота, 10 Ноябрь, 2018 18:51 ] |
Заголовок сообщения: | Re: NEW для структур без метки (untagged) |
Дополнительная информация для интересующихся данным вопросом. Тут написано, что GCC на x86 автоматически вставляет код в начало функции main, который подравнивает стек. (Человек спрашивает, что это такое и как это убрать.) Код: main: leal 4(%esp), %ecx andl $-16, %esp pushl -4(%ecx) Пояснение: «LEA is part of GCC's very clunky code to align esp by 16. It does this only in main in 32-bit code». $-16 — это 0FFFFFFF0X, соответственно Код: andl $-16, %esp снимает 4 наименее значимых бита у ESP, то есть обеспечивает истинность ESP MOD 16 = 0. А так как стек «растёт вниз», то это не приводит к потере данных.
|
Страница 4 из 4 | Часовой пояс: UTC + 3 часа |
Powered by phpBB® Forum Software © phpBB Group https://www.phpbb.com/ |