자바 코드 컴 파일 과 역 컴 파일

프로 그래 밍 언어
컴 파일 과 역 컴 파일 을 소개 하기 전에 프로 그래 밍 언어(Programming Language)를 간단하게 소개 합 니 다.프로 그래 밍 언어(Programming Language)는 저급 언어(Low-level Language)와 고급 언어(High-level Language)로 나 뉜 다.
기계 언어(Machine Language)와 어 셈 블 리 언어(Assembly Language)는 저급 언어 로 컴퓨터 명령 으로 프로그램 을 직접 작성 합 니 다.
C,C++,Java,Python 등 은 고급 언어 에 속 하고 문장(Statement)으로 프로그램 을 작성 하 며 문장 은 컴퓨터 명령 의 추상 적 인 표현 이다.
예 를 들 어 같은 문 구 는 C 언어,어 셈 블 리 언어 와 기계 언어 로 다음 과 같이 표시 한다.

컴퓨터 는 숫자 만 연산 할 수 있 고 기호,소리,이미 지 는 컴퓨터 내부 에서 모두 숫자 로 표시 해 야 한다.명령 도 예외 가 아니다.위의 표 의 기계 언어 는 완전히 16 진수 로 구성 된다.최초의 프로그래머 들 은 모두 기계 언어 로 프로 그래 밍 을 했 지만 매우 번 거 로 웠 다.모든 숫자 가 무슨 뜻 을 표시 하 는 지 확인 하기 위해 대량의 표를 찾 아야 했다.작 성 된 프로그램 은 직관 적 이지 않 고 오류 가 발생 하기 쉬 웠 다.그래서 어 셈 블 리 언어 가 생 겼 다.기계 언어 에서 한 그룹의 숫자 를 보조 기호(Mnemonic)로 표시 하고 이 보조 기호 로 어 셈 블 리 프로그램 을 직접 썼 다.그리고 어 셈 블 러(Assembler)에 게 표를 찾 아 보조 기 호 를 숫자 로 바 꾸 게 하고 어 셈 블 리 언어 를 기계 언어 로 번역 했다.
그러나 어 셈 블 리 언어 는 사용 하기에 도 복잡 하고 그 다음 에 자바,C,C++등 고급 언어 가 파생 되 었 다.
뭐 공부 해요?
위 에서 언급 한 언어 는 두 가지 가 있 는데 하 나 는 저급 언어 이 고 하 나 는 고급 언어 이다.저급 언어 는 컴퓨터 가 인식 하 는 언어 이 고 고급 언어 는 프로그래머 가 인식 하 는 언어 라 는 것 을 간단하게 이해 할 수 있다.
그렇다면 어떻게 고급 언어 에서 저급 언어 로 바 꿉 니까?이 과정 은 사실 컴 파일 이다.
위의 예 를 통 해 알 수 있 듯 이 C 언어의 어구 와 저급 언어의 명령 은 간단 한 대응 관계 가 아니 라 a=b+1 이다.문 구 는 세 개의 어 셈 블 리 나 기계 명령 으로 번역 해 야 한다.이 과정 을 컴 파일(Compile)이 라 고 부 르 고 컴 파일 러(Compiler)로 완성 해 야 한다.컴 파일 러 의 기능 이 어 셈 블 리 보다 훨씬 복잡 한 것 이 분명 하 다.C 언어 로 작 성 된 프로그램 은 컴 파일 을 거 쳐 기계 명령 으로 전환 해 야 컴퓨터 에서 실 행 될 수 있 습 니 다.컴 파일 은 시간 이 좀 걸 립 니 다.이것 은 고급 언어 로 프로 그래 밍 하 는 단점 이지 만 장점 이 더 많 습 니 다.우선,C 언어 로 프로 그래 밍 하 는 것 이 더욱 쉽 고 쓴 코드 가 더욱 치밀 하 며 가 독성 이 강하 고 잘못 되면 고치 기 쉽다.
사람 이 쉽게 작성 하고 읽 으 며 유지 할 수 있 는 고급 컴퓨터 언어 로 작 성 된 소스 코드 프로그램 을 컴퓨터 가 해석 하고 실행 할 수 있 는 저급 기계 언어 로 번역 하 는 과정 은 컴 파일 하 는 것 입 니 다.이 과정 을 담당 하 는 도 구 를 컴 파일 러 라 고 합 니 다.
이제 우 리 는 컴 파일 이 무엇 인지 알 게 되 었 고 컴 파일 러 가 무엇 인지 알 게 되 었 다.서로 다른 언어 는 모두 자신의 컴 파일 러 가 있 습 니 다.자바 언어 에서 컴 파일 을 담당 하 는 컴 파일 러 는 명령 입 니 다:자바 c
javac 는 JDK 에 수 록 된 자바 언어 컴 파일 러 입 니 다.이 도 구 는 접미사 이름 이 자바 인 원본 파일 을 접미사 이름 이'class'인 자바 가상 컴퓨터 에서 실행 할 수 있 는 바이트 코드 로 컴 파일 할 수 있 습 니 다.
Hello World.java 파일 을 다 쓴 후에,우 리 는 javac Hello World.java 명령 을 사용 하여 Hello World.class 파일 을 생 성 할 수 있 습 니 다.이 class 형식의 파일 은 JVM 에서 식별 할 수 있 는 파일 입 니 다.일반적으로 우 리 는 이 과정 을 자바 언어의 컴 파일 이 라 고 생각한다.사실 클 라 스 파일 은 기계 가 식별 할 수 있 는 언어 가 아니다.기계 가 기계 언어 만 식별 할 수 있 기 때문에 JVM 이 이런 클 라 스 파일 형식 바이트 코드 를 기계 가 식별 할 수 있 는 기계 언어 로 변환 해 야 한다.
무엇이 역 컴 파일 입 니까?
역 컴 파일 과정 은 컴 파일 과 정반 대 입 니 다.컴 파일 된 프로 그래 밍 언어 를 컴 파일 되 지 않 은 상태 로 복원 하 는 것 입 니 다.즉,프로그램 언어의 소스 코드 를 찾 는 것 입 니 다.기계 가 알 아 볼 수 있 는 언어 를 프로그래머 가 알 아 볼 수 있 는 언어 로 바 꾸 는 것 이다.자바 언어의 역 컴 파일 은 일반적으로 클 라 스 파일 을 자바 파일 로 변환 하 는 것 을 말한다.
역 컴 파일 도구 가 있 으 면 우 리 는 많은 일 을 할 수 있다.가장 중요 한 기능 은 바로 역 컴 파일 도구 가 있 으 면 우 리 는 자바 컴 파일 러 가 생 성 한 바이트 코드 를 읽 을 수 있다.바이트 코드 를 읽 으 면 무슨 소 용이 있 는 지 물 어보 고 싶다 면,나 는 책임감 있 게 너 에 게 좋 은 점 이 매우 크다 고 말 할 수 있다.예 를 들 어 나의 박문 몇 편의 전형 적 인 원리 적 인 글 은 모두 반 컴 파일 도 구 를 통 해 반 컴 파일 된 코드 분석 을 통 해 얻 은 것 이다.예 를 들 어 다 중 스 레 드(1)-Synchronized 의 실현 원 리 를 깊이 이해 하고 자바 의 매 거 진 유형-매 거 진 스 레 드 안전성 과 직렬 화 문제,자바 의 Switch 가 정형,문자 형,문자열 형의 구체 적 인 실현 디 테 일,자바 의 유형 지우 기 등 이다.나 는 최근 에 GitChat 에서 자바 문법 사탕 에 관 한 글 을 썼 는데 그 중에서 대부분 내용 은 문법 사탕 뒤의 원 리 를 역 컴 파일 도구 로 파악 했다.
자바 역 컴 파일 도구
본 고 는 주로 자바 의 역 컴 파일 도구 3 개 를 소개 한다.자바 p,jad,cfr
javap
javap 는 jdk 가 자체 적 으로 가지 고 있 는 도구 로 코드 를 역 컴 파일 할 수도 있 고 자바 컴 파일 러 가 생 성 한 바이트 코드 도 볼 수 있 습 니 다.javap 와 다른 두 개의 역 컴 파일 도구 의 가장 큰 차 이 는 그 가 만 든 파일 이 자바 파일 이 아니 라 다른 두 도구 가 코드 를 만 드 는 것 처럼 쉽게 이해 되 지 않 는 다 는 것 이다.자바 7 의 switch 가 String 을 어떻게 지원 하 는 지 분석 하려 면 다음 과 같은 소스 코드 를 컴 파일 할 수 있 습 니 다.

