Microsoft MVP성태의 닷넷 이야기
글쓴 사람
정성태 (techsharer at outlook.com)
홈페이지
첨부 파일
 
(연관된 글이 1개 있습니다.)

ilasm.exe 컴파일 오류 - error : syntax error at token '-' in ... -inf

간단하게 다음의 예제 코드를,

Console.WriteLine(GetResult());

double GetResult()
{
    return double.NegativeInfinity;
}

빌드해 생성한 DLL을 ildasm.exe로 IL 코드로 변경합니다.

C:\temp\ConsoleApp1\ConsoleApp1\bin\Debug\net7.0> ildasm ConsoleApp1.dll /out=test.il

그리고 이렇게 생성한 IL 코드를 다시 컴파일하면,

C:\temp\ConsoleApp1\ConsoleApp1\bin\Debug\net7.0> ilasm test.il /out=test.dll

Microsoft (R) .NET Framework IL Assembler.  Version 4.8.9105.0
Copyright (c) Microsoft Corporation.  All rights reserved.
Assembling 'test.il'  to EXE --> 'test.dll'
Source file is ANSI

Assembled method Microsoft.CodeAnalysis.EmbeddedAttribute::.ctor
Assembled method System.Runtime.CompilerServices.RefSafetyRulesAttribute::.ctor
Assembled method Program::<Main>$
Assembled method Program::.ctor
test.il(131) : error : syntax error at token '-' in:     IL_0001:  ldc.r8     -inf

***** FAILURE *****

오류를 재현할 수 있습니다. 오류의 원인은, GetResult 메서드에서 사용한 double.NegativeInfinity 상수가 IL 코드로는 -inf로 번역되었기 때문인데요,

.method assembly hidebysig static float64 
        '<<Main>$>g__GetResult|0_0'() cil managed
{
    .custom instance void [System.Runtime]System.Runtime.CompilerServices.CompilerGeneratedAttribute::.ctor() = ( 01 00 00 00 ) 
    // Code size       15 (0xf)
    .maxstack  1
    .locals init (float64 V_0)
    IL_0000:  nop
    IL_0001:  ldc.r8     -inf
    IL_000a:  stloc.0
    IL_000b:  br.s       IL_000d

    IL_000d:  ldloc.0
    IL_000e:  ret
} // end of method Program::'<<Main>$>g__GetResult|0_0'

어째서 ildasm.exe가 그렇게 번역한 것인지는 모르겠지만 어쨌든 ilasm.exe에는 그것이 아직 반영되지 않아 -inf 토큰을 해석할 수 없었던 것입니다. 이에 대해 검색해 보면,

error : syntax error at token '-' in: IL_002d: ldc.r8 -nan(ind) with "return Double.NaN
; https://github.com/3F/DllExport/issues/158

ILDasm.exe regression with infinum floating point values in .NET Framework 4.8 SDK
; https://developercommunity.visualstudio.com/t/ildasmexe-regression-with-infinum-floating-point-v/545431

답이 나오는데요, 각각 다음의 표현으로 수정하는 것으로 어셈블이 가능해집니다.

ldc.r4 inf
 ==> ldc.r4 (00 00 80 7F)

ldc.r4 -inf
 ==> ldc.r4 (00 00 80 FF)

ldc.r8 inf
 ==> ldc.r8 (00 00 00 00 00 00 F0 7F)

ldc.r8 -inf
 ==> ldc.r8 (00 00 00 00 00 00 F0 FF)

그러니까, 제가 사용한 코드의 경우 이렇게 바꿔주면 되는 것입니다.

.method assembly hidebysig static float64 
        '<<Main>$>g__GetResult|0_0'() cil managed
{
    .custom instance void [System.Runtime]System.Runtime.CompilerServices.CompilerGeneratedAttribute::.ctor() = ( 01 00 00 00 ) 
    // Code size       15 (0xf)
    .maxstack  1
    .locals init (float64 V_0)
    IL_0000:  nop
    //     IL_0001:  ldc.r8     -inf
    IL_0001:  ldc.r8 (00 00 00 00 00 00 F0 FF)
    IL_000a:  stloc.0
    IL_000b:  br.s       IL_000d

    IL_000d:  ldloc.0
    IL_000e:  ret
} // end of method Program::'<<Main>$>g__GetResult|0_0'

이후 ilasm.exe로 컴파일하고, 그 결과를 dnSpy 등의 도구로 보면 double.NegativeInfinity로 나옵니다.

[CompilerGenerated]
internal static double <<Main>$>g__GetResult|0_0()
{
    return double.NegativeInfinity;
}

재미있는 건, (ildasm.exe와는 달리) 위의 코드를 dnSpy의 "IL" 보기로 전환하면 "IL_0001: ldc.r8 (00 00 00 00 00 00 F0 FF)" 코드가 나옵니다. (또한, 최신 버전의 ildasm을 사용해도 바이트 배열 코드가 나옵니다.)




