第9章基于Linux操作系统的ARM编程.doc

上传人:h**** 文档编号:130605 上传时间:2018-07-09 格式:DOC 页数:47 大小:522KB
下载 相关 举报
第9章基于Linux操作系统的ARM编程.doc_第1页
第1页 / 共47页
第9章基于Linux操作系统的ARM编程.doc_第2页
第2页 / 共47页
第9章基于Linux操作系统的ARM编程.doc_第3页
第3页 / 共47页
第9章基于Linux操作系统的ARM编程.doc_第4页
第4页 / 共47页
第9章基于Linux操作系统的ARM编程.doc_第5页
第5页 / 共47页
点击查看更多>>
资源描述

1、基于 ARM9 和 Linux 嵌入式系统设计 283 第 9 章 基于 ARM9 和 Linux 嵌入式系统设计 本章将学习如何进行嵌入式 Linux 系统的开发。读完本章,读者将了解以下内容: 嵌入式 Linux 的开发环境。 Linux 开发工具 GNU gcc 的使用。 GNU make 命令和 makefile 文件。 GDB 调试器。 嵌入式 Linux 下 C 语言编程。 嵌入式 Linux 引导程序。 嵌入式 Linux 下程序调试应用举例。 9.1 嵌入式 Linux的开发环境 嵌入式系统是以应用为中心,以计算机技术为基础、软硬件均可裁剪、适应应用系统对功能、 可靠性、成本、

2、体积、功耗严格要求的专用计算机系统。其发展已有二十多年的历史,国际上也出现了一些著名的嵌入式操作系统,如 VxWorks, Palm OS, Windows CE 等,但这些操作系统均属于商品化产品,价格昂贵且由于源代码不公开导致了诸如对设备的支持,应用软件的移植等一系列的问题。而 Linux 作为一种优秀的免费操作系统,近几年在嵌入式领域异军突起,成为了最有潜力的嵌入式操作系统。 9.1.1 嵌入式 Linux开发环境建立 进行项目开发前,首先要做的是搭建一套基于 Linux 操作系统的应用开发环境,一般由目 标板和宿主机所构成。目标板用于运行操作系统和系统应用软件,目标板所用到的操作系统的

3、内核编译、应用程序的开发和调试规则需要通过宿主机来完成。开发环境对硬件没有特殊的要求,但是为了双方之间建立连接关系,关键的接口(包括串口、以太网口和 USB 口等)是必不可少的。 嵌入式 Linux 开发环境有几个方案: ( 1)在 WINDOWS 下安装 Linux虚拟机后,目前大多情况下使用 VWare软件; ( 2)直接安装 Linux 操作系统。 若使用纯 LINUX 操作系统开发环境。多数使用的开发环境为 RedHat 9, RedHat 9 支持中文,并且包含了绝大部分的开发工具,不用担心装了 Linux 就不能使用 WinDows 的问题。一般的情况都是用户已经有了 WINDOW

4、S 操作系统,再安装 Linux, Linux 会自动安装一个叫作 GRUB 的启动引导软件,可以选择引导多个操作系统。可现在的微型计算机的 CPU 速度快,内存容量大,因此,相当多的 ARM 嵌入式系统的开发人员使用在WINDOWS 下安装 Linux 虚拟机,这样,开发人员就可在 WINDOWS 和 Linux 两种操作系统下任意切换使用。给开发人员带来许多方便。 284 基于 ARM9 和 Linux 嵌入式系 统设计 9.1.2 嵌入式 Linux开 发的一般过程 嵌入式 Linux 融合了嵌入式和 Linux 的特点,其开发与一般的应用程序开发相比有着自己的特点,下面简要的介绍一下嵌

5、入式 Linux 开发的一般过程。 了解硬件是首要的一步,这是嵌入式开发的特点决定的。了解硬件指的是了解整个硬件,判断硬件对于当前的应用来说是否合适。嵌入式系统中需要使用到 CPU 和各种外围设备,由此需要收集相关硬件的资料,包括 CPU,芯片手册和各种外围设备的手册以及相关的各种电路图等,并对整体系统有较深入的了解。 了解硬件后,下一步就该准备需要使用的 Linux 工具以及其他工具,这些工具 包括针对所用 CPU 的编译器 /汇编器 /连接器、相应的库工具、目标文件分析 /管理工具、符号查看器等。由于 Linux 的开放性,针对不同目标平台的 Linux 工具都可在网上免费得到,这些工具的