public class switchDemoString {
 public static void main(String[] args) {
 String str = "world";
 switch (str) {
  case "hello":
  System.out.println("hello");
  break;
  case "world":
  System.out.println("world");
  break;
  default:
  break;
 }
 }
}
다음 두 명령 을 실행 합 니 다:

javac switchDemoString.java
javap -c switchDemoString.class
생 성 코드 는 다음 과 같 습 니 다:

public class com.hollis.suguar.switchDemoString {
 public com.hollis.suguar.switchDemoString();
 Code:
 0: aload_0
 1: invokespecial #1   // Method java/lang/Object."<init>":()V
 4: return

 public static void main(java.lang.String[]);
 Code:
 0: ldc  #2   // String world
 2: astore_1
 3: aload_1
 4: astore_2
 5: iconst_m1
 6: istore_3
 7: aload_2
 8: invokevirtual #3   // Method java/lang/String.hashCode:()I
 11: lookupswitch { // 2
  99162322: 36
  113318802: 50
  default: 61
  }
 36: aload_2
 37: ldc  #4   // String hello
 39: invokevirtual #5   // Method java/lang/String.equals:(Ljava/lang/Object;)Z
 42: ifeq  61
 45: iconst_0
 46: istore_3
 47: goto  61
 50: aload_2
 51: ldc  #2   // String world
 53: invokevirtual #5   // Method java/lang/String.equals:(Ljava/lang/Object;)Z
 56: ifeq  61
 59: iconst_1
 60: istore_3
 61: iload_3
 62: lookupswitch { // 2
   0: 88
   1: 99
  default: 110
  }
 88: getstatic #6   // Field java/lang/System.out:Ljava/io/PrintStream;
 91: ldc  #4   // String hello
 93: invokevirtual #7   // Method java/io/PrintStream.println:(Ljava/lang/String;)V
 96: goto  110
 99: getstatic #6   // Field java/lang/System.out:Ljava/io/PrintStream;
 102: ldc  #2   // String world
 104: invokevirtual #7   // Method java/io/PrintStream.println:(Ljava/lang/String;)V
 107: goto  110
 110: return
}
개인 적 으로 자바 p 는 바이트 코드 를 자바 파일 로 역 컴 파일 하지 않 고 우리 가 볼 수 있 는 바이트 코드 를 만 들 었 다 는 것 을 이해 합 니 다.사실 자바 p 에서 생 성 된 파일 은 여전히 바이트 코드 입 니 다.프로그래머 만 조금 알 아 볼 수 있 습 니 다.바이트 코드 에 대해 잘 알 고 있다 면 이상 의 코드 를 볼 수 있 습 니 다.사실은 String 을 hashcode 로 바 꾸 고 비교 하 는 것 입 니 다.
개인 적 으로 일반적인 상황 에서 우 리 는 자바 p 명령 을 사용 할 때 가 많 지 않 고 보통 바이트 코드 를 볼 때 만 사용 할 수 있다 고 생각 합 니 다.그러나 바이트 코드 중간 에 노출 된 것 이 가장 완전 합 니 다.당신 은 반드시 사용 할 기회 가 있 을 것 입 니 다.예 를 들 어 제 가 synchronized 의 원 리 를 분석 할 때 자바 p 를 사용 합 니 다.javap 를 통 해 생 성 된 바이트 코드 를 통 해 synchronized 바 텀 이 ACC 에 의존 하고 있 음 을 알 게 되 었 습 니 다.SYNCHRONIZED 태그 와 Monitorenter,Monitorexit 두 가지 명령 으로 동기 화 를 실현 합 니 다.
jad
jad 는 실행 도 구 를 다운로드 하면 class 파일 에 대한 역 컴 파일 을 실현 할 수 있 는 비교적 좋 은 역 컴 파일 도구 입 니 다.아니면 위의 소스 코드 입 니까?jad 를 사용 하여 역 컴 파일 한 내용 은 다음 과 같 습 니 다.
명령:jad switchDemoString.class

