Я правильно понимаю этот код MSIL?

У меня есть следующий код на С#

// test.Program
private static void Main()
{
    int x = 5;
    int y = 100;
    Console.WriteLine(y + ", " + x);
}

И я читаю код IL, я никогда раньше не программировал ассемблер, поэтому я спрашиваю, правильно ли то, что я делаю в каждой строке.

.method private hidebysig static 
    void Main () cil managed 
{
    // Method begins at RVA 0x2058
    // Code size 33 (0x21)
    .maxstack 3 // maximum stack in this method is 3
    .entrypoint // method is initial entry point
    .locals init ( // reserves memory for x and y variables
        [0] int32 x, // x variable is reserved on position 0 of the stack
        [1] int32 y  // y variable is reserved on position 1 of the stack
    )
    IL_0000: ldc.i4.5     // integer of 4 bytes in size and the value of 5 is loaded onto the evaluation stack position 0
    IL_0001: stloc.0      // put evaluation stack position 0 into the stack position 0, the evaluation stack is emptied
    IL_0002: ldc.i4.s 100 // integer of 4 bytes in size and the value of 100 is loaded onto the evaluation stack position 0
    IL_0004: stloc.1      // put evaluation stack position 0 onto the stack position 1, the evaluation stack is emptied
    IL_0005: ldloc.1      // load stack position 1 into the evaluation stack position 0
    IL_0006: box [mscorlib]System.Int32 // box last valuetype placed on evaluation stack, replace valuetype with reference on evaluation stack position 0, do not empty stack
    IL_000b: ldstr ", "   // put reference to string on evaluation stack position 1
    IL_0010: ldloc.0      // load stack position 0 into the evaluation stack position 2
    IL_0011: box [mscorlib]System.Int32 // box last valuetype placed on evaluation stack, replace valuetype with reference on evaluation stack position 0, do not empty stack
    IL_0016: call string [mscorlib]System.String::Concat(object, object, object) // call Concat, pass values on evaluation stack, empty evaluation stack, put result of concat on evaluationstack
    IL_001b: call void [mscorlib]System.Console::WriteLine(string) // pass first value in evaluation stack
    IL_0020: ret         // return
} // end of method Program::Main

Я правильно понимаю эту программу?


person NomenNescio    schedule 29.08.2012    source источник


Ответы (3)


Довольно много; единственное, что я хотел бы уточнить, это то, что поле (IL_0006 и IL_0011) зависит от типа, поэтому оно явно создает поле типа int (это не просто «последний тип значения»).

Кроме того, «пустой стек оценки» вводит в заблуждение; это не совсем правильно - например, call потребляет заданное количество позиций, а не "очищает" его. Существует никогда семантика "пустого стека вычислений" - это всегда "потребление некоторого количества значений, возвращение некоторого количества значений" (любое из которых может быть равно нулю).

person Marc Gravell    schedule 29.08.2012
comment
Когда чем-то занято n позиций (например, звонком), потребляются только верхние позиции, верно? А затем помещает ряд значений обратно в стек оценки? Я предполагаю, что это правда, потому что это, в конце концов, «стек», но я просто прошу быть уверенным. - person NomenNescio; 29.08.2012
comment
Да. Гипотетическая операция, которая считывала бы A, B, C, D и производила бы Y, Z, извлекала бы 4 записи из стека*, вычисляла бы результат*, а затем помещала бы в него 2 новые записи. (*) не обязательно в таком порядке, но нажатия всегда будут последними. - person quetzalcoatl; 29.08.2012

Да, ваше понимание почти полностью верно. Одно но: IL_0010 загружается не из стека, а из локалов. (Локальные объекты попадают в стек времени выполнения, но на уровне IL они называются локальными).

person usr    schedule 29.08.2012
comment
OP описывает стек оценки отдельно для локальных жителей в стеке, но я согласен, что было бы лучше просто называть их локальными. - person Marc Gravell; 29.08.2012

Это правильно, хотя я бы немного поспорил с некоторыми нечеткими формулировками, например:

поместите позицию 0 стека оценки в позицию 0 стека, стек оценки опустеет

я бы сказал

поместите 0-ю запись с вершины стека в 0-ю переменную стека, затем извлеките

просто потому, что я думаю, что «менее формальная» формулировка в большинстве случаев просто понятнее для чтения, но в остальном она кажется приемлемой.

редактировать: хм .. в конце концов, я бы сказал, что нет двух вещей, таких как «стек» и «стек оценки». Есть только "стек". Отмеченная часть начала видимой части стека, та, что с локальными переменными, может быть названа «слотами». Я бы предположил, что с IL вы могли бы просто сказать «локальная переменная Nth», и обычно все было бы ясно, но я думаю, что несколько разных переменных могут отображаться в один и тот же слот, поэтому это может вызвать некоторую путаницу. Также при работе со стеком отсутствует операция типа "опорожнение". Только push/pop с явно указанным количеством записей для копирования.

person quetzalcoatl    schedule 29.08.2012