Сборный / Говнокод #7302 Ссылка на оригинал

0

  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 wecanstoptrain, (Updated )

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

  • кто-нибудь тут понимает красноглазый гццшный асм?
    Ответить
  • 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 уже объяснил поведение компилятора в данном случае.
      Ответить

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

Из-за тебя ушел bormand, guest!

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


    8