6、绝大部分都由 GNU 提供。所需要的其他工具还包括硬件厂商提供给公司的工具,如编程器、下载工具和查错器等。所有这些工具对以后的开发、调试等都可说是必不可少的。 做好以上的准备工作后,就要进入实质性的工作阶段了。首先需要安排内存地址,如SDRAM 的内存地址, Flash 的内存地址等,这需要与实际应用和硬件状况相结合来考虑,要根据硬件的限 制以及实际应用的需要对内存地址进行合理的安排,同时要注意内存地址应具有一定的伸缩性,以便于将来需要改动时所做的变动达到最小。一般来说,嵌入式 Linux 的内存地址安排体现在连接脚本当中。 接着就该进入编写启动代码和机器相关代码阶段了。各种不同目标系统,甚至

7、相同目标系统的启动代码和机器相关代码也是不相同的。启动代码一般需要完成硬件初始化、装载内核、安装根文件系统以及开始内核执行的工作,不同目标平台的启动代码一般可通过参考 Linux 下已有的启动代码和相关 CPU 的手册进行编写。 启动代码和机器相关代码编程完成,并可 以启动系统后,下一步就可以开始驱动程序的编写了。嵌入式 Linux 系统驱动程序开发与普通 Linux 开发并没有太大的区别,都需要对相关的硬件作出了解,同时需要遵循 Linux 编写驱动程序的一些规则,编写完一个驱动程序后,一般还要写一个相应的测试程序以便随时进行测试。 Linux 下各种不同类型的设备都有相当多的驱动程序源码可

8、以参考,因此实际编写时更多的时间是花在对特定硬件特性的熟悉上。 除了以上提到的这些步骤外,进行实际开发时,很多时候还要进行库(这里所提到的库均指 C 库)、 GUI 和系统程序的移植。这是因为嵌入式 Linux 中所用的库一般不能直接使用标准库,而需要进行精简,虽然已有精简的 C 库,如 uClibc 等可供使用,但还是需要经常对其进行修改。嵌入式 Linux 常用的 GUI 有 Microwindows、 MiniGUI、QT/Embedded、 TinyX 等,各自均有其使用的场合,所针对的目标平台和应用层次也不一样,必须根据实际需要进行选择。系统程序如 mount、 ls 等有些是应用时

9、所必需的,有些则是进行调试时所需要的,初始时则需要一些通用的系统程序。 基于 ARM9 和 Linux 嵌入式系统设计 285 9.2 Linux 开发工具的使用 9.2.1 Linux开发工具 GNU gcc的使用 在 Linux 平台下 , GNU gcc 编译器,即可以编译 Linux 操作系统下运行的 应用程序 ,又可以 编译 Linux 内核本身,甚至可以交叉编译运行于其他 CPU 上的程序。下面介绍 编译程序 GCC 在编译应用程序的过程的具体用法 、 GCC 的常用选项、模式和警告选项。 1. GCC 简介 通常所说的 GCC 是 GNU Compiler Collection

10、的简称,除了编译程序之外,它还含其他相关工具,所以它能把易于人类使用的高级语言编写的源代码构建成计算机能够直接执行的二进制代码。 GCC 是 Linux 平台下最常用的编译程序,是 Linux 平台编译器的事实标准。同时,在 Linux 平台下的嵌入式开发领域, GCC 也是用得最普遍的一种编译器。GCC 之所以被广泛采用,是因为它能支持各种不同的目标体系结构。例如,它既支持基于宿主的开发(简单讲就是要为某平台编译程序,就在该平台上编译),也支持交叉编译(即在 A 平台上编译的程序是供平台 B 使用的)。目前, GCC 支持的体系结构有 40余种,常见的有 x86 系列、 Arm、 Power

11、PC 等。同时, GCC 还能运行在不同的操作系统上,如 Linux、 Solaris、 Windows 等。除了上面讲的之外, GCC 除了支持 C 语言外,还支持多种其他语言,例如 C+、 Ada、 Java、 Objective-C、 Fortram、 Pascal 等 。 2. GCC 常用模式及选项 gcc 最基本的用法是: gcc options file. 其中 option 是以 “-”开始的各种选项, file 是相关的文件名。在使用 gcc 的时,必须给出必要的选项和文件名。 gcc 的整个编译过程分别是:预处理、编译,汇编和链接。 表 9.1 gcc 编译器中常用选项 常

