Ядро и C

Kernel architecture questions
  • хм, интересно такое "в принципе" возможно? было бы здорово если все так гладко было бы
  • turbanoff wrote:хм, интересно такое "в принципе" возможно? было бы здорово если все так гладко было бы
    Можно. И не только «в принципе», но и на практике.

    Руководство:
    В самое начало файла kernel.asm впихиваем директиву «format ELF», чтоб фасм делал объектники.
    В самый конец файла kernel.asm вписываем «rb 16». Зачем — объясню попозжее.

    Если хотим дёргать ф-ю из другого файла, всё просто и стандартно:
    Пишем extrn _foo до вызова.

    Насчёт самого вызова функции:
    FASM почему-то ругается на call _foo так: «invalid use of symbol». Вроде потому что не может определить на этапе компилирования дальности вызова. Не знаю точно.
    Приходится юзать костыли:

    Code: Select all

    push f@
    push _foo
    ret
    @@: etc.
    (нужно переписать макру ccall, чтоб она вставляла такой код, а так же код очистки стека, сама.)

    Теперь линковка:
    Нужен будет такой скрипт для линковки

    Code: Select all

    OUTPUT_FORMAT(binary)
    phys = 0x80010000;
    
    SECTIONS
    {
    	. = phys;
    	.head . : {
    		kernel.o
    	}
    	.tail . : {
    		foo.o
    	}
    }
    Под виндами я собирал всё и без описания секций, всё было нормально. А вот под линуксами оказалось, что foo.o идёт в слинкованном файле до kernel.o. И, следовательно, загрузка обламывается: ведь управление передаётся в самое начало образа ядра.

    Линкуем с этим скриптом. Ну и со всякими директивами, вроде -nostdlib, чтоб линкер не пытался потянуть в ядро libc и прочие crt0.

    Теперь зачем нужно «rb 16» в конце kernel.asm.
    В конце kernel.asm располагаются неиницилизированные глобальные переменные, которые ядро зануляет при старте. Для скорости ядро забивает переменные четырёхбайтными блоками. Т.е., если размер области глобальных переменных не кратен четырём, то ядро забьет ещё некоторое количество байт после реальной области.
    (Можно так же переписать код забивки. Пусть забивает четырёхбайтными блоками область, размер которой округлён в меньшую сторону. А хвостик можно забить байтами.
    И «rb 16» будет не нужен.)

    Вот, вобщем, и всё.

    Надеюсь, возможность разработки на С позволит ускорить разработку ядра, уменьшит число ошибок и увеличит скорость работы (кому щас захотелось написать, что код, писанный руками на асме будет быстрее кода на ЯВУ, может принять стакан лечебной эвтаназии. Щас не 80-е, компилятору лучше известно, как шедуллить инструкции для процессора, да и регистры он раскидает оптимальнее. И главное — он сделает на много порядков быстрее, чем человек.)
  • Гы. Забавно, что утверждение о том, что переход на си может увеличить скорость, находится в одном посте с методом, позволяющим эту самую скорость просадить из-за разрушения буфера пар call/ret (и вытекающим отсюда простоем декодера, вынужденного ждать, пока до ret непосредственно дойдёт управление, вместо возможности начать декодирование по сохранённому адресу из буфера). Само утверждение в таком соседстве даже комментировать необязательно :)
  • Щас не 80-е, компилятору лучше известно, как шедуллить инструкции для процессора, да и регистры он раскидает оптимальнее. И главное — он сделает на много порядков быстрее, чем человек.)
    Далеко не всегда, и далеко не все. компиляторы как правило оптимальнее обрабатывают код больших программ, но например в коде колибри часть ассемблера все равно придется указывать неоптимизируемым, вот и тогда компилятор может не то что оптимальнее сделать, он может сделать даже много медленнее - он не рассчитан на такое применение.
  • diamond wrote:Гы. Забавно, что утверждение о том, что переход на си может увеличить скорость, находится в одном посте с методом, позволяющим эту самую скорость просадить из-за разрушения буфера пар call/ret (и вытекающим отсюда простоем декодера, вынужденного ждать, пока до ret непосредственно дойдёт управление, вместо возможности начать декодирование по сохранённому адресу из буфера). Само утверждение в таком соседстве даже комментировать необязательно :)
    Гы-ы-ы. Забавно, что утверждение о каком-то разрушении буфера может серьёзно просадить скорость тормозного до невозможности ядра.
    Вряд ли кто-то может сказать, что при написании кода рассчитывал распределение регистров и команд по конвейерам.

    Да и общая убогость алгоритмов и структур данных в ядре поражает. А как баблсорт на асме не переписывай, таки ксорт будет быстрее на чём угодно. ))

    Зато умиляют пары инструкций типа

    Code: Select all

    xor [reg], [reg]
    inc/dec/not [reg]
    в коде загрузки. Который выполняется 1 раз. К тому же колибря долгое время умела грузиться только с дискеты. И такой код «оптимизации» на фоне чтения с флопика выглядит мощно.

    Вот вычитал кульхацкер в какой-то древней книжке по асму, что inc выполняется быстрее, чем add, и пошёл впиливать где можно.
    А на процах до PIV, на ядре prescott, помоему, add-таки выполнялся быстрее…

    К тому же, имхуется мне, что в

    Code: Select all

    xor [reg], [reg]
    inc/dec/not [reg]
    самая что ни на есть WAW-зависимость просматривается.

    Истинно сказал кто-то: кульхацкер (а все юзающие асм не по назначению такими и являются) оптимизирует то, что умеет, а не то, что надо.

    Прочитал где-то кульхацкер, что xor [reg], [reg] хорошо применять для быстрого обнуления регистра, навставлял где мог, и остался доволен собой.
    Вместо того, чтоб повыкинуть кучу статических массивов, которые вносят всякие нелепые ограничения на ресурсы, вроде количества процессов.
  • Колибри ОС разрабатывается на протяжении почти 10 лет (если вести истории от менуэт). Во многом, решения принятые разными разработчиками ядра в разное время носили временный характер, но исторически остались до сегодняшних дней. Колибри это все же хобби ОС, и утверждать о "убожестве", "тормознутости" и т.д. без указания участков кода и вариантов их улучшения, на этом форуме не уместны. Если используется оптимизация в стиле

    Code: Select all

    xor [reg], [reg]
    inc/dec/not [reg]
    то, как правило и если это возможно, между этими инструкциями вставляется другие команды.
  • wolf.ram
    Мне кажется прямая линковка с Асм кодом кода Си не самая лучшая идея. Можно же в виде подгружаемых модулей реализовывать. А насчет критики оптимизации ты зря. Насчет алгоритмов - да правда все, но куда деваться если изначально все не проектировалось вообще. Вот и лепим костыли, ибо переписывать все приравняется к написанию по сути нового ядра, а кому это надо? У всех дела, работа бесплатная и только для своего удовольствия.
  • wolf.ram wrote:Надеюсь, возможность разработки на С позволит ускорить разработку ядра, уменьшит число ошибок и увеличит скорость работы (кому щас захотелось написать, что код, писанный руками на асме будет быстрее кода на ЯВУ, может принять стакан лечебной эвтаназии.
    Kolibri PE?
    А кому захотелось написать, что код, писанный руками на асме будет меньше кода на ЯВУ, что может принять?

    Да людей занимающихся оптимизацией ядра единицы. Если сможете оптимизировать код, хотя бы "повыкинуть кучу статических массивов, которые вносят всякие нелепые ограничения на ресурсы, вроде количества процессов" все вам только спасибо скажут.
  • Прежде чем переходить к обсуждению утверждения "ядро тормозное", отмечу две вещи по исходному утверждению "возможность разработки на C увеличит скорость работы". Во-первых, даже если считать, что ядро действительно тормозное, первое утверждение отсюда совершенно не следует. Во-вторых, если заниматься не философствованиями, а конкретными измерениями, то ассемблер заметно выигрывает у си: http://wasm.ru/forum/viewtopic.php?pid=276576#p276576
    wolf.ram wrote:Гы-ы-ы. Забавно, что утверждение о каком-то разрушении буфера может серьёзно просадить скорость тормозного до невозможности ядра.
    Вряд ли кто-то может сказать, что при написании кода рассчитывал распределение регистров и команд по конвейерам.
    Утверждение, разумеется, просадить ничего не может. Но это так, к слову.
    Интересно отметить, что характерные отзывы о Колибри как раз наоборот подчёркивают скорость работы системы. По контексту высказывания складывается ощущение, что высказывание вызвано исключительно теоретическими соображениями типа "для оптимального кода нужно рассчитывать распределение регистров и команд по конвейерам". Поэтому небольшой ликбез. Регистры по конвейерам никто не распределяет, распределяют переменные по регистрам, и это как раз ассемблерщик делает и сам - выделить часто используемые переменные и выделить под эти часто используемые переменные конкретные регистры несложно и интуитивно делается, чтобы избежать писания лишних mov'ов. Распределение команд по конвейерам появилось, когда в процессорах появился сам конвейер, и даже тогда было средством оптимизации из разряда "ловли блох", когда все остальные оптимизации уже проведены, а это может ещё пару-тройку тактов сэкономить. С тех пор процессоры ещё поумнели и могут переупорядочивать команды (а точнее, микрооперации, на которые эти команды разбиваются) самостоятельно и выполнять их в том порядке, как им удобно. Более того, у разных процессоров разная микроархитектура, разные возможности конвейеров, так что "шедулинга инструкций", оптимального для всех процессоров, просто не может существовать.
    wolf.ram wrote:Зато умиляют пары инструкций типа
    Код:
    xor [reg], [reg]
    inc/dec/not [reg]

    в коде загрузки. Который выполняется 1 раз. К тому же колибря долгое время умела грузиться только с дискеты. И такой код «оптимизации» на фоне чтения с флопика выглядит мощно.

    Вот вычитал кульхацкер в какой-то древней книжке по асму, что inc выполняется быстрее, чем add, и пошёл впиливать где можно.
    А на процах до PIV, на ядре prescott, помоему, add-таки выполнялся быстрее…
    Факты Вы видите, а вот выводы из них почему-то не делаете. Вы же правильно заметили, что код загрузки выполняется один раз. И правильно заметили, что на фоне чтения с флопика скорость особого значения не имеет. Только отсюда Вы почему-то делаете вывод, что эти инструкции вставил кульхацкер, и приписываете ему стремление увеличить скорость, для чего Вам приходится вводить допущение, что "в какой-то древней книжке по асму" написано, "что inc выполняется быстрее, чем add". Команда inc не может выполняться быстрее, чем add (хотя, как Вы правильно заметили, на некоторых процессорах бывает медленнее), и никогда не выполнялась быстрее. Более того, очевидно, что вместо xor eax,eax/inc eax вполне можно написать mov eax,1, что будет заведомо быстрее и даже потребует меньше нажатий на клавиши для набора. Ну так сделайте из всего этого логический вывод! Даю подсказку: машинный код пары команд xor eax,eax/inc eax в 32-битном режиме есть 33 C0 40 (или, что эквивалентно, 31 C0 40), машинный код команды mov eax,1 есть B8 01 00 00 00.
    wolf.ram wrote:Вместо того, чтоб повыкинуть кучу статических массивов, которые вносят всякие нелепые ограничения на ресурсы, вроде количества процессов.
    Не возражаю против утверждения, что в ядре присутствует куча статических массивов, не возражаю против того, что этого можно было бы избежать и даже следовало бы избежать. Но должен отметить две вещи: во-первых, использование статических массивов вместо динамических списков ускоряет ядро (за счёт меньшего числа разыменований указателей для доступа к элементам), а не замедляет; во-вторых, это вообще никак не связано со сравнением ассемблера и си.
  • Mario wrote:wolf.ram
    Мне кажется прямая линковка с Асм кодом кода Си не самая лучшая идея. Можно же в виде подгружаемых модулей реализовывать.
    Ну я просто дёргал код из обработчика прерывания от таймера. Так что модулем тут никак.
  • Asper wrote:Kolibri PE?
    Собрать не смог. Не помню уже, почему не собиралось, давно пробовал.
    Asper wrote:А кому захотелось написать, что код, писанный руками на асме будет меньше кода на ЯВУ, что может принять?
    Ну и будет меньше, и дальше что? Меньше != быстрее.
    Asper wrote:Да людей занимающихся оптимизацией ядра единицы.
    А как они оптимизируют без профайлера? Или опять оптимизируют, что могут, а не то, что нужно?
  • <Lrz> wrote:Колибри ОС разрабатывается на протяжении почти 10 лет (если вести истории от менуэт). Во многом, решения принятые разными разработчиками ядра в разное время носили временный характер, но исторически остались до сегодняшних дней.
    Мда, вот что значит писать без чёткого плана, в стиле «а пока и так сойдёт».
    <Lrz> wrote:Если используется оптимизация в стиле

    Code: Select all

    xor [reg], [reg]
    inc/dec/not [reg]
    то, как правило и если это возможно, между этими инструкциями вставляется другие команды.
    Пока не встречал такого.
  • diamond wrote:Прежде чем переходить к обсуждению утверждения "ядро тормозное", отмечу две вещи по исходному утверждению "возможность разработки на C увеличит скорость работы". Во-первых, даже если считать, что ядро действительно тормозное, первое утверждение отсюда совершенно не следует.
    Ну, в принципе, правильно. Тормозной асмовый код C не ускорит.
    diamond wrote:Во-вторых, если заниматься не философствованиями, а конкретными измерениями, то ассемблер заметно выигрывает у си: http://wasm.ru/forum/viewtopic.php?pid=276576#p276576
    А если нормальный компилятор взять?
    diamond wrote:Интересно отметить, что характерные отзывы о Колибри как раз наоборот подчёркивают скорость работы системы.
    Практически голой системы, наверное.
    Кстати, ГУЙ у колибри таки заметно тормозит. XP на виртуалке поотзывчивей колибри будет.
    diamond wrote:Поэтому небольшой ликбез. Регистры по конвейерам никто не распределяет, распределяют переменные по регистрам
    Я второй раз не стал слово «распределяет» вставлять. Думал, и так ясно будет, что я имел в виду.
    diamond wrote:и это как раз ассемблерщик делает и сам - выделить часто используемые переменные и выделить под эти часто используемые переменные конкретные регистры несложно и интуитивно делается
    А теперь дай вменяемый ответ на вопрос: зачем самому делать то, что делает компилятор на порядки быстрее?
    diamond wrote:С тех пор процессоры ещё поумнели и могут переупорядочивать команды (а точнее, микрооперации, на которые эти команды разбиваются) самостоятельно и выполнять их в том порядке, как им удобно.
    Только и при упорядочивании, и при подмене регистров остаются ситуации зависимостей.
    diamond wrote:Более того, у разных процессоров разная микроархитектура, разные возможности конвейеров, так что "шедулинга инструкций", оптимального для всех процессоров, просто не может существовать.
    По крайней мере перекомпилить можно с оптимизацией под другую модель )))
    И даже, при должном качестве кода, под другую архитектуру. Вот тут ты со своим асмокодом ничего не сможешь в ответ предложить (кроме эмуляции).
    diamond wrote:Даю подсказку: машинный код пары команд xor eax,eax/inc eax в 32-битном режиме есть 33 C0 40 (или, что эквивалентно, 31 C0 40), машинный код команды mov eax,1 есть B8 01 00 00 00.
    Ну да. На 2 байта больше. Там с десяток мест такого кода. На целых 20 байт больше будет…
    Есть смысл сокращать код на 20 байт? Даю подсказку: чтение идёт посекторно.
    diamond wrote:во-первых, использование статических массивов вместо динамических списков ускоряет ядро
    Кроме массивов и списков есть ещё, например, различные деревья. Которые могут ускорить поиск.
    Конечно, можно сказать, что массивы небольшие и поиск/добавление занимают не так уж много времени, возможно, даже меньше чем этого времени уходило бы на, скажем, поворот красно-чорного дерева.
    Но цена этому — ограничение количества тех или иных структур.
    diamond wrote:во-вторых, это вообще никак не связано со сравнением ассемблера и си.
    На C было бы легче это написать. И написали бы, если бы C юзали.
  • diamond wrote:Гы. Забавно, что утверждение о том, что переход на си может увеличить скорость, находится в одном посте с методом, позволяющим эту самую скорость просадить из-за разрушения буфера пар call/ret (и вытекающим отсюда простоем декодера, вынужденного ждать, пока до ret непосредственно дойдёт управление, вместо возможности начать декодирование по сохранённому адресу из буфера). Само утверждение в таком соседстве даже комментировать необязательно :)
    Твой пост теперь не актуален )))

    Чтоб избежать ошибки «invalid use of symbol» достаточно после format ELF объявить секцию, например, section '.asmcode'. Тогда на call никакой ругани нет, можно его смело юзать.
    И скрипт линкера упрощается. Вместо того, чтоб указывать ядро в первой секции, а во вторую лепить спейсок остальных объектных файлов, достаточно в одной секции прописать первой вставку секции .asmcode, а за ней уже вставлять .text, .data и проч.
  • Who is online

    Users browsing this forum: No registered users and 7 guests