public class switchDemoString
{
 public switchDemoString()
 {
 }
 public static void main(String args[])
 {
 String str = "world";
 String s;
 switch((s = str).hashCode())
 {
 default:
  break;
 case 99162322:
  if(s.equals("hello"))
  System.out.println("hello");
  break;
 case 113318802:
  if(s.equals("world"))
  System.out.println("world");
  break;
 }
 }
}
봐 라,이 코드 는 틀림없이 알 아 볼 수 있 을 것 이다.왜냐하면 이것 은 표준 자바 의 소스 코드 가 아니 기 때문이다.이것 은 원래 문자열 의 switch 가 equals()와 hashCode()방법 을 통 해 이 루어 진 것 을 똑똑히 볼 수 있다.
그러나 jad 는 오랫동안 업데이트 되 지 않 았 습 니 다.자바 7 에서 생 성 된 바이트 코드 를 역 컴 파일 할 때 지원 되 지 않 는 문제 가 발생 할 수 있 습 니 다.자바 8 의 lambda 표현 식 을 역 컴 파일 할 때 완전히 실 패 했 습 니 다.
CFR
jad 는 아주 좋 습 니 다.그러나 어 쩔 수 없 이 오랫동안 업데이트 되 지 않 았 기 때문에 새로운 도구 로 그 를 대체 할 수 밖 에 없습니다.CFR 은 좋 은 선택 입 니 다.jad 에 비해 그의 문법 은 약간 복잡 할 수 있 지만 다행히 그 는 work 할 수 있 습 니 다.
예 를 들 어,우 리 는 cfr 를 사용 하여 방금 코드 를 역 컴 파일 합 니 다.명령 실행 하기:

