binutils-2.18/ld/Makefile分析

Binutils ld链接器构建解析
本文详细解析了Binutils 2.18版本中ld链接器的构建过程,包括Makefile的递归调用机制、各个目标文件的生成顺序及依赖关系。深入介绍了关键源文件的编译流程,如ldgram、ldlex等,以及动态生成文件的过程。

 

快乐虾

http://blog.youkuaiyun.com/lights_joy/

lights@hb165.com

 

本文适用于

binutils-2.18

configure –target=bfin-uclinux-gnu

Blackfin系列DSP

Cygwin gcc 3.4.4

 

欢迎转载,但请保留作者信息

 

 

1       ld/Makefile

这个文件由主控Makefile调用configure脚本生成并执行make操作。要求生成的目标为all

1.1    all

Makefile中的第一个目标就是all

all: config.h

       $(MAKE) $(AM_MAKEFLAGS) all-recursive

all-recursive这个目标的生成是由RECURSIVE_TARGETS来完成的。

RECURSIVE_TARGETS = all-recursive check-recursive dvi-recursive /

       html-recursive info-recursive install-data-recursive /

       install-exec-recursive install-info-recursive /

       install-recursive installcheck-recursive installdirs-recursive /

       pdf-recursive ps-recursive uninstall-info-recursive /

       uninstall-recursive

# This directory's subdirectories are mostly independent; you can cd

# into them and run `make' without going through this Makefile.

# To change the values of `make' variables: instead of editing Makefiles,

# (1) if the variable is set in `config.status', edit `config.status'

#     (which will cause the Makefiles to be regenerated when you run `make');

# (2) otherwise, pass the desired values on the `make' command line.

$(RECURSIVE_TARGETS):

       @failcom='exit 1'; /

       for f in x $$MAKEFLAGS; do /

         case $$f in /

           *=* | --[!k]*);; /

           *k*) failcom='fail=yes';; /

         esac; /

       done; /

       dot_seen=no; /

       target=`echo $@ | sed s/-recursive//`; /

       list='$(SUBDIRS)'; for subdir in $$list; do /

         echo "Making $$target in $$subdir"; /

         if test "$$subdir" = "."; then /

           dot_seen=yes; /

           local_target="$$target-am"; /

         else /

           local_target="$$target"; /

         fi; /

         (cd $$subdir && $(MAKE) $(AM_MAKEFLAGS) $$local_target) /

         || eval $$failcom; /

       done; /

       if test "$$dot_seen" = "no"; then /

         $(MAKE) $(AM_MAKEFLAGS) "$$target-am" || exit 1; /

       fi; test -z "$$fail"

在这段脚本中将分别进入各子目录并执行make xxx操作,xxx-recusive目标的前面一部分。

在此略过子目录不做分析。当在ld目录下执行all-recursive操作时,上述脚本转而执行all-am目标,因此下面转而分析all-am目标。这条规则定义为:

all-am: Makefile $(PROGRAMS) $(MANS) config.h

PROGRAMS = $(noinst_PROGRAMS)

noinst_PROGRAMS = ld-new$(EXEEXT)

MANS = $(man_MANS)

man_MANS = ld.1

因此这个目标实际依赖于ld-new$(EXEEXT),它的规则定义为:

ld-new$(EXEEXT): $(ld_new_OBJECTS) $(ld_new_DEPENDENCIES)

       @rm -f ld-new$(EXEEXT)

       $(LINK) $(ld_new_LDFLAGS) $(ld_new_OBJECTS) $(ld_new_LDADD) $(LIBS)

在生成所有的.o文件后,这段脚本将之链接为ld-new.exe

1.1.1   $(ld_new_OBJECTS)

这个变量定义为:

ld_new_OBJECTS = $(am_ld_new_OBJECTS)

am_ld_new_OBJECTS = ldgram.$(OBJEXT) ldlex.$(OBJEXT) lexsup.$(OBJEXT) /

       ldlang.$(OBJEXT) mri.$(OBJEXT) ldctor.$(OBJEXT) /

       ldmain.$(OBJEXT) ldwrite.$(OBJEXT) ldexp.$(OBJEXT) /

       ldemul.$(OBJEXT) ldver.$(OBJEXT) ldmisc.$(OBJEXT) /

       ldfile.$(OBJEXT) ldcref.$(OBJEXT) sha1.$(OBJEXT)

