【Python】PyCodeObject与pyc文件

2018-12-05  本文已影响20人  lndyzwdxhs

0x00 前言

0x01 PyCodeObject

typedef struct {
    PyObject_HEAD
    int co_argcount;        /*Code Block位置参数的个数 #arguments, except *args */
    int co_nlocals;     /*Code Block中局部变量的个数,包括位置参数的个数 #local variables */
    int co_stacksize;       /*执行该段Code Block需要的栈空间 #entries needed for evaluation stack */
    int co_flags;       /* CO_..., see below */
    PyObject *co_code;      /*Code Block编译得到的字节码指令序列 instruction opcodes */
    PyObject *co_consts;    /*Code Block中的所有常量 list (constants used) */
    PyObject *co_names;     /*Code Block中的所有符号 list of strings (names used) */
    PyObject *co_varnames;  /*Code Block中局部变量名集合 tuple of strings (local variable names) */
    PyObject *co_freevars;  /*实现闭包需要的对象 tuple of strings (free variable names) */
    PyObject *co_cellvars;      /*Code Block中内部嵌套函数所引用的局部变量名集合 tuple of strings (cell variable names) */
    /* The rest doesn't count for hash/cmp */
    PyObject *co_filename;  /*Code Block对应的py文件的完整路径 string (where it was loaded from) */
    PyObject *co_name;      /*Code Block的名字,通常是函数名或类名 string (name, for reference) */
    int co_firstlineno;     /*Code Block在对应的py文件中的起始行 first source line number */
    PyObject *co_lnotab;    /*字节码指令与py文件中源代码行号的对应关系 string (encoding addr<->lineno mapping) */
    void *co_zombieframe;     /* for optimization only (see frameobject.c) */
} PyCodeObject;

字节码

/* opcode.h */
#define STOP_CODE   0
#define POP_TOP     1
#define ROT_TWO     2
#define ROT_THREE   3
#define DUP_TOP     4
#define ROT_FOUR    5
#define NOP     9

#define UNARY_POSITIVE  10
#define UNARY_NEGATIVE  11
#define UNARY_NOT   12
#define UNARY_CONVERT   13

#define UNARY_INVERT    15

#define LIST_APPEND 18
#define BINARY_POWER    19

#define BINARY_MULTIPLY 20
#define BINARY_DIVIDE   21
#define BINARY_MODULO   22
#define BINARY_ADD  23
#define BINARY_SUBTRACT 24
#define BINARY_SUBSCR   25
#define BINARY_FLOOR_DIVIDE 26
#define BINARY_TRUE_DIVIDE 27
#define INPLACE_FLOOR_DIVIDE 28
#define INPLACE_TRUE_DIVIDE 29

#define SLICE       30
/* Also uses 31-33 */

#define STORE_SLICE 40
/* Also uses 41-43 */

#define DELETE_SLICE    50
/* Also uses 51-53 */

#define INPLACE_ADD 55
#define INPLACE_SUBTRACT    56
#define INPLACE_MULTIPLY    57
#define INPLACE_DIVIDE  58
#define INPLACE_MODULO  59
#define STORE_SUBSCR    60
#define DELETE_SUBSCR   61

#define BINARY_LSHIFT   62
#define BINARY_RSHIFT   63
#define BINARY_AND  64
#define BINARY_XOR  65
#define BINARY_OR   66
#define INPLACE_POWER   67
#define GET_ITER    68

#define PRINT_EXPR  70
#define PRINT_ITEM  71
#define PRINT_NEWLINE   72
#define PRINT_ITEM_TO   73
#define PRINT_NEWLINE_TO 74
#define INPLACE_LSHIFT  75
#define INPLACE_RSHIFT  76
#define INPLACE_AND 77
#define INPLACE_XOR 78
#define INPLACE_OR  79
#define BREAK_LOOP  80
#define WITH_CLEANUP    81
#define LOAD_LOCALS 82
#define RETURN_VALUE    83
#define IMPORT_STAR 84
#define EXEC_STMT   85
#define YIELD_VALUE 86
#define POP_BLOCK   87
#define END_FINALLY 88
#define BUILD_CLASS 89