java -jar cfr_0_125.jar switchDemoString.class --decodestringswitch false
다음 코드 받 기:

public class switchDemoString {
 public static void main(String[] arrstring) {
 String string;
 String string2 = string = "world";
 int n = -1;
 switch (string2.hashCode()) {
  case 99162322: {
  if (!string2.equals("hello")) break;
  n = 0;
  break;
  }
  case 113318802: {
  if (!string2.equals("world")) break;
  n = 1;
  }
 }
 switch (n) {
  case 0: {
  System.out.println("hello");
  break;
  }
  case 1: {
  System.out.println("world");
  break;
  }
 }
 }
}
이 코드 를 통 해 문자열 을 얻 을 수 있 는 switch 는 equals()와 hashCode()방법 으로 이 루어 진 결론 입 니 다.
Jad 에 비해 CFR 은 인자 가 많 고 방금 코드 입 니 다.다음 명령 을 사용 하면 출력 결과 가 다 릅 니 다.

java -jar cfr_0_125.jar switchDemoString.class

public class switchDemoString {
 public static void main(String[] arrstring) {
 String string;
 switch (string = "world") {
  case "hello": {
  System.out.println("hello");
  break;
  }
  case "world": {
  System.out.println("world");
  break;
  }
 }
 }
}
그래서--decodestringswitch 는 switch 가 string 을 지원 하 는 디 테 일 을 디 코딩 하 는 것 을 표시 합 니 다.비슷 한 것 은 decodeenumswitch,decodefinally,decodelambdas 등 이 있다.문법 사탕 에 관 한 글 에서 저 는-decodelambda 표현 식 경찰 을 역 컴 파일 했 습 니 다.원본 코드:

public static void main(String... args) {
 List<String> strList = ImmutableList.of("Hollis", "   :Hollis", "  :www.hollischuang.com");

 strList.forEach( s -> { System.out.println(s); } );
}
java -jar cfr_0_125.jar lambdaDemo.class--decodelambdas false 컴 파일 후 코드:

public static /* varargs */ void main(String ... args) {
 ImmutableList strList = ImmutableList.of((Object)"Hollis", (Object)"\u516c\u4f17\u53f7\uff1aHollis", (Object)"\u535a\u5ba2\uff1awww.hollischuang.com");
 strList.forEach((Consumer<String>)LambdaMetafactory.metafactory(null, null, null, (Ljava/lang/Object;)V, lambda$main$0(java.lang.String ), (Ljava/lang/String;)V)());
}

private static /* synthetic */ void lambda$main$0(String s) {
 System.out.println(s);
}
CFR 에는 또 많은 다른 매개 변수 가 있 는데 모두 다른 장면 에 사용 되 며 독 자 는 자바-jar cfr 를 사용 할 수 있 습 니 다.0_125.jar--help 에 대해 알 아 봅 니 다.여기 하나씩 소개 안 할 게 요.
어떻게 역 컴 파일 을 방지 합 니까?
Class 파일 을 역 컴 파일 할 수 있 는 도구 가 있 기 때문에 개발 자 에 게 자바 프로그램 을 어떻게 보호 하 느 냐 가 매우 중요 한 도전 이 되 었 습 니 다.그러나 마 는 한 자 높 고,도 는 한 장 높다.당연히 대응 하 는 기술 이 있 지.역 컴 파일 에 대응 할 수 있 지.그러나 여기 서 한 가지 설명 을 해 야 한다.네트워크 안전 의 보호 와 마찬가지 로 아무리 노력 해도 사실은 공격 자의 원 가 를 높이 는 것 일 뿐이다.철저하게 예방 치료 할 방법 이 없다.
전형 적 인 대응 전략 은 다음 과 같은 몇 가지 가 있다.
격 리 자바 프로그램
  • 사용자 가 당신 의 Class 파일 을 접 하지 못 하 게 합 니 다
  • 클래스 파일 암호 화
    난이도
    코드 혼동
    코드 를 기능 상 등가 로 바 꾸 지만 읽 기와 이해 하기 어 려 운 형식총결산
    이상 은 이 글 의 모든 내용 입 니 다.본 고의 내용 이 여러분 의 학습 이나 업무 에 어느 정도 참고 학습 가 치 를 가지 기 를 바 랍 니 다.여러분 의 저희 에 대한 지지 에 감 사 드 립 니 다.

    좋은 웹페이지 즐겨찾기