2013-02-19 1 views
2

Я рассматриваю метод экземпляра Object.Equals (Object). С помощью отражения, это Возможное, чтобы получить IL для этого метода в виде массива байтов, следующим образом:Почему метод MethodBody.GetILAsByteArray возвращает разные массивы на разных платформах?

var mi = typeof(object).GetMethod("Equals", BindingFlags.Instance | BindingFlags.Public); 
var mb = mi.GetMethodBody(); 
var bytes = mb.GetILAsByteArray(); 

У меня есть два компьютера: один является 32-разрядной машине под управлением Windows XP, а другой 64-разрядный с Windows 7. Обе машины имеют версию 4.0.30319 SP1Rel установленной платформы .NET Framework.

На машине x86, полученный массив:

[0]: 2 
[1]: 3 
[2]: 40 
[3]: 122 
[4]: 67 
[5]: 0 
[6]: 6 
[7]: 42 

На x64 машине, хотя, я получаю это:

[0]: 2 
[1]: 3 
[2]: 40 
[3]: 123 
[4]: 67 
[5]: 0 
[6]: 6 
[7]: 42 

Четвертый байт отличается.

Теперь я знаю, что mscorlib поставляется в двух вариантах на 64-битных платформах. Однако ILDASM показывает, что IL для этого метода идентичен между вкусами и между машинами. На машине x64 я нацелил вышеуказанный код как на «Любой процессор», так и на «x86», но результат тот же.

Так что мой вопрос: может ли кто-нибудь объяснить отмеченное несоответствие между двумя машинами?

ОБНОВЛЕНИЕ

Вот C# и ИЛЫ для Object.Equals (объект):

public virtual bool Equals(object obj) 
{ 
    return RuntimeHelpers.Equals(this, obj); 
} 

.maxstack 8 
IL_0000: ldarg.0 
IL_0001: ldarg.1 
IL_0002: call bool System.Runtime.CompilerServices.RuntimeHelpers::Equals(object, object) 
IL_0007: ret 
+0

Возможно, вы могли бы показать нам ИЛ, так что, возможно, у нас есть ключ к тому, какой метод там называется. Первые три байта: 'ldarg.0'' ldarg.1' и 'call'. Цель, начинающаяся с четвертого байта. –

+0

Я сделал это. См. Обновление. –

ответ

10

Получите лучшее представление о содержании IL, просто написав метод самостоятельно и глядя на него с помощью ildasm.exe. Используйте View + Показать байты в ILDASM, чтобы увидеть значение байт, обратите внимание, что они находятся в шестнадцатеричном:

.method public hidebysig newslot virtual 
     instance bool Equals(object obj) cil managed 
// SIG: 20 01 02 1C 
{ 
    // Method begins at RVA 0x2052 
    // Code size  8 (0x8) 
    .maxstack 8 
    IL_0000: /* 02 |     */ ldarg.0 
    IL_0001: /* 03 |     */ ldarg.1 
    IL_0002: /* 28 | (0A)000010  */ call  bool [mscorlib]System.Runtime.CompilerServices.RuntimeHelpers::Equals(object, 
                                  object) 
    IL_0007: /* 2A |     */ ret 
} // end of method Program::Equals 

Теперь вы увидите, что байты в IL_0003 является частью метода маркеров, наименее значимые байт из этого. И обратите внимание, как ценность, которую я получил, сильно отличается от той, которую вы получили. Это потому, что я написал очень маленькую программу с очень маленьким кодом для ее проверки, у нее очень маленький манифест. Дисассемблер полезен, вместо того, чтобы показывать только значение токена, он фактически выполнил поиск в таблице метаданных и заменил токен на имя метода.

Токен - это индекс в таблицах метаданных манифеста сборки. Такой индекс будет изменить, когда код в сборке изменится и требует добавления к таблицам. Вы можете узнать больше об этом в спецификации CLI, ECMA 335.

+0

Зачем вам нужно писать этот метод самостоятельно, а не просто указывать ildasm на mscorlib? – svick

+0

Наверное, я вам помогаю заниматься в теме, о которой я слишком мало знаю.Я наивно ожидал использовать GetILAsByteArray в качестве основы для алгоритма контрольной суммы объекта графа (в котором учитываются как состояние графика, так и его реализация IL). Теперь я думаю, что я должен использовать дизассемблер. –

+0

Но вы смотрите на свой 'Program.Equals', и он смотрит на' Object.Equals' из 'mscorlib'. Поскольку он использует ту же версию на обеих платформах, оба mscorlibs должны иметь тот же самый манифест, и поэтому должны показывать то же самое значение токена метаданных ... правильно? Редактировать: О, подождите, он не смотрит на те же версии. Один из них - 32-разрядный 64-разрядный. Виноват. – Virtlink

1

Различных байты является частью metadatatoken со ссылкой на RuntimeHelpers.Equals(). Метки метаданных не гарантируются стабильностью при перекомпиляции модуля. Вот почему привязка к символам в других сборках происходит по имени, а не по токенам метаданных.

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