#define HAVE_ARGUMENT   90  /* Opcodes from here have an argument: */

#define STORE_NAME  90  /* Index in name list */
#define DELETE_NAME 91  /* "" */
#define UNPACK_SEQUENCE 92  /* Number of sequence items */
#define FOR_ITER    93

#define STORE_ATTR  95  /* Index in name list */
#define DELETE_ATTR 96  /* "" */
#define STORE_GLOBAL    97  /* "" */
#define DELETE_GLOBAL   98  /* "" */
#define DUP_TOPX    99  /* number of items to duplicate */
#define LOAD_CONST  100 /* Index in const list */
#define LOAD_NAME   101 /* Index in name list */
#define BUILD_TUPLE 102 /* Number of tuple items */
#define BUILD_LIST  103 /* Number of list items */
#define BUILD_MAP   104 /* Always zero for now */
#define LOAD_ATTR   105 /* Index in name list */
#define COMPARE_OP  106 /* Comparison operator */
#define IMPORT_NAME 107 /* Index in name list */
#define IMPORT_FROM 108 /* Index in name list */

#define JUMP_FORWARD    110 /* Number of bytes to skip */
#define JUMP_IF_FALSE   111 /* "" */
#define JUMP_IF_TRUE    112 /* "" */
#define JUMP_ABSOLUTE   113 /* Target byte offset from beginning of code */

#define LOAD_GLOBAL 116 /* Index in name list */

#define CONTINUE_LOOP   119 /* Start of loop (absolute) */
#define SETUP_LOOP  120 /* Target address (relative) */
#define SETUP_EXCEPT    121 /* "" */
#define SETUP_FINALLY   122 /* "" */

#define LOAD_FAST   124 /* Local variable number */
#define STORE_FAST  125 /* Local variable number */
#define DELETE_FAST 126 /* Local variable number */

#define RAISE_VARARGS   130 /* Number of raise arguments (1, 2 or 3) */
/* CALL_FUNCTION_XXX opcodes defined below depend on this definition */
#define CALL_FUNCTION   131 /* #args + (#kwargs<<8) */
#define MAKE_FUNCTION   132 /* #defaults */
#define BUILD_SLICE     133 /* Number of items */

#define MAKE_CLOSURE    134     /* #free vars */
#define LOAD_CLOSURE    135     /* Load free variable from closure */
#define LOAD_DEREF      136     /* Load and dereference from closure cell */ 
#define STORE_DEREF     137     /* Store into cell */ 

/* The next 3 opcodes must be contiguous and satisfy
   (CALL_FUNCTION_VAR - CALL_FUNCTION) & 3 == 1  */
#define CALL_FUNCTION_VAR          140  /* #args + (#kwargs<<8) */
#define CALL_FUNCTION_KW           141  /* #args + (#kwargs<<8) */
#define CALL_FUNCTION_VAR_KW       142  /* #args + (#kwargs<<8) */

/* Support for opargs more than 16 bits long */
#define EXTENDED_ARG  143

0x02 pyc文件

pyc文件的读写

static void
write_compiled_module(PyCodeObject *co, char *cpathname, time_t mtime)
{
    FILE *fp;

    fp = open_exclusive(cpathname);
    if (fp == NULL) {
        if (Py_VerboseFlag)
            PySys_WriteStderr(
                "# can't create %s\n", cpathname);
        return;
    }
    /* ==写入magic number */
    PyMarshal_WriteLongToFile(pyc_magic, fp, Py_MARSHAL_VERSION);
    /* First write a 0 for mtime */
    /* ==写入时间信息 */
    PyMarshal_WriteLongToFile(0L, fp, Py_MARSHAL_VERSION);
    /* ==写入PyCodeObject对象信息 */
    PyMarshal_WriteObjectToFile((PyObject *)co, fp, Py_MARSHAL_VERSION);
    if (fflush(fp) != 0 || ferror(fp)) {
        if (Py_VerboseFlag)
            PySys_WriteStderr("# can't write %s\n", cpathname);
        /* Don't keep partial file */
        fclose(fp);
        (void) unlink(cpathname);
        return;
    }
    /* Now write the true mtime */
    fseek(fp, 4L, 0);
    assert(mtime < LONG_MAX);
    PyMarshal_WriteLongToFile((long)mtime, fp, Py_MARSHAL_VERSION);
    fflush(fp);
    fclose(fp);
    if (Py_VerboseFlag)
        PySys_WriteStderr("# wrote %s\n", cpathname);
}
void
PyMarshal_WriteLongToFile(long x, FILE *fp, int version)
{
    WFILE wf;
    wf.fp = fp;
    wf.error = 0;
    wf.depth = 0;
    wf.strings = NULL;
    wf.version = version;
    w_long(x, &wf);
}