한 예로, 근래의 "Oracle.ManagedDataAccess.dll"을 (pdb 디버깅을 위해) 역어셈블하면 -inf 예외가 발생하는데요, 이 문제를 위와 같은 방법으로 수정하거나 아니면 .NET Core/5+에 포함된 ildasm.exe를 써도 됩니다.




[이 글에 대해서 여러분들과 의견을 공유하고 싶습니다. 틀리거나 미흡한 부분 또는 의문 사항이 있으시면 언제든 댓글 남겨주십시오.]

[연관 글]






[최초 등록일: ]
[최종 수정일: 12/6/2023]

Creative Commons License
이 저작물은 크리에이티브 커먼즈 코리아 저작자표시-비영리-변경금지 2.0 대한민국 라이센스에 따라 이용하실 수 있습니다.
by SeongTae Jeong, mailto:techsharer at outlook.com

비밀번호

댓글 작성자
 




1  2  3  4  5  6  7  8  [9]  10  11  12  13  14  15  ...
NoWriterDateCnt.TitleFile(s)
13718정성태8/27/20247431오류 유형: 921. Visual C++ - error C1083: Cannot open include file: 'float.h': No such file or directory [2]
13717정성태8/26/20247023VS.NET IDE: 192. Visual Studio 2022 - Windows XP / 2003용 C/C++ 프로젝트 빌드
13716정성태8/21/20246757C/C++: 167. Visual C++ - 윈도우 환경에서 _execv 동작 [1]
13715정성태8/19/20247362Linux: 78. 리눅스 C/C++ - 특정 버전의 glibc 빌드 (docker-glibc-builder)
13714정성태8/19/20246757닷넷: 2295. C# 12 - 기본 생성자(Primary constructors) (책 오타 수정) [3]
13713정성태8/16/20247466개발 환경 구성: 721. WSL 2에서의 Hyper-V Socket 연동
13712정성태8/14/20247223개발 환경 구성: 720. Synology NAS - docker 원격 제어를 위한 TCP 바인딩 추가
13711정성태8/13/20248063Linux: 77. C# / Linux - zombie process (defunct process) [1]파일 다운로드1
13710정성태8/8/20247996닷넷: 2294. C# 13 - (6) iterator 또는 비동기 메서드에서 ref와 unsafe 사용을 부분적으로 허용파일 다운로드1
13709정성태8/7/20247752닷넷: 2293. C# - safe/unsafe 문맥에 대한 C# 13의 (하위 호환을 깨는) 변화파일 다운로드1
13708정성태8/7/20247546개발 환경 구성: 719. ffmpeg / YoutubeExplode - mp4 동영상 파일로부터 Audio 파일 추출
13707정성태8/6/20247775닷넷: 2292. C# - 자식 프로세스의 출력이 4,096보다 많은 경우 Process.WaitForExit 호출 시 hang 현상파일 다운로드1
13706정성태8/5/20247895개발 환경 구성: 718. Hyper-V - 리눅스 VM에 새로운 디스크 추가
13705정성태8/4/20248165닷넷: 2291. C# 13 - (5) params 인자 타입으로 컬렉션 허용 [2]파일 다운로드1
13704정성태8/2/20248110닷넷: 2290. C# - 간이 dotnet-dump 프로그램 만들기파일 다운로드1
13703정성태8/1/20247437닷넷: 2289. "dotnet-dump ps" 명령어가 닷넷 프로세스를 찾는 방법
13702정성태7/31/20247845닷넷: 2288. Collection 식을 지원하는 사용자 정의 타입을 CollectionBuilder 특성으로 성능 보완파일 다운로드1
13701정성태7/30/20248111닷넷: 2287. C# 13 - (4) Indexer를 이용한 개체 초기화 구문에서 System.Index 연산자 허용파일 다운로드1
13700정성태7/29/20247726디버깅 기술: 200. DLL Export/Import의 Hint 의미
13699정성태7/27/20248238닷넷: 2286. C# 13 - (3) Monitor를 대체할 Lock 타입파일 다운로드1
13698정성태7/27/20248206닷넷: 2285. C# - async 메서드에서의 System.Threading.Lock 잠금 처리파일 다운로드1
13697정성태7/26/20247921닷넷: 2284. C# - async 메서드에서의 lock/Monitor.Enter/Exit 잠금 처리파일 다운로드1
13696정성태7/26/20247454오류 유형: 920. dotnet publish - error NETSDK1047: Assets file '...\obj\project.assets.json' doesn't have a target for '...'
13695정성태7/25/20247438닷넷: 2283. C# - Lock / Wait 상태에서도 STA COM 메서드 호출 처리파일 다운로드1
13694정성태7/25/20247906닷넷: 2282. C# - ASP.NET Core Web App의 Request 용량 상한값 (Kestrel, IIS)
13693정성태7/24/20247233개발 환경 구성: 717. Visual Studio - C# 프로젝트에서 레지스트리에 등록하지 않은 COM 개체 참조 및 사용 방법파일 다운로드1
1  2  3  4  5  6  7  8  [9]  10  11  12  13  14  15  ...