2011-01-11 4 views
2

Я только что попробовал простую программу на C с использованием инструкции if и проанализировал ее сборку. Однако его поведение сильно отличается, когда для компиляции используется флаг -O2.понимание сборки: -O2, если ветвление

код C для то же: -

#include<stdio.h> 

int main(int argc, char **argv) { 
    int a; 

    if(a<0) { 
     printf("A is less than 0\n"); 
    } 
} 

И соответствующая сборка: -

main: 
    push %ebp 
    mov %ebp, %esp 
    sub %esp, 8 
    and %esp, -16 
    sub %esp, 16 
    test %eax, %eax 
    js .L4 
    leave 
    ret 
    .p2align 4,,15 
.L4: 
    sub %esp, 12 
    push OFFSET FLAT:.LC0 
    call puts 
    add %esp, 16 
    leave 
    ret 
    .size main, .-main 
    .section .note.GNU-stack,"",@progbits 
    .ident "GCC: (GNU) 3.4.6" 

Я прочитал, что test инструкции в основном только выполняет логическое И двух операндов , Я также читал, что инструкция js выполняет скачок, когда есть изменение знака в предыдущей инструкции. Итак, test ing eax с eax дадут 0 или 1, и скачок будет зависеть от этого.

Я не понимаю, как он используется здесь для ветвления. Может ли кто-нибудь объяснить, как это работает?

+1

Хороший компилятор должен оптимизировать всю программу до нуля, так как имеет неопределенное поведение (использование неинициализированной переменной). Или, если 'a' были инициализированы, он должен оптимизировать условие, основанное на значении' a'. –

ответ

11

JS не прыгать, когда происходит изменение в знак, он прыгает, если флаг знака равен 1.

Знак бит включен, если результат последней операции был отрицательным (отрицательные числа в дополнении 2 имеют самый старший бит в 1).

Так что если операция И была между двумя отрицательными целыми числами (-1 & -1), последний бит будет равен 1 (знак знака), поэтому скачок будет выполнен. Если числа были положительными, последний бит был бы 0, прыжок не будет принят.

3

Ну, я не знаю, чего вы ожидаете, но ваша программа имеет неопределенное поведение, так как a не инициализируется. Таким образом, выход ассемблера может быть буквально любым.

+3

Означает ли вся программа undefined только потому, что значение 'a' не определено? Я предположил, что он будет использовать все, что было в стеке при вызове. – nmichaels

+1

Вывод программы может быть printf, или это может быть ничего, но почему выход компилятора должен быть чем угодно? –

+1

Теоретически вывод может быть любым, но никакой настоящий компилятор не выдаст глупостей. –

2

Если eax отрицательный, флаги укажут, что после команды test и прыжок будет выполнен. Это подталкивает ПК к .L4, который выполняет печать. В противном случае мы уйдем.

2

test eax, eax будет установлен флаг нуля, если EAX = 0

инструкция расслоение плотной проверить флаг знака в основном (а < 0)

+0

'test' устанавливает * все * арифметических флагов, а не только флаг нуля. –

2

Похоже, что при указании -O2 компилятор помещает ваш «int a» в регистр для оптимизации скорости.

Поскольку вы никогда не инициализируете 'int a', сборка не показывает ничего написанного в eax, а вместо этого имеет значение, которое было последним присвоено ему.

Другие ответы объясняют, как тест работает как механизм ветвления.

3

Руководства Intel подходят для этого. Это то, что документы для команды TEST:

alt text

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

Смежные вопросы