Я думаю, вы запутываете, как работает CIL с тем, как работает собственный код.
С CIL код, находящийся в исполняемом файле, фактически не выполняется. Обычно (с настольным CLR и без ngen) CLR считывает CIL и генерирует фактический исполняемый код «на лету» (поэтому эта часть CLR называется «только во время компилятора»).
Операции с кодом CIL, такие как call
, используют токены для ссылки на методы и другие элементы. В сгенерированном собственном коде они преобразуются в адрес родного кода для этого метода.
Коды, подобные br
, содержат смещения относительно следующей инструкции CIL, и они могут прыгать только внутри текущего метода. На x86 они скомпилированы в такие команды, как jne
, которые содержат смещения относительно следующей инструкции x86.
Но метаданные для метода описаны в таблице MethodDef
, которая содержит ссылку на поток IL для этого метода в виде 4-байтового Relative Virtual Address (и RVAs также используются в других частях файла). Я думаю, это означает, что исполняемый файл не может быть размером более 4 ГБ.
Я попытался проверить это, создав большой исполняемый файл, используя Reflection.Emit. Но самое лучшее, что я мог сделать в своей системе с 8 ГБ оперативной памяти, - это создать файл размером 1,5 ГБ (который уже сделал компьютер непригодным из-за замены).
«Адрес, сгенерированный компилятором CIL». О каком адресе вы говорите? – svick
Адрес, помещенный после кода операции в выходной код. – user35443
Какой код операции? Каждый код операции имеет свой собственный формат. – svick