15 HelloWorld的字节码的编译执行的调试

编程入门 行业动态 更新时间:2024-10-25 22:24:30

15 HelloWorld的<a href=https://www.elefans.com/category/jswz/34/1769891.html style=字节码的编译执行的调试"/>

15 HelloWorld的字节码的编译执行的调试

前言

字节码里面隐藏了多少秘密, 呵呵 我们这里来以一个极简单的例子 来探索一下, 探索一下 基于解释执行的 相关细节 

lldb 汇编调试的部分需要感谢朋友 "新加坡买买提", 去年 12 月份的时候花了一下午的时间不佞帮助我, 呵呵 本文的例子也是那个时候 编写的以及调试的, 不过 当时是 clion 里面也能进行 lldb 的调试, 命令行中也可以, 现在 clion 里面的 lldb 不知道为啥不能调试了 ... 

 

 

测试用例

package com.hx.test02;/*** TemplateInterpreter** @author Jerry.X.He <970655147@qq>* @version 1.0* @date 2019-12-08 13:36*/
public class Test23TemplateInterpreter {public static void main(String[] args) {//    System.gc();int x = 1;}}

 

对应的字节码的相关信息如下, 一下可能会用于参照 

master:classes jerry$ javap -c com/hx/test02/Test23TemplateInterpreter.class 
Compiled from "Test23TemplateInterpreter.java"
public class com.hx.test02.Test23TemplateInterpreter {public com.hx.test02.Test23TemplateInterpreter();Code:0: aload_01: invokespecial #1                  // Method java/lang/Object."<init>":()V4: returnpublic static void main(java.lang.String[]);Code:0: iconst_11: istore_12: return
}

 

 

基于 lldb 的调试

(lldb) p _active_table._table[9][4]
(address) $1 = 0x0000000105830e1f "?\x01"
(lldb) p _active_table._table[9][60]
(address) $2 = 0x0000000105833aa0 "\x8b\x04$H\x83\U00000088A\x89F?A\x0f?]\x01I??I?p?0\x04\x01"
(lldb) b 0x0000000105830e1f
Breakpoint 3: address = 0x0000000105830e1f
(lldb) b 0x0000000105833aa0
Breakpoint 4: address = 0x0000000105833aa0
// iconst_1
(lldb) c
Process 3086 resuming
Process 3086 stopped
* thread #5, stop reason = breakpoint 3.1frame #0: 0x0000000105830e1f
->  0x105830e1f: movl   $0x1, %eax0x105830e24: movzbl 0x1(%r13), %ebx0x105830e29: incq   %r130x105830e2c: movabsq $0x104308a70, %r10        ; imm = 0x104308A70 
Target 0: (java) stopped.
(lldb) stepi
Process 3086 stopped
* thread #5, stop reason = instruction step intoframe #0: 0x0000000105830e24
->  0x105830e24: movzbl 0x1(%r13), %ebx0x105830e29: incq   %r130x105830e2c: movabsq $0x104308a70, %r10        ; imm = 0x104308A70 0x105830e36: jmpq   *(%r10,%rbx,8)
Target 0: (java) stopped.
(lldb) stepi
Process 3086 stopped
* thread #5, stop reason = instruction step intoframe #0: 0x0000000105830e29
->  0x105830e29: incq   %r130x105830e2c: movabsq $0x104308a70, %r10        ; imm = 0x104308A70 0x105830e36: jmpq   *(%r10,%rbx,8)0x105830e3a: nop    
Target 0: (java) stopped.
(lldb) stepi
Process 3086 stopped
* thread #5, stop reason = instruction step intoframe #0: 0x0000000105830e2c
->  0x105830e2c: movabsq $0x104308a70, %r10        ; imm = 0x104308A70 0x105830e36: jmpq   *(%r10,%rbx,8)0x105830e3a: nop    0x105830e3b: nop    
Target 0: (java) stopped.
(lldb) stepi
Process 3086 stopped
* thread #5, stop reason = instruction step intoframe #0: 0x0000000105830e36
->  0x105830e36: jmpq   *(%r10,%rbx,8)0x105830e3a: nop    0x105830e3b: nop    0x105830e3c: nop    
Target 0: (java) stopped.// istore_1
(lldb) c
Process 3086 resuming
Process 3086 stopped
* thread #5, stop reason = breakpoint 4.1frame #0: 0x0000000105833aa0
->  0x105833aa0: movl   (%rsp), %eax0x105833aa3: addq   $0x8, %rsp0x105833aa7: movl   %eax, -0x8(%r14)0x105833aab: movzbl 0x1(%r13), %ebx
Target 0: (java) stopped.
(lldb) re r
General Purpose Registers:rax = 0x0000000000000000rbx = 0x000000000000003crcx = 0x0000000000006a00rdx = 0x0000000000006a00rdi = 0x0000000105005000rsi = 0x0000000000000008rbp = 0x0000700009d05690rsp = 0x0000700009d05640r8 = 0x0000000000000000r9 = 0x0000000100611890r10 = 0x0000000104306270  libjvm.dylib`TemplateInterpreter::_normal_table + 18432r11 = 0x000000010061188cr12 = 0x0000000000000000r13 = 0x000000011c7ede61r14 = 0x0000700009d056a8r15 = 0x0000000105005000rip = 0x0000000105833aa0rflags = 0x0000000000000246cs = 0x000000000000002bfs = 0x0000000000000000gs = 0x0000000000000000(lldb) stepi
Process 3086 stopped
* thread #5, stop reason = instruction step intoframe #0: 0x0000000105833aa3
->  0x105833aa3: addq   $0x8, %rsp0x105833aa7: movl   %eax, -0x8(%r14)0x105833aab: movzbl 0x1(%r13), %ebx0x105833ab0: incq   %r13
Target 0: (java) stopped.
(lldb) re r
General Purpose Registers:rax = 0x0000000000000001rbx = 0x000000000000003crcx = 0x0000000000006a00rdx = 0x0000000000006a00rdi = 0x0000000105005000rsi = 0x0000000000000008rbp = 0x0000700009d05690rsp = 0x0000700009d05640r8 = 0x0000000000000000r9 = 0x0000000100611890r10 = 0x0000000104306270  libjvm.dylib`TemplateInterpreter::_normal_table + 18432r11 = 0x000000010061188cr12 = 0x0000000000000000r13 = 0x000000011c7ede61r14 = 0x0000700009d056a8r15 = 0x0000000105005000rip = 0x0000000105833aa3rflags = 0x0000000000000246cs = 0x000000000000002bfs = 0x0000000000000000gs = 0x0000000000000000(lldb) stepi
Process 3086 stopped
* thread #5, stop reason = instruction step intoframe #0: 0x0000000105833aa7
->  0x105833aa7: movl   %eax, -0x8(%r14)0x105833aab: movzbl 0x1(%r13), %ebx0x105833ab0: incq   %r130x105833ab3: movabsq $0x10430b270, %r10        ; imm = 0x10430B270 
Target 0: (java) stopped.
(lldb) x 0x0000700009d05640 -c 0x100
0x700009d05640: 01 00 00 00 00 00 00 00 48 56 d0 09 00 70 00 00  ........HV?..p..
0x700009d05650: 61 de 7e 1c 01 00 00 00 a8 56 d0 09 00 70 00 00  a?~.....?V?..p..
0x700009d05660: e0 de 7e 1c 01 00 00 00 00 00 00 00 00 00 00 00  ??~.............
0x700009d05670: d0 7f bb 47 07 00 00 00 88 de 7e 1c 01 00 00 00  ?.?G.....?~.....
0x700009d05680: 00 00 00 00 00 00 00 00 a8 56 d0 09 00 70 00 00  ........?V?..p..
0x700009d05690: 10 57 d0 09 00 70 00 00 f1 09 80 05 01 00 00 00  .W?..p..?.......
0x700009d056a0: 00 00 00 00 00 00 00 00 88 83 bb 47 07 00 00 00  ..........?G....
0x700009d056b0: a0 1f 00 00 03 00 00 00 00 00 00 00 00 00 00 00  ?...............
0x700009d056c0: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00  ................
0x700009d056d0: 00 00 00 00 00 00 00 00 00 60 d0 09 00 70 00 00  .........`?..p..
0x700009d056e0: 20 58 d0 09 00 70 00 00 50 5d d0 09 00 70 00 00   X?..p..P]?..p..
0x700009d056f0: 0a 00 00 00 00 70 00 00 88 de 7e 1c 01 00 00 00  .....p...?~.....
0x700009d05700: 00 a7 82 05 01 00 00 00 a0 5a d0 09 00 70 00 00  .?......?Z?..p..
0x700009d05710: e0 58 d0 09 00 70 00 00 1d bb 8e 03 01 00 00 00  ?X?..p...?......
0x700009d05720: 01 00 00 00 00 70 00 00 00 50 00 05 01 00 00 00  .....p...P......
0x700009d05730: 50 57 d0 09 00 70 00 00 15 95 28 03 01 00 00 00  PW?..p....(.....
(lldb) stepi
Process 3086 stopped
* thread #5, stop reason = instruction step intoframe #0: 0x0000000105833aab
->  0x105833aab: movzbl 0x1(%r13), %ebx0x105833ab0: incq   %r130x105833ab3: movabsq $0x10430b270, %r10        ; imm = 0x10430B270 0x105833abd: jmpq   *(%r10,%rbx,8)
Target 0: (java) stopped.
(lldb) x 0x0000700009d05640 -c 0x100
0x700009d05640: 01 00 00 00 00 00 00 00 48 56 d0 09 00 70 00 00  ........HV?..p..
0x700009d05650: 61 de 7e 1c 01 00 00 00 a8 56 d0 09 00 70 00 00  a?~.....?V?..p..
0x700009d05660: e0 de 7e 1c 01 00 00 00 00 00 00 00 00 00 00 00  ??~.............
0x700009d05670: d0 7f bb 47 07 00 00 00 88 de 7e 1c 01 00 00 00  ?.?G.....?~.....
0x700009d05680: 00 00 00 00 00 00 00 00 a8 56 d0 09 00 70 00 00  ........?V?..p..
0x700009d05690: 10 57 d0 09 00 70 00 00 f1 09 80 05 01 00 00 00  .W?..p..?.......
0x700009d056a0: 01 00 00 00 00 00 00 00 88 83 bb 47 07 00 00 00  ..........?G....
0x700009d056b0: a0 1f 00 00 03 00 00 00 00 00 00 00 00 00 00 00  ?...............
0x700009d056c0: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00  ................
0x700009d056d0: 00 00 00 00 00 00 00 00 00 60 d0 09 00 70 00 00  .........`?..p..
0x700009d056e0: 20 58 d0 09 00 70 00 00 50 5d d0 09 00 70 00 00   X?..p..P]?..p..
0x700009d056f0: 0a 00 00 00 00 70 00 00 88 de 7e 1c 01 00 00 00  .....p...?~.....
0x700009d05700: 00 a7 82 05 01 00 00 00 a0 5a d0 09 00 70 00 00  .?......?Z?..p..
0x700009d05710: e0 58 d0 09 00 70 00 00 1d bb 8e 03 01 00 00 00  ?X?..p...?......
0x700009d05720: 01 00 00 00 00 70 00 00 00 50 00 05 01 00 00 00  .....p...P......
0x700009d05730: 50 57 d0 09 00 70 00 00 15 95 28 03 01 00 00 00  PW?..p....(.....
(lldb) stepi
Process 3086 stopped
* thread #5, stop reason = instruction step intoframe #0: 0x0000000105833ab0
->  0x105833ab0: incq   %r130x105833ab3: movabsq $0x10430b270, %r10        ; imm = 0x10430B270 0x105833abd: jmpq   *(%r10,%rbx,8)0x105833ac1: nop    
Target 0: (java) stopped.
(lldb) stepi
Process 3086 stopped
* thread #5, stop reason = instruction step intoframe #0: 0x0000000105833ab3
->  0x105833ab3: movabsq $0x10430b270, %r10        ; imm = 0x10430B270 0x105833abd: jmpq   *(%r10,%rbx,8)0x105833ac1: nop    0x105833ac2: nop    
Target 0: (java) stopped.
(lldb) stepi
Process 3086 stopped
* thread #5, stop reason = instruction step intoframe #0: 0x0000000105833abd
->  0x105833abd: jmpq   *(%r10,%rbx,8)0x105833ac1: nop    0x105833ac2: nop    0x105833ac3: nop    
Target 0: (java) stopped.
(lldb)  

其中 0x700009d056a0 对应的数据对应的是 slot1[变量x]

可以看到这里的 iconst_1, istore_1 的大致的流程, 然后 如何存放到 slot1 里面的 

这里有一个问题就是 0x105833aa0 的地方直接使用了 栈顶的数据 放到 rax 然后进行之后的业务操作 

但是 在 iconst_1 的相关代码里面么有看到 将 rax 存入 stack 的过程(这个 push rax 在后面) 

 

 

字节码执行之间中插的代码?

在 iconst_1 和 istore_1 之间, 还执行了如下一段代码, 呵呵 有些地方看的明白, 大部分地方看不明白, 先放在这里吧, 后面 有一定的了解之后再来解惑 

(lldb) dis -s 0x105825f24 -c 200// push rax, 将1入表达式栈(这里的场景)0x105825f24: pushq  %rax// MacroAssembler::call_VM_helper0x105825f25: callq  0x105825f2f0x105825f2a: jmp    0x1058261850x105825f2f: leaq   0x8(%rsp), %rax// save_bcp0x105825f34: movq   %r13, -0x40(%rbp)// cmpptr(Address(rbp, frame::interpreter_frame_last_sp_offset * wordSize), (int32_t)NULL_WORD)0x105825f38: cmpq   $0x0, -0x10(%rbp)0x105825f40: je     0x105825fbd// ignore MacroAssembler::debug64// 擦 这里对应的是哪里 0x105825fbd: pushq  %r100x105825fbf: cmpq   -0x150f9d6(%rip), %r12    ; Universe::_narrow_ptrs_base0x105825fc6: je     0x105826043// ignore MacroAssembler::debug640x105826043: popq   %r10// LP64_ONLY(mov(c_rarg0, r15_thread))0x105826045: movq   %r15, %rdi// set_last_Java_frame(java_thread, last_java_sp, rbp, NULL);0x105826048: movq   %rbp, 0x218(%r15)0x10582604f: movq   %rax, 0x208(%r15)// MacroAssembler::call_VM_leaf_base(entry_point, number_of_arguments); 0x105826056: testl  $0xf, %esp0x10582605c: je     0x1058260740x105826062: subq   $0x8, %rsp0x105826066: callq  0x1038d5ac0               ; InterpreterRuntime::at_safepoint at interpreterRuntime.cpp:10500x10582606b: addq   $0x8, %rsp0x10582606f: jmp    0x1058260790x105826074: callq  0x1038d5ac0               ; InterpreterRuntime::at_safepoint at interpreterRuntime.cpp:1050// get_thread(java_thread);0x105826079: pushq  %rax0x10582607a: pushq  %rdi0x10582607b: pushq  %rsi0x10582607c: pushq  %rdx0x10582607d: pushq  %rcx0x10582607e: pushq  %r80x105826080: pushq  %r90x105826082: pushq  %r100x105826084: pushq  %r110x105826086: testl  $0xf, %esp0x10582608c: je     0x1058260a40x105826092: subq   $0x8, %rsp0x105826096: callq  0x103003ae0               ; Thread::current at thread.hpp:6600x10582609b: addq   $0x8, %rsp0x10582609f: jmp    0x1058260a90x1058260a4: callq  0x103003ae0               ; Thread::current at thread.hpp:6600x1058260a9: popq   %r110x1058260ab: popq   %r100x1058260ad: popq   %r90x1058260af: popq   %r80x1058260b1: popq   %rcx0x1058260b2: popq   %rdx0x1058260b3: popq   %rsi0x1058260b4: popq   %rdi0x1058260b5: cmpq   %rax, %r150x1058260b8: je     0x105826135// ignore MacroAssembler::debug640x105826135: popq   %rax// reset_last_Java_frame(java_thread, true);0x105826136: movabsq $0x0, %r100x105826140: movq   %r10, 0x208(%r15)0x105826147: movabsq $0x0, %r100x105826151: movq   %r10, 0x218(%r15)0x105826158: movabsq $0x0, %r100x105826162: movq   %r10, 0x210(%r15)// check_exceptions0x105826169: cmpq   $0x0, 0x8(%r15)0x105826171: je     0x10582617c0x105826177: jmp    0x1058007a0// restore_bcp();0x10582617c: movq   -0x40(%rbp), %r13// restore_locals();0x105826180: movq   -0x38(%rbp), %r140x105826184: retq// dispatch 下一条指令 0x105826185: movzbl (%r13), %ebx0x10582618a: movabsq $0x104306270, %r10        ; imm = 0x1043062700x105826194: jmpq   *(%r10,%rbx,8)

这块代码 主要的目的是调用 InterpreterRuntime::at_safepoint 

 

生成上面这段汇编的核心代码 似乎是来自于这里, 传入的 entry_point 是 InterpreterRuntime::at_safepoint 的 entry_point 

 

呵呵 先留在这里不求甚解吧 

 

另外还有一个现象是, 这断代码 核心调用的是 InterpreterRuntime::at_safepoint 在 lldb 命令行里面调试的时候, 你会清楚的看到 会执行这段代码, 但是 在 clion 里面调试的时候 打上一个断点, 却不会执行, 这个是和 什么时候调试 有一定的关系么 ?

 

 

这部分中插代码再记录 add at 2020.06.06

======================= add at 2020.06.06 =======================

 

今天又重新调试了一下 这个例子, 呵呵 发现了一点 之前调试记录的不同的东西 

呵呵, 有些时候 没有去 调用 InterpreterRuntime::at_safepoint 

直接按照 字节码模板 的调度过程去进行执行了, 直接以 ax 作为媒介来传递了数据 

(lldb)  p _active_table._table[9][4]
(address) $1 = 0x0000000105830e1f "?\x01"
(lldb) b 0x0000000105830e1f
Breakpoint 3: address = 0x0000000105830e1f// iconst_1
(lldb) c
Process 3326 resuming
Process 3326 stopped
* thread #5, stop reason = breakpoint 3.1frame #0: 0x0000000105830e1f
->  0x105830e1f: movl   $0x1, %eax0x105830e24: movzbl 0x1(%r13), %ebx0x105830e29: incq   %r130x105830e2c: movabsq $0x103b08a70, %r10        ; imm = 0x103B08A70
Target 0: (java) stopped.
(lldb) stepi
Process 3326 stopped
* thread #5, stop reason = instruction step intoframe #0: 0x0000000105830e24
->  0x105830e24: movzbl 0x1(%r13), %ebx0x105830e29: incq   %r130x105830e2c: movabsq $0x103b08a70, %r10        ; imm = 0x103B08A700x105830e36: jmpq   *(%r10,%rbx,8)
Target 0: (java) stopped.
(lldb) stepi
Process 3326 stopped
* thread #5, stop reason = instruction step intoframe #0: 0x0000000105830e29
->  0x105830e29: incq   %r130x105830e2c: movabsq $0x103b08a70, %r10        ; imm = 0x103B08A700x105830e36: jmpq   *(%r10,%rbx,8)0x105830e3a: nop
Target 0: (java) stopped.
(lldb) stepi
Process 3326 stopped
* thread #5, stop reason = instruction step intoframe #0: 0x0000000105830e2c
->  0x105830e2c: movabsq $0x103b08a70, %r10        ; imm = 0x103B08A700x105830e36: jmpq   *(%r10,%rbx,8)0x105830e3a: nop0x105830e3b: nop
Target 0: (java) stopped.
(lldb) stepi
Process 3326 stopped
* thread #5, stop reason = instruction step intoframe #0: 0x0000000105830e36
->  0x105830e36: jmpq   *(%r10,%rbx,8)0x105830e3a: nop0x105830e3b: nop0x105830e3c: nop
Target 0: (java) stopped.// istore_1
(lldb) stepi
Process 3326 stopped
* thread #5, stop reason = instruction step intoframe #0: 0x0000000105833aa7
->  0x105833aa7: movl   %eax, -0x8(%r14)0x105833aab: movzbl 0x1(%r13), %ebx0x105833ab0: incq   %r130x105833ab3: movabsq $0x103b0b270, %r10        ; imm = 0x103B0B270
Target 0: (java) stopped.
(lldb) stepi
Process 3326 stopped
* thread #5, stop reason = instruction step intoframe #0: 0x0000000105833aab
->  0x105833aab: movzbl 0x1(%r13), %ebx0x105833ab0: incq   %r130x105833ab3: movabsq $0x103b0b270, %r10        ; imm = 0x103B0B2700x105833abd: jmpq   *(%r10,%rbx,8)
Target 0: (java) stopped.
(lldb) stepi
Process 3326 stopped
* thread #5, stop reason = instruction step intoframe #0: 0x0000000105833ab0
->  0x105833ab0: incq   %r130x105833ab3: movabsq $0x103b0b270, %r10        ; imm = 0x103B0B2700x105833abd: jmpq   *(%r10,%rbx,8)0x105833ac1: nop
Target 0: (java) stopped.
(lldb) stepi
Process 3326 stopped
* thread #5, stop reason = instruction step intoframe #0: 0x0000000105833ab3
->  0x105833ab3: movabsq $0x103b0b270, %r10        ; imm = 0x103B0B2700x105833abd: jmpq   *(%r10,%rbx,8)0x105833ac1: nop0x105833ac2: nop
Target 0: (java) stopped.
(lldb) stepi
Process 3326 stopped
* thread #5, stop reason = instruction step intoframe #0: 0x0000000105833abd
->  0x105833abd: jmpq   *(%r10,%rbx,8)0x105833ac1: nop0x105833ac2: nop0x105833ac3: nop
Target 0: (java) stopped.

 

 

呵呵 上面的 字节码执行之间中插的代码 来自于 

 

以上两种情况对应于 active_table 为 normal_table 或者 切换为 safept_table 的情况, 呵呵 但是什么情况下切换, 目前我还不明白 

active_table 为 normal_table 的场景 

(lldb) p _active_table._table[9][194]
(address) $0 = 0x000000010604f980 "XH;"
(lldb) p _active_table._table[0][0]
(address) $1 = 0x0000000106030b9e "PA\x0f\xb6]\x01I??I\xbap\xb2\xb0\x03\x01"
(lldb) p _normal_table._table[0][0]
(address) $2 = 0x0000000106030b9e "PA\x0f\xb6]\x01I??I\xbap\xb2\xb0\x03\x01"
(lldb) p _safept_table._table[0][0]
(address) $3 = 0x00000001060252e0 "P?
(lldb) p _active_table._table[9][4]
(address) $4 = 0x0000000106030e1f "\xb8\x01"
(lldb) b 0x0000000106030e1f
Breakpoint 3: address = 0x0000000106030e1f
(lldb) c
Process 3783 resuming
Process 3783 stopped
* thread #5, stop reason = breakpoint 3.1frame #0: 0x0000000106030e1f
->  0x106030e1f: movl   $0x1, %eax0x106030e24: movzbl 0x1(%r13), %ebx0x106030e29: incq   %r130x106030e2c: movabsq $0x103b08a70, %r10        ; imm = 0x103B08A70
Target 0: (java) stopped.
(lldb) p _active_table._table[0][0]
(address) $5 = 0x0000000106030b9e "PA\x0f?]\x01I??I?p??\x03\x01"

active_table 为 safept_table 的场景 

(lldb) p _active_table._table[9][194]
(address) $0 = 0x000000010584f980 "XH;"
(lldb) p _active_table._table[0][0]
(address) $1 = 0x0000000105830b9e "PA\x0f\xb6]\x01I??I\xbap\xb20\x04\x01"
(lldb) p _normal_table._table[0][0]
(address) $2 = 0x0000000105830b9e "PA\x0f\xb6]\x01I??I\xbap\xb20\x04\x01"
(lldb) p _safept_table._table[0][0]
(address) $3 = 0x00000001058252e0 "P?
(lldb)  p _active_table._table[9][4]
(address) $4 = 0x0000000105830e1f "?\x01"
(lldb) b 0x0000000105830e1f
Breakpoint 3: address = 0x0000000105830e1f
(lldb) c
Process 3646 resuming
Process 3646 stopped
* thread #5, stop reason = breakpoint 3.1frame #0: 0x0000000105830e1f
->  0x105830e1f: movl   $0x1, %eax0x105830e24: movzbl 0x1(%r13), %ebx0x105830e29: incq   %r130x105830e2c: movabsq $0x104308a70, %r10        ; imm = 0x104308A70 
Target 0: (java) stopped.
(lldb) p _active_table._table[0][0]
(address) $5 = 0x00000001058252e0 "P?

 

 

 

 

 

完 

 

 

更多推荐

15 HelloWorld的字节码的编译执行的调试

本文发布于:2024-02-12 08:22:49,感谢您对本站的认可!
本文链接:https://www.elefans.com/category/jswz/34/1686944.html
版权声明:本站内容均来自互联网,仅供演示用,请勿用于商业和其他非法用途。如果侵犯了您的权益请与我们联系,我们将在24小时内删除。
本文标签:字节   HelloWorld

发布评论

评论列表 (有 0 条评论)
草根站长

>www.elefans.com

编程频道|电子爱好者 - 技术资讯及电子产品介绍!