因而有以下依赖关系:

1.1.1.1             ldgram.$(OBJEXT)

这条规则定义为:

ldgram.o:

       $(COMPILE) -c $< $(NO_WERROR)

同时有以下依赖关系:

ldgram.o: ldgram.c sysdep.h config.h $(INCDIR)/fopen-same.h /

  ../bfd/bfd.h $(INCDIR)/ansidecl.h $(INCDIR)/symcat.h /

  $(INCDIR)/bfdlink.h ld.h ldexp.h ldver.h ldlang.h ldfile.h /

  ldemul.h ldmisc.h ldmain.h mri.h ldctor.h ldlex.h

直接编译即可。

1.1.1.2             ldlex.$(OBJEXT)

这条规则定义为:

ldlex.o:

       $(COMPILE) -c $< $(NO_WERROR)

同时有以下依赖关系:

ldlex.o: ldlex.c sysdep.h config.h $(INCDIR)/fopen-same.h /

  ../bfd/bfd.h $(INCDIR)/ansidecl.h $(INCDIR)/symcat.h /

  $(INCDIR)/safe-ctype.h $(INCDIR)/bfdlink.h ld.h ldmisc.h /

  ldexp.h ldlang.h ldgram.h ldfile.h ldlex.h ldmain.h /

  $(INCDIR)/libiberty.h $(INCDIR)/ansidecl.h

直接编译即可。

 

1.1.1.3             lexsup.$(OBJEXT)

这个目标由通用规则生成:

.c.o:

       $(COMPILE) -c $<

同时有以下依赖关系:

lexsup.o: lexsup.c sysdep.h config.h $(INCDIR)/fopen-same.h /

  ../bfd/bfd.h $(INCDIR)/ansidecl.h $(INCDIR)/symcat.h /

  ../bfd/bfdver.h $(INCDIR)/libiberty.h $(INCDIR)/ansidecl.h /

  $(INCDIR)/safe-ctype.h $(INCDIR)/bfdlink.h ld.h ldmain.h /

  ldmisc.h ldexp.h ldlang.h ldgram.h ldlex.h ldfile.h /

  ldver.h ldemul.h $(INCDIR)/demangle.h $(INCDIR)/libiberty.h

直接编译即可。

 

1.1.1.4             ldlang.$(OBJEXT)

这个目标由通用规则生成:

.c.o:

       $(COMPILE) -c $<

同时有以下依赖关系:

ldlang.o: ldlang.c sysdep.h config.h $(INCDIR)/fopen-same.h /

  ../bfd/bfd.h $(INCDIR)/ansidecl.h $(INCDIR)/symcat.h /

  $(INCDIR)/libiberty.h $(INCDIR)/ansidecl.h $(INCDIR)/safe-ctype.h /

  $(INCDIR)/obstack.h $(INCDIR)/bfdlink.h ld.h ldmain.h /

  ldexp.h ldlang.h ldgram.h ldlex.h ldmisc.h ldctor.h /

  ldfile.h ldemul.h $(INCDIR)/fnmatch.h $(INCDIR)/demangle.h /

  $(INCDIR)/libiberty.h $(INCDIR)/hashtab.h

直接编译即可。

 

1.1.1.5             mri.$(OBJEXT)

这个目标由通用规则生成:

.c.o:

       $(COMPILE) -c $<

同时有以下依赖关系:

mri.o: mri.c sysdep.h config.h $(INCDIR)/fopen-same.h /

  ../bfd/bfd.h $(INCDIR)/ansidecl.h $(INCDIR)/symcat.h /

  ld.h ldexp.h ldlang.h ldmisc.h mri.h ldgram.h $(INCDIR)/libiberty.h /

  $(INCDIR)/ansidecl.h

直接编译即可。

 

1.1.1.6             ldctor.$(OBJEXT)

这个目标由通用规则生成:

.c.o:

       $(COMPILE) -c $<

同时有以下依赖关系:

