Pull to refresh
151
0
Max Filippov @jcmvbkbc

low level freak

Send message
Ни Linux, и софт GNU (вроде весь) не разрабатывается на Github.

Однако и gentoo/gentoo — это лишь зеркало. Чем зеркало gentoo лучше зеркала linux (torvalds/linux) или gcc (gcc-mirror/gcc)?
int c = Div(arr[idx++], arr[idx]);

Здесь по-прежнему есть неопределённое поведение, поскольку выражение не удовлетворяет второй части того же самого требования стандартов C99 6.5:2/C++98 5:4:

Between the previous and next sequence point an object shall have its stored value modified at most once by the evaluation of an expression. Furthermore, the prior value shall be read only to determine the value to be stored.
Лучше (точнее, полнее) было бы просто перевести страницу на cppreference

cppreference, конечно, популярный ресурс, но всё-таки это просто wiki в интернете. Лучше использовать стандарт.
int c = Div(arr[idx++], arr[idx++]);

В этой строке — неопределённое поведение, поскольку idx модифицируется дважды между точками следования. Выбор не между Div(0, 1) и Div(1, 0), а между запуском ядерных ракет и пробуждением кт-ху.
int a,b,c;
a=b=0;
c = a+++b;
printf(«Value a=%d\n», a);

В зависимости от вида компилятора либо a==1, b==0, либо a==0, b==1.

Эта программа не содержит ничего из описанного в статье и в результате её выполнения a всегда равно 1. Выражение a+++b трактуется компилятором соответствующим стандарту как (a++) + b. В С99 это описано в пункте стандарта 6.4, в С++98 — в пункте 2.4:3.
output/target… output/host… output/build… output/image...

А ещё Makefile понимает параметр O=<путь к корневому каталогу сбоки> с помощью которого можно сборку вести в произвольном месте, в том числе за пределами buildroot.
Что я и делаю без этих хлопот…

Я не сомневаюсь. Мой комментарий был о
Данную функцию невозможно написать на языке Си
.
Как найти точку входа в задачу?

Есть варианты. Один — руками заполнить jmp_buf в InitTask. Для этого надо знать его структуру. Другой — в InitTask сделать что-то такое:

static void InitTask1(jmp_buf *buf, void (*TaskPointer)(void), unsigned long stack)
{
    set_stack_pointer(stack); // установить указатель стека созданной задачи
    if (setjmp(TaskList[TaskNum].context) == 0) {
        longjmp(*buf, 1);
    } else {
        TaskPointer();
        KillTask();
    }
}

void InitTask(void (*TaskPointer)(void), unsigned long stack)
{
    jmp_buf buf;
    if (setjmp(buf) == 0) {
        InitTask1(&buf, TaskPointer, stack);
    }
}


Возможно лучше сделать это через третью промежуточную функцию на ассемблере, которая только и делает, что устанавливает указатель стека.
Данную функцию невозможно написать на языке Си, так алгоритм ее работы полностью разрушает логику языка.

Да ладно, на раз такая функция пишется на чистом С, без ассемблера и без фаз луны:

void Sleep(unsigned long ms)
{
    TaskList[TaskNum].TaskSleep = ms;
    if (setjmp(TaskList[TaskNum].context) == 0)
    {
        while(1)
        {
            ....
            if(TaskList[TaskNum].TaskSleep==0)
                longjmp(TaskList[TaskNum].context, 1);
            ...
    }
}
С помощью целых чисел мы можем создать вещественные

Мне кажется, что из этой фразы следует эквивалентность множеств целых и вещественных чисел, что, как известно, неверно.
как в Л действительно реализуется параметризация драйвера


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


По какой-то странной причине встречается такая ошибка у разработчиков (вот я точно по первому времени её совершал, но не помню, по какой причине) — отождествление «драйвера» и «устройства». И, соответственно, попытки параметризовать драйвер параметрами устройства. В мире, где в системе любое физическое устройство присутствует в единственном экземпляре это не имеет значения. Однако, такие драйвера имеют существенные проблемы при необходимости управялть двумя однотипными устройствами. Поэтому параметры драйвера в современных линуксах встречаются всё реже и реже, а устройства параметризуются через Device Tree, таблицы ACPI или через platform data.
я предпочитаю барьеры атомикам

Звучит как «я предпочитаю тёплое мягкому»: одних только барьеров недостаточно для реализации атомарных изменений памяти, сами по себе атомики не дают гарантий упорядочивания других обращений к памяти.
Данное поведение переменной можно реализовать при помощи следующей конструкции:

volatile int Counter = 0;
Counter = (++Counter) % (Max+1);


и именно такой код мы можем видеть в множестве (то есть весьма часто) случаев. Что тут неправильного

Неопределённое поведение, школьный пример.
Ну и напоследок — как выделить младший бит числа (не знаю, зачем это может потребоваться, но вдруг пригодится)
define LowerBit(N) ((((N) — 1) ^ (N)) & (N)).


Для этого есть более короткая и понятная запись: #define LowerBit(N) (-(N) & (N))
Синхронизация с другой веткой

Можно сделать проще, командами checkout, merge и branch:
$ git checkout target -b merge      # сделать ветку merge из целевой ветки target
$ git merge -s ours source          # смёржить в ветку merge исходную ветку source
                                    # игнорируя её содержимое
$ git branch -d source              # удалить ветку source
$ git branch -m source              # переименовать ветку merge в source
Да, да:
fireman — firefighter
mailman — mailfighter
fisherman — fisherfighter
garbageman — garbagefighter
snowman — snowfighter
один из авторитетных разработчиков Яркко Саккинен

Авторитетных?
$ git log --author='Jarkko Sakkinen' --oneline | wc -l
134

Авторитетные — это те, что сказали ему «не майся дурью».
Ну как?
Какая-то perlовая каша…

Это же rot13.
ядро x86_64 запускается в файле ядра arch/x86/kernel/head_64.S, где мы найдем функцию сборки start_cpu0() и код, который явно создает стек и распаковывает zImage перед вызовом функции x86_64 start_kernel().

Всё смешалось в этом предложении. Ссылка указывает в arch/x86/boot/compressed/head_64.S, а в тексте — arch/x86/kernel/head_64.S. Это разные файлы, работающие в разное время. Первый работает сначала, он выполняет распаковку vmlinux. Он не является частью vmlinux, а добавляется в bzImage вместе с упакованным vmlinux. Второй является частью vmlinux. В нём находится код, выполняемый всеми процессорами при старте. start_cpu0 находится именно в нём.

Information

Rating
Does not participate
Location
Fremont, California, США
Registered
Activity