Why should I know this?

DEX to IR 개발일지 - Class 변환 본문

LLVM-STUDY/TODO

DEX to IR 개발일지 - Class 변환

die4taoam 2022. 12. 28. 03:06

Dex2IR 을 개발한지 좀 됐기 때문에 슬슬 구조적으로 생각해야 할 문제들이 보이기 시작해서

기억의 번복을 줄이기 위해 앞으로는 일지를 작성하려고 합니다.

 

이 글에서 고민하고 싶은건 Class.변환입니다.

바로 들어가죠.

 

이 고민의 발단이 된 instruction은 iget 입니다.

iget-object p3, p0, Lkotlinx/coroutines/android/a;->_immediate:Lkotlinx/coroutines/android/a;

iget instruction 을 적절히 처리하려면 이제는 class 구조의 도입이 불가피합니다.

iget instruction은 Instance 로부터 field의 값을 읽는 명령어기 때문이죠.

 

Class는 IR에서 어떻게 다뤄지는 확인해봅시다.

#include <iostream>

class test {
        public:
        static int si; 
        double b;
        int a;
        char c;
        short d;
};

int main()
{
        test t;
        double b = t.b;
        int a = t.a;
        char c = t.c;
        short d = t.d;
        int si = t.si;

}

class의 필드에 접근하는 방식을 보기 위해 간단한 코드를 작성했습니다.

 

 

ldr     x8, [sp, #32]                      
str     x8, [sp, #24]                      
ldr     w8, [sp, #40]                      
str     w8, [sp, #20]                      
ldrb    w8, [sp, #44]                      
strb    w8, [sp, #19]                      
ldrh    w8, [sp, #46]                      
strh    w8, [sp, #16]                      
adrp    x8, :got:_ZN4test2siE              
ldr     x8, [x8, :got_lo12:_ZN4test2siE]   
ldr     w8, [x8]                           
str     w8, [sp, #12]
  %1 = alloca %class.test, align 8                               
  %2 = alloca double, align 8                                    
  %3 = alloca i32, align 4                                       
  %4 = alloca i8, align 1                                        
  %5 = alloca i16, align 2                                       
  %6 = alloca i32, align 4                                       
  %7 = getelementptr inbounds %class.test, ptr %1, i32 0, i32 0  
  %8 = load double, ptr %7, align 8                              
  store double %8, ptr %2, align 8                               
  %9 = getelementptr inbounds %class.test, ptr %1, i32 0, i32 1  
  %10 = load i32, ptr %9, align 8                                
  store i32 %10, ptr %3, align 4                                 
  %11 = getelementptr inbounds %class.test, ptr %1, i32 0, i32 2 
  %12 = load i8, ptr %11, align 4                                
  store i8 %12, ptr %4, align 1                                  
  %13 = getelementptr inbounds %class.test, ptr %1, i32 0, i32 3 
  %14 = load i16, ptr %13, align 2                               
  store i16 %14, ptr %5, align 2                                 
  %15 = load i32, ptr @_ZN4test2siE, align 4                     
  store i32 %15, ptr %6, align 4

class 의 멤버변수에 접근하는 방식은 위와 같습니다.

 

여기서 문제가 하나 발생하는데, c++에서 class는 형상도 없이 쪼개져서 class.test라는 시작주소를 기준으로 +offset을 하여 field에 접근하게 되죠. 상대주소참조라고 불리는데, 반면 Java 는 모든 field에 대한 접근 방식은 class 에 field를 indexing 하여 접근하는 차이가 있습니다.

 

iget 명령은 class instance에서 field idx 를 통해 반환하기 때문에 offset을 계산할 필요가 없습니다.

즉, IR로 변환하고자 하는 입장에서는 class를  메모리 chunk 단위로 변환해 field를 offset 으로 참조할 수 있게 만들어야 하는 것이죠.

 

그래서 향후 필요한 작업을 정리하자면 다음과 같을 것 같습니다.

1. Class를 파싱할때 Static/Instance Field 들이 포함된 Class 구조체를 생성 => IR의 %class.test 처럼

2. 각 field의 field idx 를 생성한 Class 구조체의 멤버변수와 매칭시킬 방안을 강구 (llvm instrict 를 추가?)

3. iget의 instance 내 field 참조를 위의 IR처럼 class 주소 기반 상대주소참조로 변환

 

 

Comments