ldctor.o: ldctor.c sysdep.h config.h $(INCDIR)/fopen-same.h /

  ../bfd/bfd.h $(INCDIR)/ansidecl.h $(INCDIR)/symcat.h /

  $(INCDIR)/bfdlink.h $(INCDIR)/safe-ctype.h ld.h ldexp.h /

  ldlang.h ldmisc.h ldgram.h ldmain.h ldctor.h

直接编译即可。

 

1.1.1.7             ldmain.$(OBJEXT)

这条规则定义为:

ldmain.o: ldmain.c config.status

       $(COMPILE) -c -DDEFAULT_EMULATION='"$(EMUL)"' /

         -DSCRIPTDIR='"$(scriptdir)"' -DBINDIR='"$(bindir)"' /

         -DTOOLBINDIR='"$(tooldir)/bin"' /

         -DTARGET='"bfin-unknown-uclinux-gnu"' -DTARGET_SYSTEM_ROOT=/"/" /

         $(srcdir)/ldmain.c

还有以下的依赖关系:

ldmain.o: ldmain.c sysdep.h config.h $(INCDIR)/fopen-same.h /

  ../bfd/bfd.h $(INCDIR)/ansidecl.h $(INCDIR)/symcat.h /

  $(INCDIR)/safe-ctype.h $(INCDIR)/libiberty.h $(INCDIR)/ansidecl.h /

  $(INCDIR)/progress.h $(INCDIR)/bfdlink.h $(INCDIR)/filenames.h /

  ld.h ldmain.h ldmisc.h ldwrite.h ldexp.h ldlang.h ldgram.h /

  ldlex.h ldfile.h ldemul.h ldctor.h

直接编译即可。

 

1.1.1.8             ldwrite.$(OBJEXT)

这个目标由通用规则生成:

.c.o:

       $(COMPILE) -c $<

同时有以下依赖关系:

ldwrite.o: ldwrite.c sysdep.h config.h $(INCDIR)/fopen-same.h /

  ../bfd/bfd.h $(INCDIR)/ansidecl.h $(INCDIR)/symcat.h /

  $(INCDIR)/bfdlink.h $(INCDIR)/libiberty.h $(INCDIR)/ansidecl.h /

  $(INCDIR)/safe-ctype.h ld.h ldexp.h ldlang.h ldwrite.h /

  ldmisc.h ldgram.h ldmain.h

直接编译即可。

 

1.1.1.9             ldexp.$(OBJEXT)

这个目标由通用规则生成:

.c.o:

       $(COMPILE) -c $<

同时有以下依赖关系:

ldexp.o: ldexp.c sysdep.h config.h $(INCDIR)/fopen-same.h /

  ../bfd/bfd.h $(INCDIR)/ansidecl.h $(INCDIR)/symcat.h /

  $(INCDIR)/bfdlink.h ld.h ldmain.h ldmisc.h ldexp.h /

  ldlex.h ldgram.h ldlang.h $(INCDIR)/libiberty.h $(INCDIR)/ansidecl.h /

  $(INCDIR)/safe-ctype.h

直接编译即可。

 

1.1.1.10       ldemul.$(OBJEXT)

这个目标由通用规则生成:

.c.o:

       $(COMPILE) -c $<

同时有以下依赖关系:

ldemul.o: ldemul.c sysdep.h config.h $(INCDIR)/fopen-same.h /

  ../bfd/bfd.h $(INCDIR)/ansidecl.h $(INCDIR)/symcat.h /

  $(INCDIR)/bfdlink.h ld.h ldmisc.h ldexp.h ldlang.h /

  ldfile.h ldemul.h ldmain.h ldemul-list.h

在这里ldemul-list.h文件需要动态生成,规则如下:

ldemul-list.h: Makefile

       (echo "/* This file is automatically generated.  DO NOT EDIT! */";/

       for f in `echo " " ${EMULATION_OFILES} "" /

        | sed -e 's/ e/ ld/g' -e 's/ ld/ /g' -e 's/[.]o//g'`; do /

           echo "extern ld_emulation_xfer_type ld_$${f}_emulation;"; /

       done;/

       echo "";/

       echo "#define EMULATION_LIST //";/

       for f in `echo " " ${EMULATION_OFILES} "" /

        | sed -e 's/ e/ ld/g' -e 's/ ld/ /g' -e 's/[.]o//g'`; do /

           echo "  &ld_$${f}_emulation, //"; /

       done;/

       echo "  0") >ldemul-tmp.h

       mv ldemul-tmp.h ldemul-list.h

