python에서 원시 바이트 코드를 만드는 방법

소개하다.


우선, 나는 github.io에서 이 일을 시작했지만, 나중에 한 무리의 사이버 도적들이 나를 때려서 이 신기한 사이트를 가지는 것은 무의미하다는 것을 깨달았다.그래, 그렇다. 나는 이것을 사용한다. 제목에서 말한 바와 같이 이것은 원시적인python 바이트 코드 강좌이다. 나는 네가 그것을 좋아하길 바란다. (두 번째 부분이 있기 때문이다.)

선결 조건

  • 파이톤의 기본 지식
  • 바이트 객체 파악
  • stack의 개념 이해
  • 파이썬이란?


    파이톤은 다중 반경 해석의 프로그래밍 언어로 다중성, 대상방향 프로그래밍(OOP/OOP)과 명령식 프로그래밍을 지원한다.

    그것은 어떻게 일합니까?


    파이썬은 이름이 붙은 것처럼 해석적인 언어이다. 이것은 컴퓨터가 할 일과 당신이 쓴 것을 해석기를 통해 연결한다는 것을 의미한다.파이톤은 C나 C++ 프로그램처럼 기계 코드를 만들지 않고 자바처럼 많이 혹은 적게 작동하며 바이트 코드를 설명하는 가상 컴퓨터를 가지고 있다.이 기본 해석기는 CPython입니다. 컴퓨터에서 바이트 코드를 실행하는 것을 책임집니다.여기서 우리는 컴파일러를 사용하지 않고 언어를 처리해야 한다. 기본적으로 서면 코드를 바이트 코드로 번역한 후에 이를 해석하는 해석기이다.그 중에는 IronPython(C# 구현), Jython(순수 자바 구현), Micropython(마이크로 컨트롤러에서 실행되는 C 버전으로 최적화) 등 여러 가지가 있다.
    다음은 Python의 작업 원리도와 작성한 코드를 해석기가 실행하는 절차입니다.

    사용 가능한 바이트 코드를 만드는 방법


    알겠습니다. 첫째, 바이트 코드, 즉 16진 바이트를 박리하고, 조작 코드와 파라미터를 표시합니다. 둘째, 우리는 CodeType이 있습니다. 파이톤의 데이터 형식은 우리가 적합하고 사용할 수 있는 바이트 코드를 만드는 데 도움을 줍니다.마찬가지로 조립을 위해서, 당신은 어떻게 어셈블리를 하는지 알아야 합니다. 우리는 모듈 dis을 사용할 것입니다. 이 모듈은 어셈블리 함수, 파일, 코드에 사용됩니다.
    import dis
    
    def sum (x, y):
        return x + y
    dis.dis (sum)
    
    
    이 코드의 출력은 다음과 같다
    1. 4   0 LOAD_FAST    0 (x)
    2.     2 LOAD_FAST    1 (y)
    3.     4 BINARY_ADD
    4.     6 RETURN_VALUE
    >>>
    
    보시다시피 이 모든 것은 바이트 코드입니다. 지금은 설명입니다.
    보시다시피, 더 쉽게 설명할 수 있도록 출력의 줄을 열거했습니다.
    파이톤의 모든 지령은 특정한 조작 코드(조작 코드)가 있다. 이 예에서 우리는 3LOAD_FAST BINARY_ADD RETURN_VALUE을 사용하고 각 지령의 역할을 설명할 것이다.
  • LOAD F.A.S.T: 스택 상단(스택 상단)에 변수를 로드합니다.
  • 바이너리 ADD: 두 값 더하기​​창고 꼭대기에서 그것들을 창고 꼭대기로 되돌려줍니다.
  • RETURN VALUE: TOS의 값을 반환합니다.
  • 자, 이제 조작 코드를 설명했으니, 우리는 이해할 수 있다​​우리의 코드가 내부에서 어떻게 작동하는지 의문이 있다. 짜증나지만 필요한 의문이 있다. 예를 들어'왼쪽의 4는 무엇이고, 첫 줄의 4는 무엇입니까?'"조작코드 왼쪽의 숫자는 얼마예요?"0이(가) LOAD F.A.S.T. 오른쪽에 나타나는 이유는 무엇입니까?1번은요?","0과 1이 아닌 xy을 불러오고 싶지 않습니다.".
    그래, 순서대로 대답할게.
  • 4는 어셈블리 바이트 코드의 시작 줄입니다.
  • 은 바이트의 offset을 나타냅니다.
  • 0 0과 1은 하나의 인덱스에 대응한다. 코드의 변수는 하나의 목록(수조)에 저장되고 0과 1은 인덱스를 대표하기 때문이다. 그러나 모듈 디스는 이 숫자의 오른쪽에 있는 변수를 알려준다(따라서 0 (x)(y)). *
  • 우리는 어떻게 함수를 다시 만들어서 바이트 코드로 만듭니까?


    우리가 해야 할 첫 번째 일은 [types] 모듈(https://docs.python.org/3/library/types.html#module-types)에서 CodeTypeFunctionType을 가져오는 것이다.
    import dis
    from types import CodeType, FunctionType
    
    def sum (x, y):
        return x + y
    
    이후, 우리는 목표 코드를 만들 것이다
    활용단어참조
    import dis
    from types import CodeType, FunctionType
    
    def sum (x, y):
        return x + y
    
    # This will be explained later, these are flags
    CO_OPTIMIZED = 0x0001
    CO_NEWLOCALS = 0x0002
    CO_NOFREE = 0x0002
    
    my_code = CodeType (
        2, #argcount
        0, #kwonlyargcount
        2, #nlocals
        2, #stacksize
        (CO_OPTIMIZED | CO_NEWLOCALS | CO_NOFREE), #flags
        bytes ([124, 0, 124, 1, 23, 0, 83, 0]), #codestring
        (0,), #constants
        (), # names of constants or global (names)
        ('x', 'y',), #variable names (varnames)
        'blog_no_name', #filename
        'crafted_sum', #name (code name / function)
         9, #Firstlineno (First line where this code appears)
         b'', #lnotab
         (), #freevars
         (), # freecellvars
         )
    
    _sum = FunctionType (my_code, {})
    result = _sum (213,3)
    print (result)
    
    # Expected output
    # 216
    
    그래 그래...많은 새로운 사물이 출현했으니, 우리는 지금 이 논점들을 해석할 것이다.CodeType: argcount, kwonlyargcount, nlocals, stacksize, flags, codestring, constants, names, varnames, filename, name, firstlineno, lnotab, freevars, freecellvars논쟁하다
    묘사
    argcount
    매개변수 수
    kwonlyargcount
    키워드 매개변수 수
    nlocals
    국부 변수의 수량 (이 예에서 2, x, y)
    스택 크기
    스택의 최대 바이트 크기(이 경우 XY는 스택 프레임에 두 개의 공백이 필요하므로 2입니다.)
    깃발
    이 표지들은 바이트 코드의 일부 조건을 결정합니다. 당신은 이 reference 에 따라 지도할 수 있습니다.우리는 더욱 높은 교과서에서 깃발을 깊이 연구할 것이다.
    코드 열
    이것은 124에서 LOAD F.A.S.T., 23 BINARY ADD 및 83 RETURN VALUE를 의미하는 관련 시퀀스가 포함된 바이트 목록(배열)입니다.
    상수
    정수, False, True, 내장 함수와 같은 상수 값이 포함된 원조
    성함
    상수 이름을 포함하는 모듈
    varnames
    로컬 변수 이름
    파일 이름
    이 문자열은 파일 이름을 나타냅니다. 이 값을 사용하지 않을 때는 모든 문자열이 될 수 있습니다
    성함
    코드 객체 또는 함수의 이름
    일선 번호
    실행 코드의 첫 줄을 표시합니다. 파일을 가져오면 이것과 관련이 있습니다. 그렇지 않으면 정수일 수 있습니다.
    나타브
    이것은 바이트 대상의 편이량과 줄의 편이량 사이의 매핑입니다. 줄에 정보를 추가하지 않으려면 b''을 사용하십시오
    프리바
    나는 고급 강좌에서 이 변수들을 설명할 것이다. 이것은 패키지를 닫는 데 쓰일 것이다
    cellvars
    이 변수는 패키지에서 정의됩니다FunctionType으로 넘어가기 전에 주의해야 할 마지막 두 가지는 첫 번째는 조작 코드 뒤의 0*이다. 예를 들어 [124, 0,...] *두 번째는 각 바이트 코드가 버전에 따라 다를 수 있으므로 코드 문자열의 방향을 파악하거나 확인하려면 아래 snippet을 사용하십시오
    def sum (x, y):
        return x + y
    sum.__ code __.co_code
    
    # Expected output in Python 3.7.9 (The version I use)
    # b '|\x00|\x01\x17\x00S\x00'
    # The bytes are interpreted as characters, probably to make it more readable. (If we put chr (124) it will print the character |)
    

    제조 기능


    이제 FunctionType을 사용합니다.FunctionType: code, globals, name, argdefs, closure논쟁하다
    묘사
    비밀 번호
    대상 코드(osea, 코드 유형)
    글로벌
    전역 변수를 포함하는 사전입니다. '{"Name: Value Name}' 이렇게 하면 Name은 식별자가 되고 접근 변수처럼 접근합니다.
    이름(옵션)
    객체 코드 값 덮어쓰기)
    argdefs(선택 사항)
    기본 매개 변수 값을 지정하는 모듈
    닫기(옵션)
    하나의 모듈이freevars에 연결을 제공합니다
    좋습니다. 일단 명확해지면, 목표 코드 (my_code) 가 있는FunctionType을 추가하고 호출하기만 하면 됩니다.
    import dis
    from types import CodeType, FunctionType
    
    def sum (x, y):
        return x + y
    
    이후, 우리는 목표 코드를 만들 것이다
    import dis
    from types import CodeType, FunctionType
    
    def sum (x, y):
        return x + y
    
    # This I will explain later, they are flags
    CO_OPTIMIZED = 0x0001
    CO_NEWLOCALS = 0x0002
    CO_NOFREE = 0x0002
    
    my_code = CodeType (
        2, #argcount
        0, #kwonlyargcount
        2, #nlocals
        2, #stacksize
        (CO_OPTIMIZED | CO_NEWLOCALS | CO_NOFREE), #flags
        bytes ([124, 0, 124, 1, 23, 0, 83, 0]), #codestring
        (0,), #constants
        (), # names of constants or global (names)
        ('x', 'y',), #variable names (varnames)
        'blog_no_name', #filename
        'crafted_sum', #name (code / function name)
        9, #Firstlineno (First line where this code appears)
        b '', #lnotab
        (), #freevars
        (), # freecellvars
        )
    
    _sum = FunctionType (my_code, {})
    result = _sum (213,3)
    print (result)
    
    # Expected output
    # 216
    
    지금 이 정도입니다. 잠시 후에 다른 강좌를 올리겠습니다. 설명 closures

    출처

  • Module dis
  • How does Python work?
  • Flags and other useful data
  • Freevar, Cellvars and local variables
  • Scott Sanderson and Joe Jevnik "Playing with Python bytecode"
  • 좋은 웹페이지 즐겨찾기