From 6960b313292df84253896457621c94d89848d6e1 Mon Sep 17 00:00:00 2001 From: Peter Johnson Date: Mon, 24 Mar 2003 06:54:17 +0000 Subject: [PATCH] Add Win32 object format (untested, but compared against NASM output). svn path=/trunk/yasm/; revision=884 --- modules/objfmts/Makefile.inc | 4 +- modules/objfmts/coff/coff-objfmt.c | 273 ++++++-- modules/objfmts/win32/Makefile.inc | 14 + modules/objfmts/win32/tests/Makefile.inc | 11 + modules/objfmts/win32/tests/win32test.asm | 82 +++ modules/objfmts/win32/tests/win32test.c | 34 + modules/objfmts/win32/tests/win32test.errwarn | 0 modules/objfmts/win32/tests/win32test.hex | 660 ++++++++++++++++++ 8 files changed, 1038 insertions(+), 40 deletions(-) create mode 100644 modules/objfmts/win32/Makefile.inc create mode 100644 modules/objfmts/win32/tests/Makefile.inc create mode 100644 modules/objfmts/win32/tests/win32test.asm create mode 100644 modules/objfmts/win32/tests/win32test.c create mode 100644 modules/objfmts/win32/tests/win32test.errwarn create mode 100644 modules/objfmts/win32/tests/win32test.hex diff --git a/modules/objfmts/Makefile.inc b/modules/objfmts/Makefile.inc index dc191c0f..82c45658 100644 --- a/modules/objfmts/Makefile.inc +++ b/modules/objfmts/Makefile.inc @@ -3,8 +3,10 @@ EXTRA_DIST += \ modules/objfmts/dbg/Makefile.inc \ modules/objfmts/bin/Makefile.inc \ - modules/objfmts/coff/Makefile.inc + modules/objfmts/coff/Makefile.inc \ + modules/objfmts/win32/Makefile.inc include modules/objfmts/dbg/Makefile.inc include modules/objfmts/bin/Makefile.inc include modules/objfmts/coff/Makefile.inc +include modules/objfmts/win32/Makefile.inc diff --git a/modules/objfmts/coff/coff-objfmt.c b/modules/objfmts/coff/coff-objfmt.c index 95d88489..7cc5a511 100644 --- a/modules/objfmts/coff/coff-objfmt.c +++ b/modules/objfmts/coff/coff-objfmt.c @@ -40,7 +40,7 @@ * with VMA=0. Who's right? This is #defined as changing this setting affects * several places in the code. */ -#define COFF_SET_VMA 1 +#define COFF_SET_VMA (!win32) #define COFF_I386MAGIC 0x14C @@ -60,16 +60,26 @@ typedef struct coff_reloc { } type; /* type of relocation */ } coff_reloc; -typedef enum coff_section_data_flags { - COFF_STYP_TEXT = 0x0020, - COFF_STYP_DATA = 0x0040, - COFF_STYP_BSS = 0x0080 -} coff_section_data_flags; +#define COFF_STYP_TEXT 0x00000020UL +#define COFF_STYP_DATA 0x00000040UL +#define COFF_STYP_BSS 0x00000080UL +#define COFF_STYP_INFO 0x00000200UL +#define COFF_STYP_STD_MASK 0x000003FFUL +#define COFF_STYP_ALIGN_MASK 0x00F00000UL +#define COFF_STYP_ALIGN_SHIFT 20 +#define COFF_STYP_DISCARD 0x02000000UL +#define COFF_STYP_NOCACHE 0x04000000UL +#define COFF_STYP_NOPAGE 0x08000000UL +#define COFF_STYP_SHARED 0x10000000UL +#define COFF_STYP_EXECUTE 0x20000000UL +#define COFF_STYP_READ 0x40000000UL +#define COFF_STYP_WRITE 0x80000000UL +#define COFF_STYP_WIN32_MASK 0xFE000000UL typedef struct coff_section_data { /*@dependent@*/ yasm_symrec *sym; /* symbol created for this section */ unsigned int scnum; /* section number (1=first section) */ - coff_section_data_flags flags; + unsigned long flags; /* section flags (see COFF_STYP_* above) */ unsigned long addr; /* starting memory address (first section -> 0) */ unsigned long scnptr; /* file ptr to raw data */ unsigned long size; /* size of raw data (section data) in bytes */ @@ -150,6 +160,9 @@ static coff_symtab_head coff_symtab; /* symbol table of indexed syms */ yasm_objfmt yasm_coff_LTX_objfmt; static /*@dependent@*/ yasm_arch *cur_arch; +/* Set nonzero for win32 output. */ +static int win32; + static /*@dependent@*/ coff_symtab_entry * coff_objfmt_symtab_append(yasm_symrec *sym, coff_symrec_sclass sclass, @@ -192,7 +205,7 @@ coff_objfmt_append_local_sym(yasm_symrec *sym, /*@unused@*/ /*@null@*/ void *d) } static void -coff_objfmt_initialize(const char *in_filename, +coff_common_initialize(const char *in_filename, /*@unused@*/ const char *obj_filename, /*@unused@*/ yasm_dbgfmt *df, yasm_arch *a) { @@ -220,6 +233,22 @@ coff_objfmt_initialize(const char *in_filename, STAILQ_INSERT_TAIL(&coff_symtab, entry, link); } +static void +coff_objfmt_initialize(const char *in_filename, const char *obj_filename, + yasm_dbgfmt *df, yasm_arch *a) +{ + win32 = 0; + coff_common_initialize(in_filename, obj_filename, df, a); +} + +static void +win32_objfmt_initialize(const char *in_filename, const char *obj_filename, + yasm_dbgfmt *df, yasm_arch *a) +{ + win32 = 1; + coff_common_initialize(in_filename, obj_filename, df, a); +} + static int coff_objfmt_set_section_addr(yasm_section *sect, /*@null@*/ void *d) { @@ -283,15 +312,17 @@ coff_objfmt_output_expr(yasm_expr **ep, unsigned char **bufp, reloc->sym = sym; vis = yasm_symrec_get_visibility(sym); if (vis & YASM_SYM_COMMON) { - /*@dependent@*/ /*@null@*/ coff_symrec_data *csymd; - - /* COMMON symbols have their length added in */ - csymd = yasm_symrec_get_of_data(sym); - assert(csymd != NULL); - *ep = yasm_expr_new(YASM_EXPR_ADD, yasm_expr_expr(*ep), - yasm_expr_expr(yasm_expr_copy(csymd->size)), - csymd->size->line); - *ep = yasm_expr_simplify(*ep, yasm_common_calc_bc_dist); + /* In standard COFF, COMMON symbols have their length added in */ + if (!win32) { + /*@dependent@*/ /*@null@*/ coff_symrec_data *csymd; + + csymd = yasm_symrec_get_of_data(sym); + assert(csymd != NULL); + *ep = yasm_expr_new(YASM_EXPR_ADD, yasm_expr_expr(*ep), + yasm_expr_expr(yasm_expr_copy(csymd->size)), + csymd->size->line); + *ep = yasm_expr_simplify(*ep, yasm_common_calc_bc_dist); + } } else if (!(vis & YASM_SYM_EXTERN)) { /* Local symbols need relocation to their section's start */ if (yasm_symrec_get_label(sym, &label_sect, &label_precbc)) { @@ -308,11 +339,22 @@ coff_objfmt_output_expr(yasm_expr **ep, unsigned char **bufp, if (rel) { reloc->type = COFF_RELOC_REL32; - /* Need to reference to start of section, so add $$ in. */ - *ep = yasm_expr_new(YASM_EXPR_ADD, yasm_expr_expr(*ep), - yasm_expr_sym(yasm_symrec_define_label("$$", info->sect, NULL, - 0, (*ep)->line)), - (*ep)->line); + /* For standard COFF, need to reference to start of section, so add + * $$ in. + * For Win32 COFF, need to reference to next bytecode, so add '$' + * (really $+$.len) in. + */ + if (win32) + *ep = yasm_expr_new(YASM_EXPR_ADD, yasm_expr_expr(*ep), + yasm_expr_sym(yasm_symrec_define_label("$", info->sect, bc, + 0, (*ep)->line)), + (*ep)->line); + else + *ep = yasm_expr_new(YASM_EXPR_ADD, yasm_expr_expr(*ep), + yasm_expr_sym(yasm_symrec_define_label("$$", info->sect, + NULL, 0, + (*ep)->line)), + (*ep)->line); *ep = yasm_expr_simplify(*ep, yasm_common_calc_bc_dist); } else reloc->type = COFF_RELOC_ADDR32; @@ -401,7 +443,7 @@ coff_objfmt_output_section(yasm_section *sect, /*@null@*/ void *d) csd->addr = info->addr; - if (csd->flags == COFF_STYP_BSS) { + if ((csd->flags & COFF_STYP_STD_MASK) == COFF_STYP_BSS) { /*@null@*/ yasm_bytecode *last = yasm_bcs_last(yasm_section_get_bytecodes(sect)); @@ -747,42 +789,170 @@ coff_objfmt_sections_switch(yasm_sectionhead *headp, yasm_valparam *vp = yasm_vps_first(valparams); yasm_section *retval; int isnew; - coff_section_data_flags flags; + unsigned long flags; int flags_override = 0; char *sectname; int resonly = 0; + static const struct { + const char *name; + unsigned long stdflags; /* if 0, win32 only qualifier */ + unsigned long win32flags; + /* Mode: 0 => clear specified bits + * 1 => set specified bits + * 2 => clear all bits, then set specified bits + */ + int mode; + } flagquals[] = { + { "code", COFF_STYP_TEXT, COFF_STYP_EXECUTE | COFF_STYP_READ, 2 }, + { "text", COFF_STYP_TEXT, COFF_STYP_EXECUTE | COFF_STYP_READ, 2 }, + { "data", COFF_STYP_DATA, COFF_STYP_READ | COFF_STYP_WRITE, 2 }, + { "bss", COFF_STYP_BSS, COFF_STYP_READ | COFF_STYP_WRITE, 2 }, + { "info", COFF_STYP_INFO, COFF_STYP_DISCARD | COFF_STYP_READ, 2 }, + { "discard", 0, COFF_STYP_DISCARD, 1 }, + { "nodiscard", 0, COFF_STYP_DISCARD, 0 }, + { "cache", 0, COFF_STYP_NOCACHE, 0 }, + { "nocache", 0, COFF_STYP_NOCACHE, 1 }, + { "page", 0, COFF_STYP_NOPAGE, 0 }, + { "nopage", 0, COFF_STYP_NOPAGE, 1 }, + { "share", 0, COFF_STYP_SHARED, 1 }, + { "noshare", 0, COFF_STYP_SHARED, 0 }, + { "execute", 0, COFF_STYP_EXECUTE, 1 }, + { "noexecute", 0, COFF_STYP_EXECUTE, 0 }, + { "read", 0, COFF_STYP_READ, 1 }, + { "noread", 0, COFF_STYP_READ, 0 }, + { "write", 0, COFF_STYP_WRITE, 1 }, + { "nowrite", 0, COFF_STYP_WRITE, 0 }, + }; if (!vp || vp->param || !vp->val) return NULL; sectname = vp->val; if (strlen(sectname) > 8) { + /* TODO: win32 format supports >8 character section names in object + * files via "/nnnn" (where nnnn is decimal offset into string table). + */ yasm__warning(YASM_WARN_GENERAL, lindex, N_("COFF section names limited to 8 characters: truncating")); sectname[8] = '\0'; } - if (strcmp(sectname, ".data") == 0) + if (strcmp(sectname, ".data") == 0) { flags = COFF_STYP_DATA; - else if (strcmp(sectname, ".bss") == 0) { + if (win32) + flags |= COFF_STYP_READ | COFF_STYP_WRITE | + (3<val, "code") == 0 || - yasm__strcasecmp(vp->val, "text") == 0) { - flags = COFF_STYP_TEXT; - flags_override = 1; - } else if (yasm__strcasecmp(vp->val, "data") == 0) { - flags = COFF_STYP_DATA; - flags_override = 1; - } else if (yasm__strcasecmp(vp->val, "bss") == 0) { - flags = COFF_STYP_BSS; - flags_override = 1; - resonly = 1; + size_t i; + int match, win32warn; + + win32warn = 0; + + match = 0; + for (i=0; ival, flagquals[i].name) == 0) { + if (!win32 && flagquals[i].stdflags == 0) + win32warn = 1; + else switch (flagquals[i].mode) { + case 0: + flags &= ~flagquals[i].stdflags; + if (win32) + flags &= ~flagquals[i].win32flags; + break; + case 1: + flags |= flagquals[i].stdflags; + if (win32) + flags |= flagquals[i].win32flags; + break; + case 2: + flags &= ~COFF_STYP_STD_MASK; + flags |= flagquals[i].stdflags; + if (win32) { + flags &= ~COFF_STYP_WIN32_MASK; + flags |= flagquals[i].win32flags; + } + break; + } + flags_override = 1; + match = 1; + } } + + if (match) + ; + else if (yasm__strcasecmp(vp->val, "align") == 0 && vp->param) { + if (win32) { + /*@dependent@*/ /*@null@*/ const yasm_intnum *align; + unsigned long bitcnt; + unsigned long addralign; + + align = yasm_expr_get_intnum(&vp->param, NULL); + if (!align) { + yasm__error(lindex, + N_("argument to `%s' is not a power of two"), + vp->val); + return NULL; + } + addralign = yasm_intnum_get_uint(align); + + /* Check to see if alignment is a power of two. + * This can be checked by seeing if only one bit is set. + */ + BitCount(bitcnt, addralign); + if (bitcnt > 1) { + yasm__error(lindex, + N_("argument to `%s' is not a power of two"), + vp->val); + return NULL; + } + + /* Check to see if alignment is supported size */ + if (addralign > 8192) { + yasm__error(lindex, + N_("Win32 does not support alignments > 8192")); + return NULL; + } + + /* Convert alignment into flags setting */ + flags &= ~COFF_STYP_ALIGN_MASK; + while (addralign != 0) { + flags += 1<>= 1; + } + } else + win32warn = 1; + } else + yasm__warning(YASM_WARN_GENERAL, lindex, + N_("Unrecognized qualifier `%s'"), vp->val); + + if (win32warn) + yasm__warning(YASM_WARN_GENERAL, lindex, + N_("Standard COFF does not support qualifier `%s'"), vp->val); } retval = yasm_sections_switch_general(headp, sectname, 0, resonly, &isnew, @@ -839,7 +1009,7 @@ coff_objfmt_section_data_print(FILE *f, int indent_level, void *data) yasm_symrec_print(f, indent_level+1, csd->sym); fprintf(f, "%*sscnum=%d\n", indent_level, "", csd->scnum); fprintf(f, "%*sflags=", indent_level, ""); - switch (csd->flags) { + switch (csd->flags & COFF_STYP_STD_MASK) { case COFF_STYP_TEXT: fprintf(f, "TEXT"); break; @@ -960,3 +1130,28 @@ yasm_objfmt yasm_coff_LTX_objfmt = { NULL /*coff_objfmt_bc_objfmt_data_delete*/, NULL /*coff_objfmt_bc_objfmt_data_print*/ }; + +/* Define objfmt structure -- see objfmt.h for details */ +yasm_objfmt yasm_win32_LTX_objfmt = { + "Win32", + "win32", + "obj", + ".text", + 32, + coff_objfmt_dbgfmt_keywords, + "null", + win32_objfmt_initialize, + coff_objfmt_output, + coff_objfmt_cleanup, + coff_objfmt_sections_switch, + coff_objfmt_section_data_delete, + coff_objfmt_section_data_print, + coff_objfmt_extglob_declare, + coff_objfmt_extglob_declare, + coff_objfmt_common_declare, + coff_objfmt_symrec_data_delete, + coff_objfmt_symrec_data_print, + coff_objfmt_directive, + NULL /*coff_objfmt_bc_objfmt_data_delete*/, + NULL /*coff_objfmt_bc_objfmt_data_print*/ +}; diff --git a/modules/objfmts/win32/Makefile.inc b/modules/objfmts/win32/Makefile.inc new file mode 100644 index 00000000..8cc8aadc --- /dev/null +++ b/modules/objfmts/win32/Makefile.inc @@ -0,0 +1,14 @@ +# $IdPath$ + +lib_LTLIBRARIES += yasm-win32.la + +yasm_win32_la_SOURCES = \ + modules/objfmts/coff/coff-objfmt.c +yasm_win32_la_LDFLAGS = -module -avoid-version -no-undefined +yasm_win32_la_LIBADD = libyasm.la +YASM_MODULES += -dlopen yasm-win32.la + +EXTRA_DIST += \ + modules/objfmts/win32/tests/Makefile.inc + +include modules/objfmts/win32/tests/Makefile.inc diff --git a/modules/objfmts/win32/tests/Makefile.inc b/modules/objfmts/win32/tests/Makefile.inc new file mode 100644 index 00000000..5e66fc71 --- /dev/null +++ b/modules/objfmts/win32/tests/Makefile.inc @@ -0,0 +1,11 @@ +# $IdPath$ + +TESTS += \ + modules/objfmts/win32/tests/win32_test.sh + +EXTRA_DIST += \ + modules/objfmts/win32/tests/win32_test.sh \ + modules/objfmts/win32/tests/win32test.c \ + modules/objfmts/win32/tests/win32test.asm \ + modules/objfmts/win32/tests/win32test.hex \ + modules/objfmts/win32/tests/win32test.errwarn diff --git a/modules/objfmts/win32/tests/win32test.asm b/modules/objfmts/win32/tests/win32test.asm new file mode 100644 index 00000000..17b93f9e --- /dev/null +++ b/modules/objfmts/win32/tests/win32test.asm @@ -0,0 +1,82 @@ +; test source file for assembling to COFF +; build with (under DJGPP, for example): +; yasm -f coff cofftest.asm +; gcc -o cofftest cofftest.c cofftest.o + +; This file should test the following: +; [1] Define and export a global text-section symbol +; [2] Define and export a global data-section symbol +; [3] Define and export a global BSS-section symbol +; [4] Define a non-global text-section symbol +; [5] Define a non-global data-section symbol +; [6] Define a non-global BSS-section symbol +; [7] Define a COMMON symbol +; [8] Define a NASM local label +; [9] Reference a NASM local label +; [10] Import an external symbol +; [11] Make a PC-relative call to an external symbol +; [12] Reference a text-section symbol in the text section +; [13] Reference a data-section symbol in the text section +; [14] Reference a BSS-section symbol in the text section +; [15] Reference a text-section symbol in the data section +; [16] Reference a data-section symbol in the data section +; [17] Reference a BSS-section symbol in the data section + +[BITS 32] +[GLOBAL _lrotate] ; [1] +[GLOBAL _greet] ; [1] +[GLOBAL _asmstr] ; [2] +[GLOBAL _textptr] ; [2] +[GLOBAL _selfptr] ; [2] +[GLOBAL _integer] ; [3] +[EXTERN _printf] ; [10] +[COMMON _commvar 4] ; [7] + +[SECTION .text] + +; prototype: long lrotate(long x, int num); +_lrotate: ; [1] + push ebp + mov ebp,esp + mov eax,[ebp+8] + mov ecx,[ebp+12] +.label rol eax,1 ; [4] [8] + loop .label ; [9] [12] + mov esp,ebp + pop ebp + ret + +; prototype: void greet(void); +_greet mov eax,[_integer] ; [14] + inc eax + mov [localint],eax ; [14] + push dword [_commvar] + mov eax,[localptr] ; [13] + push dword [eax] + push dword [_integer] ; [1] [14] + push dword _printfstr ; [13] + call _printf ; [11] + add esp,16 + ret + +[SECTION .data] + +; a string +_asmstr db 'hello, world', 0 ; [2] + +; a string for Printf +_printfstr db "integer==%d, localint==%d, commvar=%d" + db 10, 0 + +; some pointers +localptr dd localint ; [5] [17] +_textptr dd _greet ; [15] +_selfptr dd _selfptr ; [16] + +[SECTION .bss] + +; an integer +_integer resd 1 ; [3] + +; a local integer +localint resd 1 ; [6] diff --git a/modules/objfmts/win32/tests/win32test.c b/modules/objfmts/win32/tests/win32test.c new file mode 100644 index 00000000..f7446b8a --- /dev/null +++ b/modules/objfmts/win32/tests/win32test.c @@ -0,0 +1,34 @@ +/* + * test source file for assembling to COFF + * build with (under DJGPP, for example): + * yasm -f coff cofftest.asm + * gcc -o cofftest cofftest.c cofftest.o + */ + +#include + +extern int lrotate(long, int); +extern void greet(void); +extern char asmstr[]; +extern void *selfptr; +extern void *textptr; +extern int integer, commvar; + +int main(void) { + + printf("Testing lrotate: should get 0x00400000, 0x00000001\n"); + printf("lrotate(0x00040000, 4) = 0x%08lx\n", lrotate(0x40000,4)); + printf("lrotate(0x00040000, 14) = 0x%08lx\n", lrotate(0x40000,14)); + + printf("This string should read `hello, world': `%s'\n", asmstr); + + printf("The integers here should be 1234, 1235 and 4321:\n"); + integer = 1234; + commvar = 4321; + greet(); + + printf("These pointers should be equal: %p and %p\n", + &greet, textptr); + + printf("So should these: %p and %p\n", selfptr, &selfptr); +} diff --git a/modules/objfmts/win32/tests/win32test.errwarn b/modules/objfmts/win32/tests/win32test.errwarn new file mode 100644 index 00000000..e69de29b diff --git a/modules/objfmts/win32/tests/win32test.hex b/modules/objfmts/win32/tests/win32test.hex new file mode 100644 index 00000000..3697acb6 --- /dev/null +++ b/modules/objfmts/win32/tests/win32test.hex @@ -0,0 +1,660 @@ +4c +01 +03 +00 +00 +00 +00 +00 +70 +01 +00 +00 +10 +00 +00 +00 +00 +00 +0c +01 +2e +74 +65 +78 +74 +00 +00 +00 +00 +00 +00 +00 +00 +00 +00 +00 +40 +00 +00 +00 +8c +00 +00 +00 +cc +00 +00 +00 +00 +00 +00 +00 +07 +00 +00 +00 +20 +00 +50 +60 +2e +64 +61 +74 +61 +00 +00 +00 +40 +00 +00 +00 +00 +00 +00 +00 +40 +00 +00 +00 +12 +01 +00 +00 +52 +01 +00 +00 +00 +00 +00 +00 +03 +00 +00 +00 +40 +00 +30 +c0 +2e +62 +73 +73 +00 +00 +00 +00 +80 +00 +00 +00 +00 +00 +00 +00 +08 +00 +00 +00 +00 +00 +00 +00 +00 +00 +00 +00 +00 +00 +00 +00 +00 +00 +00 +00 +80 +00 +30 +c0 +55 +89 +e5 +8b +45 +08 +8b +4d +0c +d1 +c0 +e2 +fc +89 +ec +5d +c3 +a1 +00 +00 +00 +00 +40 +a3 +04 +00 +00 +00 +ff +35 +00 +00 +00 +00 +a1 +34 +00 +00 +00 +ff +30 +ff +35 +00 +00 +00 +00 +68 +0d +00 +00 +00 +e8 +00 +00 +00 +00 +81 +c4 +10 +00 +00 +00 +c3 +12 +00 +00 +00 +0e +00 +00 +00 +06 +00 +18 +00 +00 +00 +0e +00 +00 +00 +06 +00 +1e +00 +00 +00 +0b +00 +00 +00 +06 +00 +23 +00 +00 +00 +0c +00 +00 +00 +06 +00 +2b +00 +00 +00 +0e +00 +00 +00 +06 +00 +30 +00 +00 +00 +0c +00 +00 +00 +06 +00 +35 +00 +00 +00 +0a +00 +00 +00 +14 +00 +68 +65 +6c +6c +6f +2c +20 +77 +6f +72 +6c +64 +00 +69 +6e +74 +65 +67 +65 +72 +3d +3d +25 +64 +2c +20 +6c +6f +63 +61 +6c +69 +6e +74 +3d +3d +25 +64 +2c +20 +63 +6f +6d +6d +76 +61 +72 +3d +25 +64 +0a +00 +04 +00 +00 +00 +11 +00 +00 +00 +3c +00 +00 +00 +34 +00 +00 +00 +0e +00 +00 +00 +06 +00 +38 +00 +00 +00 +02 +00 +00 +00 +06 +00 +3c +00 +00 +00 +0c +00 +00 +00 +06 +00 +2e +66 +69 +6c +65 +00 +00 +00 +00 +00 +00 +00 +fe +ff +00 +00 +67 +01 +2d +00 +00 +00 +00 +00 +00 +00 +00 +00 +00 +00 +00 +00 +00 +00 +00 +00 +2e +74 +65 +78 +74 +00 +00 +00 +00 +00 +00 +00 +01 +00 +00 +00 +03 +01 +40 +00 +00 +00 +07 +00 +00 +00 +00 +00 +00 +00 +00 +00 +00 +00 +00 +00 +5f +6c +72 +6f +74 +61 +74 +65 +00 +00 +00 +00 +01 +00 +00 +00 +02 +00 +5f +67 +72 +65 +65 +74 +00 +00 +11 +00 +00 +00 +01 +00 +00 +00 +02 +00 +5f +61 +73 +6d +73 +74 +72 +00 +00 +00 +00 +00 +02 +00 +00 +00 +02 +00 +5f +74 +65 +78 +74 +70 +74 +72 +38 +00 +00 +00 +02 +00 +00 +00 +02 +00 +5f +73 +65 +6c +66 +70 +74 +72 +3c +00 +00 +00 +02 +00 +00 +00 +02 +00 +5f +69 +6e +74 +65 +67 +65 +72 +00 +00 +00 +00 +03 +00 +00 +00 +02 +00 +5f +70 +72 +69 +6e +74 +66 +00 +00 +00 +00 +00 +00 +00 +00 +00 +02 +00 +5f +63 +6f +6d +6d +76 +61 +72 +04 +00 +00 +00 +00 +00 +00 +00 +02 +00 +2e +64 +61 +74 +61 +00 +00 +00 +00 +00 +00 +00 +02 +00 +00 +00 +03 +01 +40 +00 +00 +00 +03 +00 +00 +00 +00 +00 +00 +00 +00 +00 +00 +00 +00 +00 +2e +62 +73 +73 +00 +00 +00 +00 +00 +00 +00 +00 +03 +00 +00 +00 +03 +01 +08 +00 +00 +00 +00 +00 +00 +00 +00 +00 +00 +00 +00 +00 +00 +00 +00 +00 +04 +00 +00 +00 -- 2.40.0