生成此文件后直接编译即可。

 

1.1.1.11       ldver.$(OBJEXT)

这个目标由通用规则生成:

.c.o:

       $(COMPILE) -c $<

同时有以下依赖关系:

ldver.o: ldver.c sysdep.h config.h $(INCDIR)/fopen-same.h /

  ../bfd/bfd.h $(INCDIR)/ansidecl.h $(INCDIR)/symcat.h /

  ../bfd/bfdver.h ld.h ldver.h ldexp.h ldlang.h ldfile.h /

  ldemul.h ldmain.h

直接编译即可。

 

1.1.1.12       ldmisc.$(OBJEXT)

这个目标由通用规则生成:

.c.o:

       $(COMPILE) -c $<

同时有以下依赖关系:

ldmisc.o: ldmisc.c sysdep.h config.h $(INCDIR)/fopen-same.h /

  ../bfd/bfd.h $(INCDIR)/ansidecl.h $(INCDIR)/symcat.h /

  $(INCDIR)/bfdlink.h $(INCDIR)/libiberty.h $(INCDIR)/ansidecl.h /

  $(INCDIR)/demangle.h $(INCDIR)/libiberty.h ld.h ldmisc.h /

  ldexp.h ldlang.h ldgram.h ldlex.h ldmain.h ldfile.h /

  $(BFDDIR)/elf-bfd.h $(INCDIR)/elf/common.h $(INCDIR)/elf/internal.h /

  $(INCDIR)/elf/external.h $(INCDIR)/bfdlink.h

直接编译即可。

 

1.1.1.13       ldfile.$(OBJEXT)

这个目标由通用规则生成:

.c.o:

       $(COMPILE) -c $<

同时有以下依赖关系:

ldfile.o: ldfile.c sysdep.h config.h $(INCDIR)/fopen-same.h /

  ../bfd/bfd.h $(INCDIR)/ansidecl.h $(INCDIR)/symcat.h /

  $(INCDIR)/bfdlink.h $(INCDIR)/safe-ctype.h ld.h ldmisc.h /

  ldexp.h ldlang.h ldfile.h ldmain.h ldgram.h ldlex.h /

  ldemul.h $(INCDIR)/libiberty.h $(INCDIR)/ansidecl.h /

  $(INCDIR)/filenames.h

直接编译即可。

 

1.1.1.14       ldcref.$(OBJEXT)

这个目标由通用规则生成:

.c.o:

       $(COMPILE) -c $<

同时有以下依赖关系:

ldcref.o: ldcref.c sysdep.h config.h $(INCDIR)/fopen-same.h /

  ../bfd/bfd.h $(INCDIR)/ansidecl.h $(INCDIR)/symcat.h /

  $(INCDIR)/bfdlink.h $(INCDIR)/libiberty.h $(INCDIR)/ansidecl.h /

  $(INCDIR)/demangle.h $(INCDIR)/libiberty.h $(INCDIR)/objalloc.h /

  ld.h ldmain.h ldmisc.h ldexp.h ldlang.h

直接编译即可。

 

1.1.1.15       sha1.$(OBJEXT)

这个目标由通用规则生成:

.c.o:

       $(COMPILE) -c $<

同时有以下依赖关系:

sha1.o: sha1.c config.h sha1.h

直接编译即可。

 

1.1.2   $(ld_new_DEPENDENCIES)

这个变量定义为:

ld_new_DEPENDENCIES = $(EMULATION_OFILES) $(EMUL_EXTRA_OFILES) $(BFDLIB) $(LIBIBERTY) $(LIBINTL_DEP)

EMUL_EXTRA_OFILES =

EMULATION_OFILES =  eelf32bfin.o eelf32bfinfd.o

因而有以下依赖关系。

1.1.2.1             eelf32bfin.o

这个目标由通用规则生成:

.c.o:

       $(COMPILE) -c $<

但是eelf32bfin.c则需要动态生成:

