1. Assembler / Говнокод #7302

    +132

    1. 1
    2. 2
    3. 3
    4. 4
    5. 5
    6. 6
    7. 7
    8. 8
    9. 9
    movq	(%rdi), %rdi	# this.11_6->_M_impl._M_start, D.49210
    	testq	%rdi, %rdi	# D.49210
    	je	.L1	#,
    	jmp	_ZdlPv	#
    	.p2align 5,,7
    	.p2align 3
    .L1:
    	rep
    	ret

    Говнокод от компилятора g++-4.5.2

    Почему нельзя было сделать так:
    movq (%rdi), %rdi # this.11_6->_M_impl._M_start, D.49210
    testq %rdi, %rdi # D.49210
    jne _ZdlPv #,
    rep
    ret

    Не понимаю...

    Запостил: wecanstoptrain, 21 Июля 2011

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

    • показать все, что скрытокто-нибудь тут понимает красноглазый гццшный асм?
      Ответить
      • Перевожу на русский:
        mov rdi, QWORD PTR [rdi]	
        	test	rdi, rdi	
        	je	L1	
        	jmp	_ZdlPv	
                      align что-то там
        L1:
        	rep
        	ret

        Код для x86-64, но ничего сложного нет. Банальный высер компилятора с je+jmp.
        Ответить
      • АТ синтаксис
        Ответить
    • je бывает short и near. В обоих случаях за байтами команды следуют байты относительного смещения адреса перехода. je с косвенной и с абсолютной адресацией не бывает, в отличие от jmp.

      Кто такая _ZdlPv? Функция? Внешняя? Если да, то в объектном файле будет jmp [константа], а по адресу [константа] расположен фиксап, который будет заполняться при линковке. Если же заменить je+jmp [фиксап] на jne фиксап, то теоретически пофиксить такой код можно, но только при статической линковке. А если _ZdlPv — функция из динамической библиотеки, то будет облом.
      Ответить
      • да, _ZdlPv - внешний operator delete(void*), определен в libstdc++.so
        тогда это не говнокод, про такую тонкость с условным переходом не знал
        Ответить
        • Меня только rep в коде смущает. В x86-32 это был префикс перед строковыми операторами. А что он делает в этом коде, не знаю.
          Ответить
          • у процессоров amd64 предсказатель переходов впадает в кому при виде однобайтовой инструкции ret после условных переходов или после джампа на ret. Он перестает все предсказывать и стопорится, ожидая пока не выполнится ret.
            Поэтому в optimization guide от amd сказано, что в этих случаях надо использовать двухбайтный вариант rep ret. Это справедливо как для x86_32-кода так и для x86_64-кода для процов архитектур Athlon 64/64-II
            Ответить
            • Спасибо за справку. Тогда получается, что весь код обусловлен особенностями процессоров.
              Ответить
              • Это работа такая у компиляторов.
                Ответить
              • Кстати, .NET компилятор тоже принудительно при jit-компиляции в вышеописанных случаях генерит rep ret, причем делает это как для амд-, так и для интел-процессоров, хотя у интела в спеках сказано, что префикс rep может применяться только для строковых операций, а для всех остальных его использование reserved. Походу у мелкомягких есть какая-то договоренность с интелом по поводу rep ret, раз они так смело это используют.
                Ответить
                • Нет никаких договоренностей. На самом деле в манах интела совершенно четко сказано, что применять префикс "rep" можно с любой командой, но действовать он будет только со строковыми командами, в остальных случаях он просто игнорируется. И это еще со времен самых первых камней. Раньше использовалось для ввода в ступор анализаторов антивирусов (первые версии вообще накалывались на раз-два) и просто для резервирования места в полиморфном коде. Сейчас вот амд-шный баг процессора закрывают.
                  Ответить
    • > Почему нельзя было сделать так:

      С такими вопросами на GCC mail list'ы.

      Я предполагаю что это сделано для branch prediction. Либо компилер сам догадался, либо в коде стояли хинты то что 'je' ветка будет выполнятся редко - поэтому она была сделана джампов вниз, которые процессор предполагает что с высокой вероятностью не произойдут. (И джампы вверх наоборот.)

      align'ы внизу потому что на Интеловых процах переход по адресу выровненому на 8 байт быстрее чем по невыровненому адресу. (Мода которую запустли P4.)

      Ну это я предполагаю - давно на асме ничего не писал.
      Ответить
      • Да выше inkanus-gray уже объяснил поведение компилятора в данном случае.
        Ответить

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