• Как работают исключения?

    jcmvbkbc
    @jcmvbkbc
    "I'm here to consult you" © Dogbert
    Может ли кто нибудь объяснить на низком уровне, пошагово, то как работают исключения в с++?

    Вот описание части Itanium ABI связанной с раскруткой стека:
    https://itanium-cxx-abi.github.io/cxx-abi/abi-eh.html

    ABI процессоров других архитектур устроены в этом месте точно так же.

    Вот подробное описание структур, используемых при раскрутке стека в коде генерируемом gcc:
    www.airs.com/blog/archives/460
    www.airs.com/blog/archives/464

    Документы по ссылкам достаточно сложны для восприятия. Для облегчения понимания можно откомпилировать простой С++ код выбрасывающий и ловящий исключение и найти в нем части описанные в первом документе.
    Например
    void e_destructor();
    void s_destructor();
    
    struct E {
            int code;
    
            E(int c): code(c)
            {
            }
            ~E()
            {
                    e_destructor();
            }
    };
    
    struct S {
            ~S()
            {
                    s_destructor();
            }
    };
    
    void f(int v)
    {
            throw E(v);
    }
    
    int g(void (*p)(int v), int v)
    {
            try {
                    struct S s;
                    p(v);
            } catch(struct E e) {
                    return e.code;
            } catch (int i) {
                    return i;
            } catch (...) {
                    throw;
            }
            return 0;
    }

    после g++ -O2 -S превращается в следующие фрагменты:
    функция f:
    _Z1fi:
    .LFB9:
            .cfi_startproc
            pushq   %rbx
            .cfi_def_cfa_offset 16
            .cfi_offset 3, -16
            movl    %edi, %ebx
            movl    $4, %edi
            call    __cxa_allocate_exception
            movl    $_ZN1ED1Ev, %edx
            movl    %ebx, (%rax)  <---- инициализация E::code
            movl    $_ZTI1E, %esi
            movq    %rax, %rdi
            call    __cxa_throw
            .cfi_endproc

    Здесь видны вызовы __cxa_allocate_exception, конструктора объекта класса E и __cxa_throw
    функция g:
    _Z1gPFviEi:
    .LFB10:
            .cfi_startproc
            .cfi_personality 0x3,__gxx_personality_v0
            .cfi_lsda 0x3,.LLSDA10
            pushq   %rbp
            .cfi_def_cfa_offset 16
            .cfi_offset 6, -16
            pushq   %rbx
            .cfi_def_cfa_offset 24
            .cfi_offset 3, -24
            movq    %rdi, %rax
            movl    %esi, %edi
            subq    $8, %rsp
            .cfi_def_cfa_offset 32
    .LEHB0:
            call    *%rax  <--- вызов функции по указателю
    .LEHE0:
    .LEHB1:
            call    _Z12s_destructorv  <--- вызов деструктора объекта s при нормальном выходе из блока try
    .LEHE1:
            xorl    %eax, %eax
    .L17:
            addq    $8, %rsp
            .cfi_remember_state
            .cfi_def_cfa_offset 24
            popq    %rbx
            .cfi_def_cfa_offset 16
            popq    %rbp
            .cfi_def_cfa_offset 8
            ret

    Хвост с обработчиками исключений:
    .L13:
            .cfi_restore_state
            movq    %rdx, %rbx
            movq    %rax, %rbp
            call    _Z12s_destructorv
            movq    %rbx, %rdx
    .L6:
            cmpq    $1, %rdx
            je      .L8
            cmpq    $2, %rdx
            jne     .L22
            movq    %rbp, %rdi
            call    __cxa_begin_catch
            movl    (%rax), %ebx
            call    __cxa_end_catch
            movl    %ebx, %eax
            jmp     .L17
    .L14:
            movq    %rax, %rbp
            jmp     .L6
    .L22:
            movq    %rbp, %rdi
            call    __cxa_begin_catch
    .LEHB2:
            call    __cxa_rethrow
    .LEHE2:
    .L8:
            movq    %rbp, %rdi
            call    __cxa_get_exception_ptr
            movq    %rbp, %rdi
            movl    (%rax), %ebx
            call    __cxa_begin_catch
    .LEHB3:
            call    _Z12e_destructorv
    .LEHE3:
    .LEHB4:
            call    __cxa_end_catch
    .LEHE4:
            movl    %ebx, %eax
            jmp     .L17
    .L16:
            movq    %rax, %rbx
            call    __cxa_end_catch
            movq    %rbx, %rdi
    .LEHB5:
            call    _Unwind_Resume
    .LEHE5:
    .L15:
            movq    %rax, %rbx
            call    __cxa_end_catch
            movq    %rbx, %rdi
    .LEHB6:
            call    _Unwind_Resume
    .LEHE6:
            .cfi_endproc

    Здесь видны вызовы __cxa_begin_catch и __cxa_end_catch, __cxa_rethrow повторно выбрасывающий пойманное исключение, __cxa_get_exception_ptr и _Unwind_Resume, вызываемый если блок catch не ловит это исключение.

    Дальше идёт структура LSDA описанная в третьем документе.

    Сама раскрутка стека в этом коде отсутствует. Она выполняется следующим кодом libgcc: фаза 1 и фаза 2.
    Ответ написан
    Комментировать
  • Как задать размер массива через аргументы функции?

    jcmvbkbc
    @jcmvbkbc
    "I'm here to consult you" © Dogbert
    Но не дает задавать так размеры ("m и n должны иметь константное значение). Как тогда это можно сделать?

    С99 позволяет. Используйте уже С99, 18 лет прошло с момента его принятия.
    Связанный вопрос/ответ про передачу многомерного массива прямо через аргументы функции: Как засунуть n — мерный массив в аргумент функции?
    Ответ написан
    Комментировать
  • Как правильно сформировать заголовок Data в TCP с помощью nc?

    jcmvbkbc
    @jcmvbkbc
    "I'm here to consult you" © Dogbert
    echo '0000: 02 04 00 40' | xxd -g 1 -r | nc localhost 42
    Ответ написан
  • Почему не работает сортировка пузырьком в массиве?

    jcmvbkbc
    @jcmvbkbc
    "I'm here to consult you" © Dogbert
    Почему не работает сравнение среднего балла студента: (s[i].getSredne < s[j].getSredne)?

    Потому что это не вызов функции, а что-то другое. Правильно будет
    s[i].getSredne() < s[j].getSredne()
    Ответ написан
    7 комментариев
  • Как обработать нажатие комбинации клавиш: CTRL + ПКМ, ALT + ПКМ (TASM+WINAPI)?

    jcmvbkbc
    @jcmvbkbc
    "I'm here to consult you" © Dogbert
    Обработать WM_RBUTTONDOWN, состояние CTRL можно взять из wparam. За состоянием ALT придётся лезть в GetKeyState.
    Ответ написан
  • В чем разница между syscall setreuid в C/C++ и asm?

    jcmvbkbc
    @jcmvbkbc
    "I'm here to consult you" © Dogbert
    в чем проблема то тогда

    а по ходу нельзя из elf64 вызывать системные вызовы через int 0x80. Так что либо замени int 0x80 на syscall (и, кстати, _NR_exit для x86_64 -- это 60), либо используй nasm -static -f elf32 и ld -m elf_i386 (и тогда _NR_setreuid будет 70).
    Ответ написан
    3 комментария
  • Как можно оптимизировать алгоритм сокращения дроби?

    jcmvbkbc
    @jcmvbkbc
    "I'm here to consult you" © Dogbert
    Классическое решение -- поиск НОД алгоритмом Евклида.
    Ответ написан
    Комментировать
  • Как встроить в OS компилятор C++?

    jcmvbkbc
    @jcmvbkbc
    "I'm here to consult you" © Dogbert
    Вам туда: wiki.osdev.org
    Ответ написан
    1 комментарий
  • Какие оптимизации используются в языках С и С++?

    jcmvbkbc
    @jcmvbkbc
    "I'm here to consult you" © Dogbert
    Мне не нужен полный список низкоуровневых оптимизаций, таких как размещение переменных в регистры, а нужны такие, как вычисление константных выражений или раскрытие простых методов (get/set). Какие оптимизации в C и C++ различаются? В частности, рассматриваю gcc.

    gcc -Q --help=optimizers выведет список всех включенных в настоящий момент (другими опциями командной строки) оптимизаций. Что каждый из -f* ключей означает можно посмотреть тут: https://gcc.gnu.org/onlinedocs/gcc/Optimize-Option...
    Ответ написан
    1 комментарий
  • Как добавить ключ в configure и подключить дополнительные пакеты?

    jcmvbkbc
    @jcmvbkbc
    "I'm here to consult you" © Dogbert
    Сделал ровно то, что вы описали ( https://gist.github.com/jcmvbkbc/f8d64eadb76b83ecf... ), всё работает.
    Вопросы:
    - Makefile.foo.include -- это файл того же вида, что и Makefile.am, верно?
    - autoreconf выполнили после редактирования configure.ac и Makefile.am?
    Ответ написан
  • В чём разница команд remote?

    jcmvbkbc
    @jcmvbkbc
    "I'm here to consult you" © Dogbert
    Непонятно почему именно так, почему послеremote add git не может себе в конфиг этот репозиторий как удалённый внести?

    Он внёс, вы просто неправильно вызвали git pull: git pull без дополнительных аргументов будет тянуть из remote по имени origin. Надо было написать git pull pseudo.
    Ответ написан
    Комментировать
  • Как определять новые методы в производных классах?

    jcmvbkbc
    @jcmvbkbc
    "I'm here to consult you" © Dogbert
    Но согласно общей концепции, у обычного сотрудника не может быть подчиненных. Значит метод getListEmployee() не нужен родительскому классу Person.


    Нужен метод классу или не нужен зависит от его ответственности. Если вы собираетесь использовать Person для работы с сотрудниками любого типа (кстати, плохое название класса, не отражает сути), а у каких-то сотрудников в принципе могут быть подчинённые, то какой-то метод для этого должен присутствовать в Person. Удобство использования этого интерфейса будет зависеть от реализации.

    Так, например, можно добавить метод getListEmployee(), возвращающий список подчинённых (кстати, опять плохое название метода, не отражает сути), а реализация этого метода в классе Employee может возвращать пустой список.
    Или можно добавить метод getSubordinateEnumerator(), возвращающий интерфейс перечисления подчинённых, а в классе Employee возвращать из этого метода NULL.

    Если же вы не собираетесь использовать единый интерфейс Person, а, например, будете пытаться привести Person* к типу Employee* или Manager* с помощью dynamic_cast, то метод в Person не нужен.
    Ответ написан
    4 комментария
  • Как передавать UDP пакеты через определенный интерфейс?

    jcmvbkbc
    @jcmvbkbc
    "I'm here to consult you" © Dogbert
    пакет должен уходить в eth1, "пройти" через оборудование и попасть в eth2. Проблема в том, что система не отправляет пакеты в интерфейс и далее в оборудование, а сразу "получает" их на eth2.

    Всё верно, без фокусов эта схема работать не будет.
    Возможные фокусы:
    - посылать пакет через RAW сокет, чтобы маршрутизатор ядра не вмешивался;
    - посылать пакет не на адрес eth2, а на другой адрес. Править адрес назначения с помощью iptables, в таблице mangle, в цепочке POSTROUTING.
    Ответ написан
    1 комментарий
  • Какой будет путь к содержимому распакованной папки?

    jcmvbkbc
    @jcmvbkbc
    "I'm here to consult you" © Dogbert
    /home/user/important/important
    Но ты забыл спросить "почему".
    Ответ написан
  • Как версионируются пакеты в linux?

    jcmvbkbc
    @jcmvbkbc
    "I'm here to consult you" © Dogbert
    Или все-таки нельзя ставить два пакета разных версий?

    Нельзя установить одновременно несколько версий одного и того же пакета.
    Если требуется иметь одновременно несколько версий программы/библиотеки, их оформляют как разные пакеты. Версия программы/библиотеки при этом часто используется как часть имени пакета.
    Например, у меня установлены одновременно gcc-4.8 и gcc-4.9:
    $ dpkg -l 'gcc-4.[89]' | sort
    +++-==============-============-============-=================================
    Desired=Unknown/Install/Remove/Purge/Hold
    ii  gcc-4.8        4.8.4-1      amd64        GNU C compiler
    ii  gcc-4.9        4.9.2-10     amd64        GNU C compiler
    | Status=Not/Inst/Conf-files/Unpacked/halF-conf/Half-inst/trig-aWait/Trig-pend
    |/ Err?=(none)/Reinst-required (Status,Err: uppercase=bad)
    ||/ Name           Version      Architecture Description

    Имена пакетов здесь: gcc-4.8 и gcc-4.9. По файлам они нигде не пересекаются.
    Ответ написан
    Комментировать
  • Почему после "umask u=rwx,g=rwx,o=" создаваемые файлы не имеют разрешения на запуск?

    jcmvbkbc
    @jcmvbkbc
    "I'm here to consult you" © Dogbert
    touch testfile

    а где заветное и ожидаемое -rwx-rwx--- ???

    С помощью strace можно увидеть, что touch открывает файл с параметром mode = 0666, поэтому x там неоткуда взяться:
    $ strace -v -e open touch test
    open("test", O_WRONLY|O_CREAT|O_NOCTTY|O_NONBLOCK, 0666) = 3
    Ответ написан
  • Можно ли в Linux x64 собрать драйвер (модуль ядра) для Linux x86?

    jcmvbkbc
    @jcmvbkbc
    "I'm here to consult you" © Dogbert
    Всё что вам нужно, чтобы собрать модуль для ядра любой архитектуры любой версии -- это компилятор для этой архитектуры, исходники ядра и .config для этого ядра.
    Шаги такие:
    - распаковать/вычекнуть исходники ядра нужной версии
    - создать и сконфигурировать каталог сборки ядра: создать каталог, скопировать в него .config, выполнить
    make -C <каталог исходников ядра> \
    O=<каталог сборки ядра> \
    ARCH=<целевая архитектура> \
    CROSS_COMPILE=<префикс кросс-компилятора> \
    silentoldconfig

    - собрать ядро:
    make -C <каталог исходников ядра> \
    O=<каталог сборки ядра> \
    ARCH=<целевая архитектура> \
    CROSS_COMPILE=<префикс кросс-компилятора> \
    vmlinux

    - собрать модуль используя созданный на предыдущем шаге каталог:
    make -C <каталог сборки ядра> \
    M=<каталог исходников модуля> \
    ARCH=<целевая архитектура> \
    CROSS_COMPILE=<префикс кросс-компилятора> \
    modules


    CROSS_COMPILE можно опустить, если нужно использовать хостовый компилятор. Для x86 ARCH=x86
    Ответ написан
    1 комментарий
  • Почему не работает sscanf?

    jcmvbkbc
    @jcmvbkbc
    "I'm here to consult you" © Dogbert
    Чтобы работало с приведённой строкой, формат должен быть таким:
    sscanf(mycharp, "%[^'*']*,%[','^]", o, s);
    Исходный формат не работает, потому что обработка %[^'*'] остановится на входном символе *, и так там и останется, потому что последующая часть форматной строки не поглощает этот символ.
    Кроме того, вы, мне кажется, понаставили лишних апострофов внутри квадратных скобок. В форматной строке они интерпретируются буквально, т.е. формат "%[^'*']" означает "символы, кроме апострофа, звёздочки или апострофа". Вот так тоже должно работать:
    sscanf(mycharp, "%[^*]*,%[,^]", o, s);
    Ответ написан
    3 комментария
  • Как узнать MINOR номер устройства в современном linux в режиме ядра?

    jcmvbkbc
    @jcmvbkbc
    "I'm here to consult you" © Dogbert
    filp->f_path.dentry->d_inode->i_rdev вместо filp->f_dentry->d_inode->i_rdev
    Ответ написан