12、用选项 说 明 -o 表示要求编译器生成指定文件名的可执行文件 -c 表示只要求编译器 进行编译生成 .o 的目标文件,而不要进行链接 -g 要求编译器在编译的时候提供以后对程序进行调试的信息 -E 表示编译器对源文件只进行预处理就停止,而不做编译、汇编和链接 -S 表示编译器只进行编译,而不做汇编和链接 -O 表示编译器优化生成可执行文件 -Wall 生成所有的警告信息 例如, $ gcc -o hello hello.c , gcc 编译器就会生成一个 hello 的可执行文件。在 hello.c的当前目录下执行 ./hello。 286 基于 ARM9 和 Linux 嵌入式系 统设计

13、gcc 编译器生成的目标文件默认格式为 elf( executive linked file)格式,这是 Linux 系统所采用的可执行链接文件的通用文件格式。 elf 格式由若干个段( section)组成,如果没有特别指明,由标准 c 源代码生成的目标文件中包含以下段: .text(正文段)包含程序的指令代码, .data(数据段)包含固定的数据,如常量,字符串等, .bss(未初始化数据段)包含未初始化的变量和数组等。 GCC 常用两种模式:编译模式和编译连接模式。下面以一些命令来说明各种模式的使用方法。为简单起见,假设全部的源代码都在一个文件 test.c 中。 $ gcc -o te

14、st 此命令是把源文件 test.c 直接编译成可执行程序 test。 $ gcc -c test.c 此命令是把源文件 test.c 编译成不可执行目标文件 test.o。默认情况下,生成的目标文件名为 test.o,但也可以为输出文件指定名称,如下所示: $ gcc -c test.c o mytest.o 此命令是把源文件 test.c 编译成不可执行目标文件 test.o。 下面的命令将同时编译 3 个源文件,即 first.c、 second.c 和 third.c,然后将它们连接成一个可执行程序 test。命令如下: $ gcc -o test first.c second.c t

15、hird.c 3其他常用选项的使用 许多情况下,头文件和源文件会单独存放在不同的目录中。例如,假设存放源文件的子目录名为 ./src,而包含文件则放在层次的其他目录下,如 ./inc。当在 ./src 目录下进行编译工作时,如何告诉 GCC 到哪里找头文件呢?方法如下所示: $ gcc test.c I./inc -o test 上面的命令告诉 GCC 包含文件存放在 ./inc 目录下,在当前目录的上一级。如果在编译时需要的包含文件 存放在多个目录下,可以使用多个 -I 来指定各个目录。如: $ gcc test.c I./inc I././inc2 -o test 这里指出了另一个包含子目

16、录 inc2,较之前目录它还要在再上两级才能找到。另外,还可以在编译命令行中定义符号常量。为此,可以简单的在命令行中使用 -D 选项即可,如下例所示: $ gcc D TEST_CONFIGURATION test.c -o test 上面的命令与在源文件中加入下列命令是等效的: #define TEST_CONFIGURATION 基于 ARM9 和 Linux 嵌入式系统设计 287 4. 警告功 能 当 GCC 在编译过程中检查出错误时,它就会中止编译;但检测到警告时却能继续编译生成可执行程序,因为警告只是针对程序结构的诊断信息,它不能说明程序一定有错误,而是存在风险,或者可能存在错误。

17、虽然 GCC 提供了非常丰富的警告,但前提是已经启用了它们,否则它不会报告这些检测到的警告。 在众多的警告选项之中,最常用的就是 -Wall 选项。该选项能发现程序中一系列的常见错误警告,该选项用法举例如下: $ gcc -Wall test.c -o test 该选项相当于同时使用了下列所有的选项: unused-function:遇到仅声明过但尚未定义的静态函数时发出警告。 unused-label:遇到声明过但不使用的标号的警告。 unused-parameter:从未用过的函数参数的警告。 unused-variable:在本地声明但从未用过的变量的警告。 unused-value:仅

18、计算但从未用过的值的警告。 format:检查对 printf 和 scanf 等函数的调用,确认各参数类型和格式串中的一致。 implicit-int:警告没有规定类型的声明。 implicit-function-: 在函数在未经声明就使用时给予警告。 char-subscripts:警告把 char 类型作为数组下标。 missing-braces:聚合初始化两边缺少大括号。 Parentheses:在某些情况下如果忽略了括号,编译器就发出警告。 return-type:如果函数定义了返回类型,而默认类型是 int 型,编译器就发出警告。同时警告那些不带返回值的 return 语句,如果他

