Не в состоянии вызвать 2 функции в CIL - PullRequest
0 голосов
/ 06 марта 2020

Я начал изучать CIL сегодня и использую несколько учебных пособий, чтобы получить базовое c понимание.

В настоящее время у меня есть 2 функции, 1 функция добавляет 10 к целому числу, данному в качестве аргумента, и печатает ответ. Вторая функция берет 2 целых числа, прибавляет 5 к ним обоим и затем умножает ответы. Затем он возвращается.

Обе функции работают, когда вызывается только 1 из них, но при вызове обеих я получаю следующую ошибку:

Необработанное исключение: System.InvalidProgramException: Common Language Runtime обнаружил недопустимую программу.

в Bewerkingen.Program.Main (String [] args)

Я не знаю, как заставить эти 2 функции работать при вызове друг за другом. Это мой код:

.assembly extern mscorlib {} 
.assembly Bewerkingen {} 
.module Bewerkingen.exe

.class public Functions
extends [mscorlib]System.Object
{
 .method public specialname void .ctor()
 {
  ret
 }
 .method public void Add(int32)
 {
  ldarg.1
  ldc.i4 10
  add
  call void [mscorlib]System.Console::WriteLine(int32)
  ret
 }
 .method public int32 add5mul(int32,int32)
 {
  ldarg.1
  ldc.i4 5
  add
  ldarg.2
  ldc.i4 5
  add
  mul
  ret
 }
}

.class Bewerkingen.Program
extends [mscorlib]System.Object
{
 .method static void Main(string[] args)
 cil managed
 {
  .entrypoint
  newobj instance void Functions::.ctor()
  ldc.i4 3
  call instance void Functions::Add(int32)
  ldc.i4 5
  ldc.i4 3
  call instance int32 Functions::add5mul(int32,int32)
  call void [mscorlib]System.Console::WriteLine(int32)
  ret
 }
}

Ответы [ 2 ]

2 голосов
/ 06 марта 2020

У вас небольшая проблема: ваш .ctor должен вызвать ctor базового объекта (ldarg.0, call instance void [System.Private.CoreLib]System.Object::.ctor(), ref). И для программы, и для функций

Основная проблема, однако, заключается в том, что вы пытаетесь вызвать add5mul на ... ничего. В стеке нет объекта Functions для вызова.

// Push Functions instance onto stack
// Stack: [functions]
  newobj instance void Functions::.ctor()

// Push 3 onto stack
// Stack: [3, functions]
  ldc.i4 3

// Pop 3 and functions off the stack
// Stack: []
  call instance void Functions::Add(int32)

// Push 5 and 3 onto stack
// Stack: [3, 5]
  ldc.i4 5
  ldc.i4 3

// Pop 5, 3, and... nothing. We're missing the Functions instance to call it on.
  call instance int32 Functions::add5mul(int32,int32)

Это можно исправить, продублировав экземпляр Functions перед его первым использованием:

  newobj instance void Functions::.ctor()
  dup                                                     <-- Here
  ldc.i4 3
  call instance void Functions::Add(int32)
  ldc.i4 5
  ldc.i4 3
  call instance int32 Functions::add5mul(int32,int32)
  call void [mscorlib]System.Console::WriteLine(int32)
  ret

Вы также можете сохранить этот экземпляр функции в локальном слоте:

.method static void Main(string[] args)
 cil managed
 {
  .locals init (
    [0] class Functions
  )
  .entrypoint
  newobj instance void Functions::.ctor()
  stloc.0
  ldloc.0
  ldc.i4 3
  call instance void Functions::Add(int32)
  ldloc.0
  ldc.i4 5
  ldc.i4 3
  call instance int32 Functions::add5mul(int32,int32)
  call void [mscorlib]System.Console::WriteLine(int32)
  ret
 }


SharpLab.io - отличный ресурс для изучения IL. Вот ваш код, переведенный в C# и декомпилированный в IL .

1 голос
/ 06 марта 2020

Ваш первый вызов функции использует ссылки на объекты, необходимые для вызова нестати c функции. Сохраните ссылку на объект после операции newobj в локальную переменную и загрузите эту ссылку для каждого вызова функции.

Из msdn:

Вызовы экземпляра (или виртуального) Метод должен указывать на этот экземпляр перед любым из видимых пользователем аргументов. Ссылка на экземпляр не должна быть пустой ссылкой. Подпись, переносимая в метаданных, не содержит записи в списке параметров для указателя this; вместо этого он использует бит, чтобы указать, требует ли метод передачи указателя this. https://docs.microsoft.com/en-us/dotnet/api/system.reflection.emit.opcodes.call?view=netframework-4.8

...