eelf32bfin.c: $(srcdir)/emulparams/bfin.sh /

  $(ELF_DEPS) /

  $(srcdir)/scripttempl/elf.sc ${GEN_DEPENDS}

       ${GENSCRIPTS} elf32bfin "$(tdir_elf32bfin)" bfin

生成这个c文件后将之编译为.o文件。

1.1.2.2             eelf32bfinfd.o

这个目标由通用规则生成:

.c.o:

       $(COMPILE) -c $<

但是eelf32bfinfd.c则需要动态生成:

eelf32bfinfd.c: $(srcdir)/emulparams/elf32bfinfd.sh $(srcdir)/emulparams/bfin.sh /

  $(ELF_DEPS) /

  $(srcdir)/scripttempl/elf.sc ${GEN_DEPENDS}

       ${GENSCRIPTS} elf32bfinfd "$(tdir_elf32bfinfd)" elf32bfinfd

生成这个c文件后将之编译为.o文件。

 

2       目标生成顺序

以下是所有目标的生成顺序:

ld/Makefile: info-recursive: begin

ld/Makefile: info-recursive: end

ld/Makefile: all: begin

ld/Makefile: all-recursive: begin

ld/Makefile: ldgram.o: begin

ld/Makefile: ldgram.o: end

ld/Makefile: ldlex.o: begin

ld/Makefile: ldlex.o: end

ld/Makefile: lexsup.o: begin

ld/Makefile: lexsup.o: end

ld/Makefile: ldlang.o: begin

ld/Makefile: ldlang.o: end

ld/Makefile: mri.o: begin

ld/Makefile: mri.o: end

ld/Makefile: ldctor.o: begin

ld/Makefile: ldctor.o: end

ld/Makefile: ldmain.o: begin

ld/Makefile: ldmain.o: end

ld/Makefile: ldwrite.o: begin

ld/Makefile: ldwrite.o: end

ld/Makefile: ldexp.o: begin

ld/Makefile: ldexp.o: end

ld/Makefile: ldemul-list.h: begin

ld/Makefile: ldemul-list.h: end

ld/Makefile: ldemul.o: begin

ld/Makefile: ldemul.o: end

ld/Makefile: ldver.o: begin

ld/Makefile: ldver.o: end

ld/Makefile: ldmisc.o: begin

ld/Makefile: ldmisc.o: end

ld/Makefile: ldfile.o: begin

ld/Makefile: ldfile.o: end

ld/Makefile: ldcref.o: begin

ld/Makefile: ldcref.o: end

ld/Makefile: sha1.o: begin

ld/Makefile: sha1.o: end

ld/Makefile: eelf32bfin.c: begin

ld/Makefile: eelf32bfin.c: end

ld/Makefile: eelf32bfin.o: begin

ld/Makefile: eelf32bfin.o: end

ld/Makefile: eelf32bfinfd.c: begin

ld/Makefile: eelf32bfinfd.c: end

ld/Makefile: eelf32bfinfd.o: begin

ld/Makefile: eelf32bfinfd.o: end

ld/Makefile: ld-new.exe: begin

ld/Makefile: ld-new.exe: end

ld/Makefile: all-recursive: end

ld/Makefile: all: end

3       参考资料

binutils-2.18/libiberty/Makefile分析 2008-8-27

binutils-2.18/bfd/Makefile分析( 2008-8-28 )

binutils-2.18/gprof/Makefile分析( 2008-8-29 )

 

 

 

 

 

 

 

 

 

 