void
PyMarshal_WriteObjectToFile(PyObject *x, FILE *fp, int version)
{
    WFILE wf;
    wf.fp = fp;
    wf.error = 0;
    wf.depth = 0;
    wf.strings = (version > 0) ? PyDict_New() : NULL;
    wf.version = version;
    w_object(x, &wf);
    Py_XDECREF(wf.strings);
}
#define TYPE_NULL       '0'
#define TYPE_NONE       'N'
#define TYPE_FALSE      'F'
#define TYPE_TRUE       'T'
#define TYPE_STOPITER       'S'
#define TYPE_ELLIPSIS       '.'
#define TYPE_INT        'i'
#define TYPE_INT64      'I'
#define TYPE_FLOAT      'f'
#define TYPE_BINARY_FLOAT   'g'
#define TYPE_COMPLEX        'x'
#define TYPE_BINARY_COMPLEX 'y'
#define TYPE_LONG       'l'
#define TYPE_STRING     's'
#define TYPE_INTERNED       't'
#define TYPE_STRINGREF      'R'
#define TYPE_TUPLE      '('
#define TYPE_LIST       '['
#define TYPE_DICT       '{'
#define TYPE_CODE       'c'
#define TYPE_UNICODE        'u'
#define TYPE_UNKNOWN        '?'
#define TYPE_SET        '<'
#define TYPE_FROZENSET      '>'

字符串写入pyc文件

typedef struct {
    FILE *fp;
    int error;
    int depth;
    /* If fp == NULL, the following are valid: */
    PyObject *str;
    char *ptr;
    char *end;
    PyObject *strings; /* dict on marshal, list on unmarshal */
    int version;
} WFILE;
/* w_object中处理string的代码 */
else if (PyString_Check(v)) {
        if (p->strings && PyString_CHECK_INTERNED(v)) {
            PyObject *o = PyDict_GetItem(p->strings, v);
            if (o) {
                long w = PyInt_AsLong(o);
                w_byte(TYPE_STRINGREF, p);
                w_long(w, p);
                goto exit;
            }
            else {
                int ok;
                o = PyInt_FromSsize_t(PyDict_Size(p->strings));
                ok = o &&
                     PyDict_SetItem(p->strings, v, o) >= 0;
                Py_XDECREF(o);
                if (!ok) {
                    p->depth--;
                    p->error = 1;
                    return;
                }
                w_byte(TYPE_INTERNED, p);
            }
        }
        else {
            w_byte(TYPE_STRING, p);
        }
        n = PyString_GET_SIZE(v);
        if (n > INT_MAX) {
            /* huge strings are not supported */
            p->depth--;
            p->error = 1;
            return;
        }
        w_long((long)n, p);
        w_string(PyString_AS_STRING(v), (int)n, p);
    }

pyc文件读出字符串

PyObject *
PyMarshal_ReadObjectFromFile(FILE *fp)
{
    RFILE rf;
    PyObject *result;
    rf.fp = fp;
    rf.strings = PyList_New(0);
    rf.depth = 0;
    rf.ptr = rf.end = NULL;
    result = r_object(&rf);
    Py_DECREF(rf.strings);
    return result;
}

欢迎关注微信公众号(coder0x00)或扫描下方二维码关注,我们将持续搜寻程序员必备基础技能包提供给大家。


上一篇 下一篇

猜你喜欢

热点阅读