Как компилятор Visual Studio компилирует атрибуты безопасности в CIL?

У меня есть следующий атрибут SecurityPermission(SecurityAction.Assert) на метод в моем классе. Я компилирую его (отладочная сборка) и просматриваю вывод в ildasm.exe, просматривая необработанные кучи и просматривая кучу больших двоичных объектов, содержащую большой двоичный объект PermissionSet. Что я ожидаю (согласно ECMA-335):

2e 01 80 84 53 79 73 74  65 6d 2e 53 65 63 75 72 >.   System.Secur<
69 74 79 2e 50 65 72 6d  69 73 73 69 6f 6e 73 2e >ity.Permissions.<
53 65 63 75 72 69 74 79  50 65 72 6d 69 73 73 69 >SecurityPermissi<
6f 6e 41 74 74 72 69 62  75 74 65 2c 20 6d 73 63 >onAttribute, msc<
6f 72 6c 69 62 2c 20 56  65 72 73 69 6f 6e 3d 32 >orlib, Version=2<
2e 30 2e 30 2e 30 2c 20  43 75 6c 74 75 72 65 3d >.0.0.0, Culture=<
6e 65 75 74 72 61 6c 2c  20 50 75 62 6c 69 63 4b >neutral, PublicK<
65 79 54 6f 6b 65 6e 3d  62 37 37 61 35 63 35 36 >eyToken=b77a5c56<
31 39 33 34 65 30 38 39  00 00

Но то, что я увидел, было так:

2e 01 80 84 53 79 73 74  65 6d 2e 53 65 63 75 72 >.   System.Secur<
69 74 79 2e 50 65 72 6d  69 73 73 69 6f 6e 73 2e >ity.Permissions.<
53 65 63 75 72 69 74 79  50 65 72 6d 69 73 73 69 >SecurityPermissi<
6f 6e 41 74 74 72 69 62  75 74 65 2c 20 6d 73 63 >onAttribute, msc<
6f 72 6c 69 62 2c 20 56  65 72 73 69 6f 6e 3d 32 >orlib, Version=2<
2e 30 2e 30 2e 30 2c 20  43 75 6c 74 75 72 65 3d >.0.0.0, Culture=<
6e 65 75 74 72 61 6c 2c  20 50 75 62 6c 69 63 4b >neutral, PublicK<
65 79 54 6f 6b 65 6e 3d  62 37 37 61 35 63 35 36 >eyToken=b77a5c56<
31 39 33 34 65 30 38 39  01 00

В частности, обратите внимание на 01 00 в конце, где я ожидал 00 00, В спецификации сказано, что после подсчитанной строки должно быть количество именованных аргументов. Поскольку я не передаю никаких именованных аргументов, я ожидал, что это число будет 16-битным 0.

Это скомпилировано для.NET 2.0 с использованием Visual Studio 2013.

Чтобы усложнить ситуацию еще больше, если я добавлю именованный аргумент, я получу это:

2e 01 80 84 53 79 73 74  65 6d 2e 53 65 63 75 72 >.   System.Secur<
69 74 79 2e 50 65 72 6d  69 73 73 69 6f 6e 73 2e >ity.Permissions.<
53 65 63 75 72 69 74 79  50 65 72 6d 69 73 73 69 >SecurityPermissi<
6f 6e 41 74 74 72 69 62  75 74 65 2c 20 6d 73 63 >onAttribute, msc<
6f 72 6c 69 62 2c 20 56  65 72 73 69 6f 6e 3d 32 >orlib, Version=2<
2e 30 2e 30 2e 30 2c 20  43 75 6c 74 75 72 65 3d >.0.0.0, Culture=<
6e 65 75 74 72 61 6c 2c  20 50 75 62 6c 69 63 4b >neutral, PublicK<
65 79 54 6f 6b 65 6e 3d  62 37 37 61 35 63 35 36 >eyToken=b77a5c56<
31 39 33 34 65 30 38 39  12 01 54 02 0d 55 6e 6d >1934e089  T  Unm<
61 6e 61 67 65 64 43 6f  64 65 01                >anagedCode      <

Еще раз, посмотрите на конец подсчитанной строки для атрибута, и вы можете увидеть 12 01 затем следует список именованных аргументов (список из одного элемента). Я ожидал, что это будет 01 0016-разрядный байтовый порядок 1 для числа именованных аргументов.

Исходя из этого, я предполагаю, что второй байт после подсчитанной строки является именованным параметром count, но я все еще не понимаю, что это за первый байт (0x01 в первом примере, 0x12 в следующем).

Если я добавлю второй именованный атрибут, первый байт изменится на 26, если я добавлю третий именованный атрибут, он изменится на 33. Я не вижу очевидного паттерна чисел, кроме факта, что они увеличиваются.

Я задаю этот вопрос, потому что я пытаюсь создать блок PermissionSet вручную (я пишу профилировщик CLR), и мне нужно знать, что добавить в этот байт.

1 ответ

Решение

Я думаю, что вы правы в своем смятении, я помню это из моего предыдущего опыта с названными параметрами - NumNamed был реализован в виде сжатого int вместо int16, указанного в спецификации, и в отличие от примера, приведенного в §VI.B.3. Я не знаю, изменилось ли это в последующих реализациях.NET 3.0+.

Для набора разрешений, который вы ищете,

... * Набор свойств, закодированных в качестве именованных аргументов для пользовательского атрибута, будет (как в §II.23.3, начиная с NumNamed).

... §II.23.3...

Далее приводится описание необязательных "именованных" полей и свойств. Это начинается с NumNamed - беззнаковый int16, дающий количество "именованных" свойств или полей, которые следуют.... В случае, когда NumNamed не равен нулю, за ним следуют NumNamed-повторы NamedArgs.

12 01 это целое число с прямым порядком байтов, "дающее количество свойств, которые следуют" Одно именованное свойство общей длиной 18 (в десятичном формате включительно).

Эта общая длина является шаблоном, который вы искали, но будьте осторожны, так как я думаю, что эта длина является необязательной, и иногда компилятору удается упаковать количество свойств в предыдущем int16, отбрасывая длину. Вам придется поэкспериментировать с другим количеством атрибутов, чтобы убедиться, что вы правильно анализируете все случаи.

NamesArgs:

... SerString - количество байтов в PackedLen, за которыми следуют символы UTF8

НЕДВИЖИМОСТЬ - это один байт 0x54. FieldOrPropName - это имя поля или свойства, хранящееся как SerString (определено выше).

Другие вопросы по тегам