1. Си / Говнокод #25449

    0

    1. 1
    #define BSWAP16(x) ( (uint16_t)(((uint32_t)x)*(1 | 1 << 16) >> 8) )

    Запостил: j123123, 15 Марта 2019

    Комментарии (141) RSS

    • #define BSWAP16(x) (uint16_t)( (uint16_t)(x) * (1 | 1 << 16) >> 8)
      Ответить
      • На платформе с 16-битным интом не сработает, в отличие от оригинала.
        Ответить
        • А если в оригинал сунут число > 65536?
          Ответить
        • Разве на платформе с 16-битным интом оно не сломается еще на стадии (1 | 1 << 16) в том числе и на оригинале?

          Надо наверно так, чтоб уж наверняка:
          #define BSWAP16(x) (uint16_t)( (uint16_t)(x) * (1ULL | 1ULL << 16ULL) >> 8ULL)
          Ответить
          • По-моему 0x00010001 нагляднее этих сдвигов будет.
            Ответить
        • На платформе с 16-битным интом нету uint32_t
          Ответить
          • Почему? На платформах с 32-битным интом sizeof(long long) * CHAR_BIT может быть (и чаще всего так и есть) равным 64. Аналогично, на платформах с 16-битным интом uint32_t скорее всего будет синонимом unsigned long long.
            Ответить
            • потому что какие есть платформы с 16ти битным интом кроме борланд си?
              Ответить
              • Детали реализации меня не волнуют.
                Ответить
              • Watcom C.

                По крайней мере, в Open Watcom уже есть <stdint.h>.

                У x86 есть несколько инструкций для 32-битных чисел, они используют пару регистров (DX и AX, например).
                Ответить
                • нопример?
                  Ответить
                  • idiv, div, imul, mul
                    Ответить
                    • версии с 32х битными операндами появились в 286 или даже 386
                      в 8086 их не было
                      Ответить
                      • С парой регистров DX:AX всегда были.
                        Ответить
                        • а если вот я сейчас проверю что будет?
                          Ответить
                          • http://gabrielececchetti.it/Teaching/CalcolatoriElettronici/Docs/i8086_instruction_set.pdf
                            см. инструкции div, mul
                            Ответить
                            • Почему браузер в заголовке этой ссылки пишет «file://H:\Apps\devel\emu8086\documentation\8086 _instruction_set»?
                              Ответить
                              • Этот заголовок пишет не браузер, а плагин pdf.

                                Потому что автор оставил такие метаданные в pdf-файле. Он ещё написа́л, что автора зовут gabriele.
                                Ответить
                  • У MUL произведение 32-битное, у DIV делимое 32-битное.

                    Я ещё открыл для себя давно забытую инструкцию SHLD: сдвинуть содержимое регистра на N позиций влево, вдвинув в освободившиеся позиции биты из другого регистра. Есть аналогичная инструкция SHRD.

                    А ещё в плавпитухе есть 32-битное и 64-битное целое.
                    Ответить
                    • > в плавпитухе
                      Но как с целым-то с ним оперировать не получится.
                      Ответить
                      • Да, там всё через жопу: загружать в питушиный стек из оперативки через FILD, арифметика через FIADD, FISUB, FIMUL, FIDIV, FICOM, сохранение в оперативке из питушиного стека через FIST (кулак, ліл). Нужно ещё помнить, что в это же время нельзя работать с «много средства массовой информации удлинениями».

                        Но снимок в оперативке, сделанный инструкцией КУЛАК, выглядит так же, как обычное целое число.
                        Ответить
                        • Именнопо этому я за софтварную эмуляцию FPU
                          Ответить
                          • Для тебя много средства массовой информации удлинения важнее?
                            Ответить
                            • Не пониимаю как это связано с мягкими фракциями парящей точки модуля.

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

                              Кажется это исправили в струящихся одна коммнда -- много сведений удлиненийя
                              Ответить
      • #define BSWAP16(x) (x ^ (uint16_t)(x << 8 | x >> 8) ^ x)
        Ответить
    • : BSWAP16  ( u -- u )
          BASE @ >R  HEX
          S" FFFF AND 00010001 * 8 RSHIFT FFFF AND" EVALUATE
          R> BASE !
      ; IMMEDIATE
      Работает и в режиме компиляции (как макрос) и в режиме интерпретации.

      https://ideone.com/1KiivR
      Ответить
    • Байтоёбство без побитовых операций:
      #define BSWAP16(x) ({union{uint16_t u16; uint8_t u8[2];} t = {.u16 = x}; (union{uint16_t u16; uint8_t u8[2];}){.u8 = {t.u8[1], t.u8[0]}}.u16;})
      Ответить
    • ror ax, 8
      Именно поэтому я за "assembler".
      Ответить
      • rev16 r0, r0
        Именно поэтому я за "ARM".
        Ответить
      • xchg ah, al
        Ответить
        • Это в x86 валидная инструкция? О_о
          Ответить
          • Вполне
            Ответить
          • А что не так? ah, al, bh, bl, ch, cl, dh, dl в некоторых инструкциях могут использоваться как самостоятельные регистры.

            Есть инструкция xchg, ожидающая восьмибитные данные. Аргументами могут выступать два восьмибитных регистра либо восьмибитный регистр и указатель на память.
            Ответить
          • Ещё как, у XCHG есть несколько версий: однобайтовая с регисторм AX/EAX (КОП 90-9F), и с батом MOD/RM (КОП 86 -- размер операнда байт, 87 -- WORD/DWORD), что рождает кучу 2-хбайтовых NOP'ов типа XCHG AH, AH XCHG BX, BX и т.п. К сожалению XCHG REG, REG не попадает в множество ASCII :(
            Ответить
            • Зато XOR и SUB попадают. Можно эмулировать XCHG пачкой ксоров или вычитаний.
              Ответить
              • Во множество ASCII-кодов попадают только значения «регистр-память» байта mod R/M. Кобенации «регистр-регистр» за пределами ASCII-кодов.
                Ответить
                • Придумал, как обменять значения ah и al в ascii-кодах.
                  temp equ [bx+40h] ; Произвольный адрес в памяти.
                  ; Значение этой ячейки потом восстановится.
                  xor ah, temp; [email protected] ; в ah теперь ah XOR temp
                  xor temp, al; [email protected] ; в temp теперь temp XOR ah XOR al
                  xor al, temp; [email protected] ; в al теперь temp xor ah
                  xor al, temp; [email protected] ; в al теперь старое значение ah
                  xor ah, temp; [email protected] ; в ah теперь temp XOR al
                  xor temp, ah; [email protected] ; в ah теперь старое значение al
                  xor temp, al; [email protected] ; в temp теперь старое значение temp

                  Итого: [email protected]@[email protected]@[email protected]@[email protected]
                  21 байт. Длинновато вышло, зато в ASCII-кодах.
                  Ответить
                  • Ты же не будешь отрицать, что ты поехавший?
                    Ответить
                    • Братишка, давай я насру в уголочке в ASCII-кодах, программисты слетятся, тут мы их и прихлопнем?
                      Ответить
                  • Как ты это делаешь? Ты помнишь заизусть какие машинные коды соответствуют какой команде?
                    Ответить
                    • У меня шпаргалка есть:
                      http://govnokod.ru/15764#comment419684
                      Ответить
                      • Как ты понял, что, например, "@", соответствует именно "AX, [BX+SI+d8]"?
                        Ответить
                        • У меня тут @ —– это вообще произвольная константа. Вместо неё можно использовать любой октет, только во всей программе один и тот же.

                          [email protected] –— это ah, [bx+40h]
                          [email protected] –— это al, [bx+40h]
                          Ответить
                        • Или ты про материал по ссылке? Ну так mod-R/M можно собрать самому по битам, а для тупых даже опубликованы готовые сетки значений mod-R/M и s-i-b:
                          http://www.club155.ru/x86cmdformats-modrm
                          Ответить
                    • Тут самое сложное –— не запутаться, изобретая схему обмена значений. Ещё важно было не забыть восстановить значение ни в чём не повинной переменной, которое мы временно портили.
                      Ответить
                  • 5 байт:
                    PPDXD
                    push ax
                    push ax
                    inc sp
                    pop ax
                    inc sp
                    Ответить
                    • Ты реально аццкий сотона!
                      Ответить
                    • Твоим методом также можно вращать регистры BP, SI, DI, для которых у x86 не было половинок (bpl, sil, dil появились только у x86-64 в длинном режиме, а bph, sih, dih до сих пор не придумали).
                      Ответить
                      • Так можно было бы ещё и числа по регисрам сдвигать:
                        PUSHA
                        PUSH (какой там? AX?)
                        ;INC SP если надо сдвинуть на байт
                        POPA
                        но SP тоже сдвигается, а в старом стеке остаётся число :(
                        Ответить
                        • Да, жаль, что PUSHA и POPA захватывают SP, а то бы легко было эмулировать SIMD.

                          А так придётся SP где-то ещё сохранять, а потом восстанавливать.
                          Ответить
                    • Циклический сдвиг 32-битного числа на 8:
                      #include <stdio.h>
                      #include <stdint.h>
                      char * __attribute__((section(".text"))) vrot8 = "QXPPDXDDD\xc3";
                      int main() {
                          uint32_t __attribute__((fastcall)) (* rotator)(uint32_t) = (void *)vrot8;
                          uint32_t x = 0x12345678;
                          printf("rot(%x) = %x\n", x, rotator(x));
                          return 0;
                      }


                      64-битный вариант (почему-то не работает):
                      #include <stdio.h>
                      #include <stdint.h>
                      char *__attribute__((section(".text"))) vrot8 = "WXPPDXDDDDDDD\xc3";
                      int main() {
                      	uint64_t __attribute__((sysv_abi)) (* rotator)(uint64_t) = (void *)vrot8;
                      	uint64_t x = 0x123456789abcdef;
                      	printf("rot(%lx) = %lx\n", x, rotator(x));
                      	return 0;
                      }
                      Ответить
                      • В 64-битном режиме почему-то после INC RSP неправильно работает POP. Похоже, что POP в длинном режиме выравнивает значение RSP перед тем, как взять данные.
                        Ответить
                        • Например, сдвиг на 16 бит без применения INC/DEC работает:
                          #include <stdio.h>
                          #include <stdint.h>
                          const char __attribute__((section(".text"))) vrot8[] = "WXfPPfXX\xc3";
                          int main() {
                          	uint64_t __attribute__((sysv_abi)) (*rotator)(uint64_t) = vrot8;
                          	uint64_t x = 0x123456789abcdef;
                          	printf("rot(%lx) = %lx\n", x, rotator(x));
                          	return 0;
                          }


                          https://ideone.com/jycvRV
                          Ответить
                        • > почему-то
                          А ты декомпильни этот код. 'D' - не инкремент. Это префикс REX.R
                          Ответить
                          • Вот я идиот! Даже не глянул сетку опкодов. Я думал, что все новые инструкции где-то в пространстве 0F, а опкоды для старых инструкций совпадают, как было при переходе с 16-битного кода на 32-битный. А они, оказывается, часть старых опкодов затёрли новыми инструкциями.

                            Какой багор )))

                            Надо запомнить, что у x86-64 однобайтовых инкрементов/декрементов нет, на их месте ненужные префиксы Рэкс-фас; PUSHA, POPA, BOUND отменили; на месте ARPL теперь MOVSXD; AAA, AAS, DAA, DAS, AAM, AAD отменили; префиксы сегментов отменили, за исключением FS, GS; пуш и поп для сегментных регистров тоже отменили; LES, LDS, CALL FAR, JMP FAR тоже отменили.

                            И зачем-то отменили опкод 82H, который никому не мешал.

                            Как вообще можно что-то делать без однобайтовых инкрементов/декрементов???
                            Ответить
                            • Отредактировал комментарий, потому что ошибся.

                              83H –— это операции с 16/32-битным регистром, у которых в качестве второго аргумента выступало 8-битное непосредственное, которое на лету дополнялось нулями до 16/32-битного. Было очень удобно, потому что не нужно было хранить в программе лишние нули.

                              А 82H –— это просто копия 80H.
                              Ответить
                            • Идея: вместо инкремента вычитать минус единицу. Минус единицу можно представить как 0x5555555555555555 + 0x5555555555555555 + 0x5555555555555555.
                              Ответить
                              • Всё, высрал инкремент:
                                #include <stdio.h>
                                #include <stdint.h>
                                char *__attribute__((section(".text"))) incr = "fhUUfhUUfhUUfhUUTZH+:H+:H+:ZWX\xc3";
                                int main() {
                                    uint64_t __attribute__((sysv_abi)) (* increment)(uint64_t) = (void *)incr;
                                    uint64_t x = 0x123456789abcdef;
                                    printf("inc(%lx) = %lx\n", x, increment(x));
                                    return 0;
                                }


                                https://ideone.com/2Z5MCE

                                Узнал две особенности x86-64:
                                1. У кучи инструкций непосредственный аргумент может быть максимум 32-битным. Старшая половина добивается нулями. Мне пришлось делать четыре 16-битных пуша, чтобы запушить 64-битное число.
                                2. У инструкций с mod-R/M нужно указывать префикс REX.W (H), иначе результат обрежется до 32-битного.

                                Как всё сложно...
                                Ответить
                          • Кстати, почему в длинном режиме непосредственный аргумент не может быть 64-битным? Они ввели это ограничение, чтобы инструкция не получалась слишком длинной и чтобы с лёгкостью укладывалась в кэш/конвейер/предиктор?
                            Ответить
                            • > The x86 instruction set (16, 32 or 64 bit, all variants/modes) guarantees / requires that instructions are at most 15 bytes.
                              https://stackoverflow.com/questions/14698350/x86-64-asm-maximum-bytes-for-an-instruction

                              «mov qword [rax + rcx + 0x11223344], 0x55667788», например, занимает 12 байт, а с 64-битным аргументом получится 16 (и ещё всякие префиксы могут быть же). Ну и как пишут на SO — 64-битный аргумент можно напрямую загружать в регистр.
                              Ответить
                              • Поглядел, нашёл единственную инструкцию с 64-битным непосредственным: MOV reg, imm (КОП B8H+номер регистра).
                                Ответить
                              • Получается, что если я искусственно соберу длинную инструкцию (нафигачив префиксов сегмента и REP), то программа выполнится на 8086/8088, но упадёт на более современных процессорах (начиная с 80286) даже в реальном режиме?
                                Ответить
                      • Замечание про атрибуты.

                        В 64-битном режиме у «gcc» есть два соглашения о вызове: «sysv_abi» и «ms_abi». При «sysv_abi» первые 6 аргументов передаются через регистры (RDI, RSI, RDX, RCX, R8, R9), при «ms_abi» только четыре первых аргумента передаются через регистры (RCX, RDX, R8, R9). Плавающий питух передаётся через питушиный стек (до четырёх аргументов в случае «ms_abi» и до восьми аргументов в случае «sysv_abi»). Стек в обоих случаях чистит вызываемая функция. Нельзя портить RBX и RBP (а для «ms_abi» ещё и RSI и RDI) и четыре последних нумерных.

                        В 32-битном режиме вариантов способа вызова гораздо больше. «Fastcall» у разных компиляторов реализован по-разному («gcc» первые два аргумента передаёт через ecx и edx).

                        Мне больше всего понравилось, как сделали в «Watcom C»: там с помощью #pragma можно создать своё собственное соглашение, указав, через какие именно регистры нужно передавать аргументы и кто будет чистить стек.
                        Ответить
                        • Нашёл ещё одно отличие ms_abi и sysv_abi в 64-битном режиме: перед вызовом функции большого количества аргументов в ms_abi указатель на вершину стека уменьшается, как будто первые четыре аргумента тоже запушили, хотя реально в этом участке стека лежит мусор.
                          Ответить
                          • https://docs.microsoft.com/en-us/cpp/build/x64-calling-convention?view=vs-2017
                            The x64 Application Binary Interface (ABI) uses a four-register fast-call calling convention by default.
                            Space is allocated on the call stack as a shadow store for callees to save those registers.
                            Ответить
                          • В sysv_abi есть ещё одно страшное отличие - red zone. Кусок стека, который можно невозбранно юзать без декремента rsp.

                            Эта хуйня порождает очень весёлые баги в ring 0 (если пишешь своё ядро, например)... Её, конечно, можно отключить. Но для этого про неё надо знать.
                            Ответить
                            • Какие баги? Кто-то не учел редзону и засрал переменные?
                              Ответить
                              • > кто-то
                                Да тупо процессор во время обработки прерывания. Он же ничего не знает про эти ваши редзоны.
                                Ответить
                                • Я тоже ничего не знаю про «редзоны». Именно поэтому я за «PHP».
                                  Ответить
                            • Можно пример висёлого ьуги-вуги?
                              Ответить
                              • И мне можно? Я тоже люблю буги-вуги.

                                Я надеваю штиблеты и галстук-шнурок,
                                Я запираю свою дверь на висячий замок.
                                Ответить
                        • > вызываемая
                          Вызывающая.
                          Ответить
                          • Да, посмотрел дизасм, теперь уже понял, что вызывающая, как в cdecl.

                            То есть можно создавать функции с переменным количеством аргументов, а вот сделать принудительный пуш/поп посредством каламбура типов не получится.
                            Ответить
                            • Напиши себе ascii'шные push и pop. Они то гарантированно будут работать в отличие от игры с конвеншенами. Вот только оптимизатор потом обидится и достанет локальные переменные не оттуда...
                              Ответить
                            • При очистке вызываемым тоже можно замутить переменное количество аргументов. Передаёшь ему количество в регистре или крайнем аргументе да и всё.

                              В общем-то это даже надёжней т.к. вызываемый видит обе границы аргументов. А в cdecl - только нижнюю.
                              Ответить
                              • Как я тебе стек из вызываемой функции чистить буду? RET ожидает кококоличество очищаемых байтиков в непосредственном аргументе.

                                Варианты реализации:
                                1. Патчить код (изменять байтик, следующий за опкодом RET). Для этого нужно снимать защиту.

                                2. Свитч-кейс, в каждой ветке которого будет RET N с соответствующим значением N.

                                3. Извлекать из стека адрес возврата, чистить стек, после этого делать джамп (ну или push+ret) на сохранённый в регистре адрес возврата.
                                Ответить
                                • 3.

                                  А можно даже количество не передавать. Не дочитал все vararg'и - получай UB.
                                  Ответить
                                  • З.Ы. В общем-то вызов printf() с кривой строкой формата - это уже UB. Так что такая реализация имеет право на жизнь.
                                    Ответить
                                • > RET N
                                  Кстати, а ведь ret и ret N спекулятивно возвращаются к вызывающему независимо от N и состояния стека? Т.е. вариант с push + ret будет более правильным, нежели jmp...
                                  Ответить
                                  • В варианте с jmp предиктор будет думать, что подпрограмма никогда не кончится.
                                    Ответить
                                  • В жопу спекулятивно.
                                    Ответить
                                    • > в жопу спекулятивно
                                      Сперва присунул, потом спросил?
                                      Ответить
                                      • Всегда так делаю.
                                        Ответить
                                      • Нет, сначала присунул, потом сказал "no homo" и тем самым все сайд-эффекты обнулились. Ну или почти все.
                                        Ответить
                                        • Мне кажется, спекулятивно –— это наоборот: пригрозить присунуть, но не присунуть. Или присунуть палец...
                                          Ответить
                                        • или не обнулились, если речь о мельтдауне
                                          Ответить
                                        • > и тем самым все сайд-эффекты обнулились. Ну или почти все.
                                          …кроме ЗППП.
                                          Ответить
                                • В жопу стек.
                                  Ответить
    • Устроился в Яндекс. Точнее в Яндекс.Еда. Пока курьером.
      Ответить
      • Задачки, которые нахуй не пригодятся в работе, задавали?
        Ответить
        • Дали три адреса и просили найти кротчайший путь между всеми тремя чтобы быстрее принести пельмени

          Я использовал Яндекс.Карты
          Ответить
      • Один парень устроился в «Яндекс» и умер. Курьер сервиса «Яндекс.Еда» умер прямо на рабочем месте, отработав 10 часов без перерыва. Молодому человеку исполнился 21 год. Компания «Яндекс» уже принесла извинения родственникам погибшего.

        Пишут, что сервис славится нереальными задачами типа доставить еду на расстояние 4 километра за 14 минут. Напоминаю, что курьер пеший. За опоздание штраф.
        Ответить
        • Ублюдки, пользуются тем, что в сране безработица, выжимают из людей последние силы.
          Ответить
          • На Х-ре уже появилась заметка с интересными комментариями:
            https://habr.com/ru/news/t/448722/

            Один комментатор уже вспомнил песню «16 тонн». Если кто-то не знает, это песня про США эпохи Великой депрессии:
            https://ru.wikipedia.org/wiki/Sixteen_Tons
            Ответить
          • Выжал тебе в рот, глотай.
            В рашке чуть ли не самая низкая безработица в Европе.
            Ответить
        • > 10 часов без перерыва
          Имхо, страшнее когда так работают таксисты или газелисты. Зомбаки за рулём.

          > нереально
          Если верить гуглу, то КМС должен пробежать за это время 5км. Так что вполне реально.
          Ответить
          • > КМС

            С десятикилограммовым рюкзаком?

            > Зомбаки за рулём.

            Читал в какой-то книжке, что спящий водитель хуже пьяного: у пьяного есть хоть какая-то реакция, пусть даже с задержкой, а у спящего реакции на обстановку нет.
            Ответить
            • > десятикилограммовым
              Ну да, это уже к спецназовцам...
              Ответить
            • З.Ы. Кстати, довольно часто вижу этих жёлтых чуваков с рюкзаками в метро.
              Ответить
        • Какой анскилл )))
          Ответить
    • Заметил, что активность с 21:00 до 01:00 на Говнокоде заметно пропадает.
      С чем это связано?
      Ответить
      • я дрочу в это время
        Ответить
        • Петух явно чём-то занят. Основная активность то от него.
          Ответить
          • Петухи рано садятся спать. Им рано вставать.
            Ответить
      • Это по какому времени?
        Ответить
        • По дефолтному
          Ответить
          • Мне тут не спалось, и я решил поболтать с 'J', так вот она говорит что активность падать примероно с 1:00 до 8:00 по UTC+0:
            load 'web/gethttp'
               load 'convert/pjson'
               coinsert 'pjson'
            
               getcomments =: verb define
                   comments =. 0 $ a:
                   i =. 0
                   args =. ''
                   while. i < y do.
                       comments =. comments , dec gethttp 'http://b.gcode.cx/ngk/api/comments' , args
                       args =. '?before=' , (_1 ; _3 1) {:: comments
                       i =. i + 20
                   end.
                   comments
               )
               
               comments =: getcomments 400
               hours =: /:~ ("[email protected]:{~&11 [email protected]{::~&_3 1)every comments
               ([email protected]] ,. +/"[email protected][email protected]])hours
            0 20
             1  7
             3  1
             4  3
             5  4
             6  1
             7  2
             8 10
             9 26
            10 17
            11 14
            12 12
            13 41
            14 38
            15 44
            16 13
            17 29
            18 32
            19 15
            20 15
            21 18
            22 25
            23 13
            Вобщет по хорошему надо было считать среднее за каждый час в день, но мои красны глазы жаждут погрузится во тьму.
            Ответить

    Добавить комментарий