19、们所属的函数并非 void 类型。 sequence-point:出现可疑的代码元素时,发出报警。 Switch:如果某条 switch 语句的参数属于枚举类型,但是没有对应的 case 语句使用枚举元素,编译器就发出警告(在 switch 语句中使用 default 分支能够防止这个警告)。超出枚举范围的 case 语句同样会导致这个警告。 strict-aliasing:对变量别名进行最严格的检查。 unknown-pragmas:使用了不允许的 #pragma。 Uninitialized:在初始化之前就使用自动变量。 需要注意的是,各警告选项既然能使之生效,当然也能使之关闭。比如假设我

20、们想要使用 -Wall 来启用个选项,同时又要关 闭 unused 警告,利益通过下面的命令来达到目的: $ gcc -Wall -Wno-unused test.c -o test 下面是使用 -Wall 选项的时候没有生效的一些警告项: 288 基于 ARM9 和 Linux 嵌入式系 统设计 cast-align:一旦某个指针类型强制转换时,会导致目标所需的地址对齐边界扩展,编译器就发出警告。例如,某些机器上只能在 2 或 4 字节边界上访问整数,如果在这种机型上把 char *强制转换成 int *类型, 编译器就发出警告。 sign-compare:将有符号类型和无符号类型数据进行比

21、较时发出警告。 missing-prototypes :如果没有预先声明函数原形就定义了全局函数,编译器就发出警告。即使函数定义自身提供了函数原形也会产生这个警告。这样做的目的是检查没有在头文件中声明的全局函数。 packed:当结构体带有 packed 属性但实际并没有出现紧缩式给出警告。 padded:如果结构体通过充填进行对齐则给出警告。 unreachable-code:如果发现从未执行的代码时给出警告。 inline:如果某函数不能内嵌( inline),无论是声明为 inline 或者是指定了-finline-functions 选项,编译器都将发出警告。 disabled-opt

22、imization:当需要太长时间或过多资源导致不能完成某项优化时给出警告。 9.2.2 GDB 调试器简介 Linux 系统中包含了 GNU 调试程序 gdb,它是一个用来调试 C 和 C+ 程序的调试器。可以使程序开发者在程序运行时观察程序的内部结构和内存的使用情况。 gdb 提供如下功能: 运行程序,设置所有的能影响程序运行的参数和环境。 控制程序在指定的条件下停止运行。 当程序停止时,可以检查程序的状态。 修改程序的 错误,并重新运行程序。 动态监视程序中变量的值。 可以单步执行代码,观察程序的运行状态。 gdb 程序调试的对象是可执行文件,而不是程序的源代码文件。然而,并不是所有的可

23、执行文件都可以用 gdb 调试。如果要让产生的可执行文件可以用来调试,需在执行 gcc指令编译程序时,加上 -g 参数,指定程序在编译时包含调试信息。调试信息包含程序里的每个变量的类型和在可执行文件里的地址映射以及源代码的行号。 gdb 利用这些信息使源代码和机器码相关联。 1 gdb 的启动 在终端窗口中,有两种方法运行 gdb,即在终端窗口 的命令行中直接输入 gdb 命令或gdb filename 命令运行 gdb,下面分别介绍。 方法 1: 先启动 gdb 后执行 file filename 命令。即 gdb 基于 ARM9 和 Linux 嵌入式系统设计 289 file filen

24、ame 执行上述两条命令就可启动 gdb,并装入可执行的程序 filename。 方法 2: 启动 gdb 的同时装入可执行的程序。即 gdb filename 其中, filename 是要调试的可执行文件。用这种方式运行 gdb 可以直接指定想要调试的程序。这和启动 gdb 后执行 file filename 命令效果完全一样。 启动 gdb 后,就可以使用 gdb 的命令调试程序。 2 gdb 的基本命令 gdb 中的命令主要分为以下几类:工作环境相关命令、设置断点与恢复命令、源代码查看命令、查看运行数据相关命令及修改运行参数命令。 gdb 的命令可以通过 help 命令进行查找命令所属

