Precisa de alguma ajuda decifrar uma linha de código assembler, a partir do código .NET JITted

StackOverflow https://stackoverflow.com/questions/781811

Pergunta

Em um construtor C #, que termina com uma chamada para this(...), a chamada real é traduzido para isso:

0000003d  call        dword ptr ds:[199B88E8h]

O que é o registo de DS conteúdo aqui? Eu sei que é o segmento de dados, mas isso é chamada através de um VMT-mesa ou similar? Duvido, porém, desde this(...) não seria uma chamada para um método virtual, apenas um outro construtor.

Eu pergunto porque o valor naquele local parece ser ruim, de alguma forma, se eu acertar F11, traço em (Visual Studio 2008), em que a chamada instrução, o programa falha com uma violação de acesso.

O código é profundo dentro de uma 3ª biblioteca de controle do partido, onde, apesar de eu ter o código fonte, eu não tenho as assembleias compilado com informações de depuração o suficiente para que eu possa segui-lo através de código C #, somente através da desmontador, e então eu tenho que corresponder volta para o código real.

O código C # em questão é a seguinte:

public AxisRangeData(AxisRange range) : this(range, range.Axis) {
}

refletor me mostra este código IL:

.maxstack 8
L_0000: ldarg.0 
L_0001: ldarg.1 
L_0002: ldarg.1 
L_0003: callvirt instance class DevExpress.XtraCharts.AxisBase DevExpress.XtraCharts.AxisRange::get_Axis()
L_0008: call instance void DevExpress.XtraCharts.Native.AxisRangeData::.ctor(class DevExpress.XtraCharts.ChartElement, class DevExpress.XtraCharts.AxisBase)
L_000d: ret 

É essa última chamada lá, para o outro construtor da mesma classe, que falha. O depurador não superfícies dentro do outro método, ele apenas deixa de funcionar.

A desmontagem para o método depois JITting é esta:

00000000  push        ebp  
00000001  mov         ebp,esp 
00000003  sub         esp,14h 
00000006  mov         dword ptr [ebp-4],ecx 
00000009  mov         dword ptr [ebp-8],edx 
0000000c  cmp         dword ptr ds:[18890E24h],0 
00000013  je          0000001A 
00000015  call        61843511 
0000001a  mov         eax,dword ptr [ebp-4] 
0000001d  mov         dword ptr [ebp-0Ch],eax 
00000020  mov         eax,dword ptr [ebp-8] 
00000023  mov         dword ptr [ebp-10h],eax 
00000026  mov         ecx,dword ptr [ebp-8] 
00000029  cmp         dword ptr [ecx],ecx 
0000002b  call        dword ptr ds:[1889D0DCh]   // range.Axis
00000031  mov         dword ptr [ebp-14h],eax 
00000034  push        dword ptr [ebp-14h] 
00000037  mov         edx,dword ptr [ebp-10h] 
0000003a  mov         ecx,dword ptr [ebp-0Ch] 
0000003d  call        dword ptr ds:[199B88E8h]   // this(range, range.Axis)?
00000043  nop              
00000044  mov         esp,ebp 
00000046  pop         ebp  
00000047  ret              

Basicamente o que eu estou pedindo é esta:

  • O que o propósito do engano ds:[ADDR] aqui? VMT-tabela é apenas para virtual não é? e este é construtor
  • Será que o construtor ainda têm de ser JITted, o que poderia significar que a chamada seria realmente chamar através de um calço JIT? Eu tenho medo Eu estou em águas profundas aqui, então tudo pode e poderia ajudar.

Editar : Bem, o problema ficou pior, ou melhor, ou o que quer

.

Estamos desenvolvendo o recurso .NET em um projeto C #, em uma solução Visual Studio 2008, e depuração e desenvolvimento através do Visual Studio.

No entanto, no final, este código vai ser carregado em um tempo de execução .NET hospedado por uma aplicação Win32 Delphi.

A fim de facilitar a experimentação dessas características, também podemos configurar o projeto do Visual Studio / solução / depurador para copiar o produzido dll para o diretório do Delphi aplicativo, e em seguida, executar o aplicativo Delphi, através do depurador Visual Studio.

Acontece que, o problema desaparece se eu executar o exterior programa do depurador, mas durante a depuração, ele surge, cada vez.

Não tenho certeza que ajuda, mas desde que o código não está previsto para ser lançado de produção por mais 6 meses ou mais, em seguida, leva um pouco da pressão fora dele para a versão de testes que temos em breve.

Eu vou mergulhar nas partes de memória mais tarde, mas provavelmente não até no fim de semana, e postar um acompanhamento.

Foi útil?

Solução

segmento de dados é onde compiladores costumam colocar variáveis ??globais e onde reside a tabela de endereços de importação.

00000029  cmp         dword ptr [ecx],ecx 
0000002b  call        dword ptr ds:[1889D0DCh]

A primeira linha é realmente um nulo-check, que eventualmente levanta uma NullReferenceException se o ponteiro localizado no registo ECX é inválido.

O callvirt instrução MSIL deve fazer o nulo-check antes de invocar o método real. Dito isto, podemos seguramente assumir que estas duas linhas de código assembly ter a seguinte representação de código MSIL:

class DevExpress.XtraCharts.AxisBase DevExpress.XtraCharts.AxisRange::get_Axis()

E o código de montagem comentou:

00000026  mov         ecx,dword ptr [ebp-8]      // store the pointer to the 'range' in ECX
00000029  cmp         dword ptr [ecx],ecx        // null-check
0000002b  call        dword ptr ds:[1889D0DCh]   // range.get_Axis()
00000031  mov         dword ptr [ebp-14h],eax    // store the result in a local variable
00000034  push        dword ptr [ebp-14h]        // push the result onto a stack
00000037  mov         edx,dword ptr [ebp-10h]    // this variable was previously loaded with the 'range' pointer
0000003a  mov         ecx,dword ptr [ebp-0Ch]    // here seems to be stored the actual 'this' pointer
0000003d  call        dword ptr ds:[199B88E8h]   // call the this(...) ctor

É claro para mim por que ele está falhando, você já tentou olhar para cima o conteúdo da posição de memória (DS:[199B88E8h])?

Licenciado em: CC-BY-SA com atribuição
Não afiliado a StackOverflow
scroll top