Няшная / Говнокод #25449 Ссылка на оригинал

0

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

Запостил: j123123 j123123, (Updated )

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

    • На платформе с 16-битным интом не сработает, в отличие от оригинала.
      Ответить
      • Разве на платформе с 16-битным интом оно не сломается еще на стадии (1 | 1 << 16) в том числе и на оригинале?

        Надо наверно так, чтоб уж наверняка:
        #define BSWAP16(x) (uint16_t)( (uint16_t)(x) * (1ULL | 1ULL << 16ULL) >> 8ULL)
        Ответить
      • На платформе с 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, например).
              Ответить
                • У MUL произведение 32-битное, у DIV делимое 32-битное.

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

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

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

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

                            Кажется это исправили в струящихся одна коммнда -- много сведений удлиненийя
                            Ответить
  • : 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;})
    Ответить
    • > Байтоёбство без побитовых операций

      В js тоже есть «union»
      var buffer   = new ArrayBuffer(2);
      var int16View= new Int16Array(buffer);
      var int8View = new Int8Array(buffer);
      
      int16View[0] = 0x326A;
      console.log(int16View[0].toString(16))
      int8View[0] ^= int8View[1];
      int8View[1] ^= int8View[0];
      int8View[0] ^= int8View[1];
      
      console.log(int16View[0].toString(16))
      Ответить
        • А что не так? 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; 2g@ ; в ah теперь ah XOR temp
                xor temp, al; 0G@ ; в temp теперь temp XOR ah XOR al
                xor al, temp; 2G@ ; в al теперь temp xor ah
                xor al, temp; 2G@ ; в al теперь старое значение ah
                xor ah, temp; 2g@ ; в ah теперь temp XOR al
                xor temp, ah; 0g@ ; в ah теперь старое значение al
                xor temp, al; 0G@ ; в temp теперь старое значение temp

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

                        g@ –— это ah, [bx+40h]
                        G@ –— это al, [bx+40h]
                        Ответить
                  • Тут самое сложное –— не запутаться, изобретая схему обмена значений. Ещё важно было не забыть восстановить значение ни в чём не повинной переменной, которое мы временно портили.
                    Ответить
                  • Твоим методом также можно вращать регистры 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-битного.

                              Как всё сложно...
                              Ответить
                              • > высрал инкремент:
                                $ echo -n -e "fhUUfhUUfhUUfhUUTZH+:H+:H+:ZWX\xc3" |  ndisasm -b 64 -
                                00000000  66685555          push word 0x5555
                                00000004  66685555          push word 0x5555
                                00000008  66685555          push word 0x5555
                                0000000C  66685555          push word 0x5555
                                00000010  54                push rsp
                                00000011  5A                pop rdx
                                00000012  482B3A            sub rdi,[rdx]
                                00000015  482B3A            sub rdi,[rdx]
                                00000018  482B3A            sub rdi,[rdx]
                                0000001B  5A                pop rdx
                                0000001C  57                push rdi
                                0000001D  58                pop rax
                                0000001E  C3                ret


                                > fffUUfUU
                                Что-то мне не нравится pitush word 0x5555.
                                Ответить
                                • Я не придумал, как по-другому запушить константу 0x5555555555555555, используя только опкоды из диапазона ASCII.

                                  Есть альтернативный способ?
                                  Ответить
                                  • Ну конечная цель загрузить -1
                                    > вместо инкремента вычитать минус единицу

                                    А через CWD/CDQ не получится?
                                    Ответить
                                    • CWD/CDQ поможет, если у нас изначально была минус единица, хотя бы для более короткого типа. Её нужно откуда-нибудь достать.
                                      Ответить
                                      • > если у нас изначально была минус единица, хотя бы для более короткого типа. Её нужно откуда-нибудь достать

                                        Например
                                        2C ib 	SUB AL, imm8
                                        
                                        
                                        SUB AL, 33
                                        ADD AL, 32
                                        Ответить
                                    • Кстати, я кидал ссылку на крутую шизу, но ту учётку смыло.

                                      Вот тут автор изобрёл компилятор, который получает EXE-файлы для «DOS», состоящие только из печатаемых ASCII-символов (включая заголовок):
                                      http://tom7.org/abc/

                                      https://sourceforge.net/p/tom7misc/svn/HEAD/tree/trunk/abc/

                                      Такой экзешник можно передавать как текстовый файл.
                                      Ответить
                                      • exeшник с текстовыми комментариями. Очень недурно.

                                        Даже file не разгадал
                                        $ file ../paper.exe 
                                        ../paper.exe: ASCII text, with very long lines, with no line terminators
                                        Ответить
                                        • Существует куча COM-файлов, у которых в шизоидном коде только небольшой распаковщик, а остаток файла представляет собой полезный код, закодированный в UUE или в Base64. Даже упаковщики для этого написали.

                                          А вот EXE-файлов, зожатых таким образом, я не видел. Tom7 — первый, кто придумал заголовки EXE составлять из печатаемых символов.
                                          Ответить
                                          • > первый, кто придумал заголовки EXE составлять из печатаемых символов.

                                            В странную эпоху живём.

                                            Появились читабельные EXEшники.

                                            Исчезли читабельные JSники.

                                            Теперь JS имеет читабельность бинарного файла, зато обладает скоростью скриптового языка.
                                            Ответить
                                            • >Появились
                                              Миша Збыковски просил передать, что давно уже
                                              Ответить
                                  • > Есть альтернативный способ?
                                    $ nasm -f elf64 ./dec.asm -l /dev/stdout && less 
                                         1 00000000 31C0                    xor eax,eax
                                         2 00000002 2C55                    sub al,85
                                         3 00000004 2C55                    sub al,85
                                         4 00000006 2C55                    sub al,85
                                         5 00000008 6698                    cbw
                                         6 0000000A 6699                    cwd  
                                         7 0000000C 99                      cdq

                                    cdq не ascii

                                    Именно поэтому я за x86-32
                                    $ nasm -f elf32 ./dec.asm -l /dev/stdout && less 
                                         1 00000000 48                      dec eax
                                         2 00000001 6648                    dec ax
                                    Ответить
                              • $ nasm -f elf64 ./dec.asm -l /dev/stdout && less 
                                     1 2D11622000              sub eax,2122257
                                     2 0510622000              add eax,2122256
                                Ответить
                        • Кстати, почему в длинном режиме непосредственный аргумент не может быть 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 указатель на вершину стека уменьшается, как будто первые четыре аргумента тоже запушили, хотя реально в этом участке стека лежит мусор.
                        Ответить
                        • В sysv_abi есть ещё одно страшное отличие - red zone. Кусок стека, который можно невозбранно юзать без декремента rsp.

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

                              Я надеваю штиблеты и галстук-шнурок,
                              Я запираю свою дверь на висячий замок.
                              Ответить
                        • Да, посмотрел дизасм, теперь уже понял, что вызывающая, как в 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...
                                Ответить
  • Устроился в Яндекс. Точнее в Яндекс.Еда. Пока курьером.
    Ответить
      • Дали три адреса и просили найти кротчайший путь между всеми тремя чтобы быстрее принести пельмени

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

      Пишут, что сервис славится нереальными задачами типа доставить еду на расстояние 4 километра за 14 минут. Напоминаю, что курьер пеший. За опоздание штраф.
      Ответить
      • Ублюдки, пользуются тем, что в сране безработица, выжимают из людей последние силы.
        Ответить
      • > 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&#039; , args
                     args =. '?before=' , (_1 ; _3 1) {:: comments
                     i =. i + 20
                 end.
                 comments
             )
             
             comments =: getcomments 400
             hours =: /:~ (".@:{~&11 12@{::~&_3 1)every comments
             (~.@] ,. +/"1@=@])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
          Вобщет по хорошему надо было считать среднее за каждый час в день, но мои красны глазы жаждут погрузится во тьму.
          Ответить

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

Переведи на "PHP", guest!

    А не использовать ли нам bbcode?


    8