25、的 种类( class),可以从相关 class 找到相应命令。如下所示: (gdb) help 此命令可列出命令的种类。 (gdb) help data 此命令查找 data 类种的命令,并列出 data 类种的所有命令。 (gdb) help call 此命令 查找 call 命令 。 若用户已知命令名,直接键入“ help command”来查看命令。 下面分别对这几类的命令进行讲解。 ( 1)工作环境相关命令 gdb 中不仅可以调试所运行的程序,而且还可以对程序相关的工作环境进行相应的设定,甚至还可以使用 shell 中的命令进行相关的操作,其功能极其强大。表 9.2 所示列出了 gd

26、b 常见工作环境相关命令。 表 9.2 gdb 工作环境相关命令 命 令 格 式 含 义 set args 指定运行时参数,如: set args 2 show args 查看设置好的运行 参数 path dir 设定程序的运行路径 show paths 查看程序的运行路径 set enVironment var =value 设置环境变量 show enVironment var 查看环境变量 cd dir 进入到 dir 目录,相当于 shell 中的 cd 命令 pwd 显示当前工作目录 shell command 运行 shell 的 command 命令 290 基于 ARM9 和

27、Linux 嵌入式系 统设计 (2) 设置断点与恢复命令 gdb 中设置断点与恢复的常见命令如表 9.3 所示。 表 9.3 gdb 设置断点与恢复相关命 令 命 令 格 式 含 义 bnfo b 查看所设断点 break 行号或函数名 设置断点 tbreak 行号或函数名 设置临时断点,到达后被自动删除 delete 断点号 删除指定断点,其断点号为” info b”中的第一栏。若缺省断点号则删除所有断点 disable 断点号 停止指定断点,使用” info b”仍能查看此断点。同 delete 一样,省断点号则停止所有断点 enable 断点号 激活指定断点,即激活被 disable 停

28、止的断点 condition 断点号 修改对应断点的条件 ignore 断点号 在程序执行中,忽略对应断点 num 次 step 单步恢复程序运行,且进入函数调用 next 单步恢复程序运行,但不进入函数调用 finish 运行程序,直到当前函数完成返回 c 继续执行函数,直到函数结束或遇到新的断点 ( 3) gdb 中源码查看相关命令 在 gdb 中可以查看源码以方便其他操作,它的常见相关命令如表 9.4 所示: 表 9.4 gdb 源码查看相关相关命令 命 令 格 式 含 义 list | 查看指定位置代码 file 文件名 加载指定文件 forward-search 正则表达式 源代码前

29、向搜索 reverse-search 正则表达式 源代码后向搜索 dir dir 停止路径名 show directories 显示定义了的源文件搜索路径 info line 显示加载到 gdb 内存中的代码 (4) gdb 中查看运行数据相关命令 gdb 中查看运行数据是指当程序处于“运行”或“暂停”状态时,可以查看的变量及表达式的信息,其常见命令如表 9.5 所示: 基于 ARM9 和 Linux 嵌入式系统设计 291 表 9.5 gdb 查看运行数据相关命令 命 令 格 式 含 义 print 表达式 |变量 查看程序运行时对应表达式和变量的值 x 查看内存变量内容。其中 n 为整数表

30、示显示内存的长度, f 表示显示的格式, u 表示从当前地址往后请求显示的字节数 display 表达式 设定在单步运行或其他情况中,自动显示的对应表达式的内容 ( 5)其他 gdb 命令 run 命令:执行当前被调试的程序。 kill 命令:停止正在调试的应用程序。 watch 命令:设置监视点,监视表 达式的变化。 awatch 命令:设置读写监视点。当要监视的表达式被读或写时将应用程序挂起。它的语法与 watch 命令相同。 rwatch 命令:设置读监视点,当监视表达式被读时将程序挂起,等侍调试。此命令的语法与 watch 相同。 info break 命令:显示当前断点列表,包括每个

31、断点到达的次数。 info files 命令:显示调试文件的信息。 info func 命令:显示所有的函数名。 info local 命令:显示当前函数的所有局部变量的信息。 info prog 命令:显示调试程序的执行状态。 Shell 命令:执行 Linux Shell 命令。 make 命令:不退出 gdb 而重新编译生成可执行文件。 Quit 命令:退出 gdb。 (6) gdb 中修改运行参数相关命令 gdb 还可以修改运行时的参数,并使该变量按照用户当前输入的值继续运行。它的设置方法为:在单步执行的过程中,键入命令“ set 变量设定值”。这样,在此之后,程序就会按照该设定的值运