<think>我们正在解决RISC-VGNU工具链构建过程中遇到的binutils构建错误,特别是bfd目录下的问题。根据引用[2],用户在新版本riscv-gnu-toolchain中遇到了子模块路径更改的问题:binutils的子模块路径从`riscv-binutils`改为了`binutils`,导致构建失败。此外,引用[3]提供了关于工具链命名的背景信息,但当前问题更关注构建过程。根据错误信息:&ldquo;gitsubmoduleupdate--init--recursiveriscv-binutils”失败,因为新版本中已经移除了&ldquo;riscv-”前缀,所以子模块名称应为`binutils`。解决方案:1.手动更新子模块:进入riscv-gnu-toolchain目录,执行以下命令:```bashgitsubmoduleupdate--init--recursivebinutils```如果已经尝试过更新而失败,可能需要先清理:```bashgitsubmoduledeinit-fbinutils#如果之前初始化失败,可以尝试先取消初始化gitsubmoduleupdate--init--recursivebinutils```2.如果上述方法无效,可能是子模块配置有问题。可以尝试编辑`.gitmodules`文件,将binutils子模块的路径修正为正确的URL和路径。通常,正确的配置应该类似:```ini[submodule"binutils"]path=binutilsurl=https://sourceware.org/git/binutils-gdb.git```然后再次运行`gitsubmoduleupdate--init--recursivebinutils`。3.如果问题仍然存在,可以尝试删除整个工具链目录,重新克隆,并注意在初始化子模块时使用正确的名称。4.引用[1]中提到过复制boringssl到特定路径,但此问题与binutils相关,因此可能不需要。但注意,如果构建过程中还涉及其他子模块(如newlib、gcc等),确保所有子模块都已正确初始化。5.如果使用Homebrew安装(如引用[2]所述),可能需要更新Homebrew的配方(formula)以适配新的子模块名称。但用户可能更倾向于手动构建,因为Homebrew的更新可能滞后。6.构建环境配置:确保构建环境满足要求,例如必要的依赖包(如gcc,make,autoconf,automake,texinfo等)。7.如果构建过程中bfd目录出现错误,可能是由于binutils的特定版本存在问题。可以尝试切换到稳定版本的分支或标签:```bashcdbinutilsgitcheckout<稳定版本标签>cd..```8.构建命令:在riscv-gnu-toolchain目录下,按照引用[1]中的配置和构建步骤:```bash./configure--prefix=/opt/riscv-gnu-toolchain--with-cmodel=medany--enable-multilibmake```注意:构建过程中可能需要较长时间,且确保有足够的权限(如安装到/opt可能需要sudo)。如果问题仍然存在,请提供具体的错误信息,以便进一步分析。§§相关问题§§1.如何手动初始化riscv-gnu-toolchain的子模块?2.在构建riscv-gnu-toolchain时,如何解决依赖问题?3.如何为特定的RISC-V架构配置工具链?</think>### RISC-V GNU工具链构建错误解决方案 针对您在构建`riscv-gnu-toolchain`时遇到的`build-binutils-linux bfd`目录错误,结合引用内容和常见问题,以下是逐步解决方案: #### 错误原因分析 1. **子模块路径变更**(引用[2]问题): - 新版本工具链中`binutils`子模块路径从`riscv-binutils`改为`binutils` - 导致`git submodule update`命令失败:`pathspec 'riscv-binutils' did not match` 2. **环境配置问题**: - 依赖库缺失(如GMP/MPFR/MPC) - 权限问题(安装到`/opt`需`sudo`) - 工具链命名规则混淆(引用[3]的架构前缀说明) #### 解决方案步骤 1. **修正子模块初始化**: ```bash # 进入工具链目录 cd riscv-gnu-toolchain # 手动更新子模块路径(移除旧前缀) git submodule deinit -f riscv-binutils # 清理旧配置 git submodule update --init --recursive binutils ``` 2. **安装构建依赖**: ```bash # Ubuntu/Debian sudo apt install autoconf automake autotools-dev curl libmpc-dev \ libmpfr-dev libgmp-dev gawk build-essential bison flex texinfo ``` 3. **重建binutils**: ```bash # 清理旧构建 make clean rm -rf build-binutils-linux # 指定bfd目录重建 ./configure --prefix=/opt/riscv-gnu-toolchain \ --with-cmodel=medany \ --enable-multilib \ --enable-languages=c,c++ make build-binutils-linux ``` 4. **权限处理**: ```bash # 若安装到系统目录需sudo(引用[1]) sudo make install ``` 5. **环境变量配置**(引用[1]): 在`~/.bashrc`添加: ```bash export PATH=/opt/riscv-gnu-toolchain/bin:$PATH export RISCV=/opt/riscv-gnu-toolchain ``` #### 验证成功 ```bash riscv64-unknown-linux-gnu-as --version # 应显示binutils版本 ``` > **注意**:若仍报错,检查`build-binutils-linux/bfd/config.log`中的具体编译错误。
评论 8
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

嵌云阁主

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值