32、行了。 特别注意,在 gcc 编译选项中一定要加入” -g”。只有在代码处于“运行”或“暂停”状态时才能查看变量值 ,设置断点后程序在指定行之前停止。 9.3 GNU make 命令和 makefile 文件 Makefile 文件描述了目标文件之间的依赖关系,以及指定编译过程中使用的工具。Makefile 里主要包含了五个方面:显式规则、隐晦规则、变量定义、文件指示和注释。 显式规则。显式规则说明了如何生成一个或多个目标文件。这是由 Makefile 的书写者明显指出,要生成的文件、文件的依赖文件、生成的命令。 292 基于 ARM9 和 Linux 嵌入式系 统设计 隐晦规则。由于 mak

33、e 有自动推导的功能,所以隐晦的规则可以让我们比较简略地书写 Makefile,这是由 make 所支持的。 变量的定义。在 Makefile 中可定义一系列的变量,变量一般是字符串,类似 C 语言中的宏,当 Makefile 被执行时,其中的变量都会被扩展到相应的引用位置上。 文件指示。其包括 3 个部分,一个是在一个 Makefile 中引用另一个 Makefile,就像C 语言中的 include 一样;另一个是指根据某些情况指定 Makefile 中的有效部分,就像 C 语言中的预编译 #if 一样;还有就是定义一个多行的命令。 注释。 Makefile 中只有行注释,和 UNIX 的

34、 Shell 脚本一样,其注释是用“ #”字符,如果 在 Makefile 中使用“ #”字符,可以用反斜框进行转义,如:“ #”。 最后,还值得一提的是,在 Makefile 中的命令,必须要以 Tab键开始。 Makefile 定义了一系列的规则来指定哪些文件需要先编译,哪些文件需要后编译,哪些文件需要重新编译,甚至于进行更复杂的功能操作。 Makefile 就像一个 Shell 脚本一样,其中也可以执行操作系统的命令。 Makefile 带来的好处就是“自动化编译”,一旦写好,只需要一个 make 命令,整个工程完全自动编译,极大地提高了软件开发的效率。 GNU的 make 工作时的执

35、行步骤如下: 1、 读入所有的 Makefile。 2、 读入被 include 的其它 Makefile。 3、 初始化文件中的变量。 4、 推导隐晦规则,并分析所有规则。 5、 为所有的目标文件创建依赖关系链。 6、 根据依赖关系,决定哪些目标要重新生成。 7、 执行生成命令。 1-5 步为第一个阶段, 6-7 为第二个阶段。第一个阶段中,如果定义的变量被使用了,那么, make 会把其展开在使用的位置。但 make 并不会完全马上展开。 make 程序利用Makefile 中的数据和每个文件的最后修改时间来确定那个文件需要更新,对于需要更新的文件, make 程序执行 Makefile

36、数据中定义的命令来更新。 9.3.1 Makefile 文件的规则 GNU make 的主要功能是读入一个文本文件 makefile,并根据 makefile 的内容执行一系列的工作。 Makefile 的默认文件名为 GNU makefile、 makefile 或 Makefile,也可以在make 的命令行中指定别的文件名。如果不特别指定, make 命令在执行时将按顺序查找默认的 Makefile 文件。多数 Linux 程序员使用第三种文件名 Makefile。因为第一个字母是大写,通常被列在一个目录的文件列表的最前面 。 Makefile 文件包含一些规则。这些规则主要是描述哪些文件(称为 target 目标文件,注意,不是指编译时产生的目标文件)是从哪些别的文件(称为 dependency 依赖文件)中产生的,以及用什么命令( command)来执行这个过程。 依靠这些信息, make 会对磁盘上的文件进行检查,如果目标文件的生成或被改动时

展开阅读全文
相关资源
相关搜索

当前位置:首页 > 学术论文资料库 > 毕业论文

Copyright © 2018-2021 Wenke99.com All rights reserved

工信部备案号浙ICP备20026746号-2  

公安局备案号:浙公网安备33038302330469号

本站为C2C交文档易平台,即用户上传的文档直接卖给下载用户,本站只是网络服务中间平台,所有原创文档下载所得归上传人所有,若您发现上传作品侵犯了您的权利,请立刻联系网站客服并提供证据,平台将在3个工作日内予以改正。