链接脚本ld

2023-05-16

1 基础内容

1.1 程序编译阶段

一般而言,程序编译经历下图四个阶段,链接是编译的最后一步,无论是在PC上编译代码,还是在PC上使用嵌入式gcc工具交叉编译嵌入式代码,编译过程都是如下几步
在这里插入图片描述

1.2 链接脚本

链接过程是将各式各样的.o文件链接为一个文件的过程。链接脚本描述连接器如何将这些输入文件(.o)文件映射为一个输出文件的,并且定义了输出文件的memory layout。几乎所有的链接脚本都是在做这些事情。

在使用ld的时候,通过-T选项,可以使用自己写的链接脚本完成链接过程,否则会使用默认的链接脚本。

基础的链接脚本概念

接下来需要定义一些基础的概念以及词汇用来描述链接脚本语言。

连接器将输入文件组合为一个单独的输出文件。输入文件和输出文件的数据类型是我们熟知的object file format。每个文件被称为object file。输出文件不仅仅可以称为object file,有时也会叫他executable可执行文件,出于我们描述的目的,我们依旧称他为object file。

每一个object,有很多其他的信息,但是最重要的是section的列表。这也是着重要谈的。大多数时候,我们会把输入的Object文件里面的section称之为 input section。链接输出的单个Object文件里面的section称之为output section。

在Object文件中,每一个section有一个名字还有对应的size信息,几乎所有的section都有一个数据关联块(associated block of data)。

section可以被标记为loadable,意味着当输出文件运行起来的时候,这个section的content信息应当被加载到memory中。

section没有content信息,并且被标记为allocatable,意味着会有一块内存会被创建,但是却没有任何内容放在上面,程序运行起来的时候无需要加载任何信息到memory中。

如果section既不是loadable也不是allocatable,那么意味着它包含了一些debug的信息。

链接脚本的输出文件是一个Object文件,里面包含了多个section,包括loadable的section,也包括allocatable section。每一个section包含两个地址,分别是VMA以及LMA。

VMA是virtual memory address,LMA是load memory address。大多数两类地址是相同的,但是在嵌入式开发中不大相同,LMA是flash地址,而VMA是将flash加载到ram里面运行的ram地址。

例如下述的嵌入式C代码,显然全局变量a在编译成bin的时候是烧写进flash的,但是程序运行起来之后a的数据是需要加载进ram的,因为a是一个变量,不排除程序运行过程中代码会改变他的值。因此flash会存放他的初始值,运行的时候从ROM加载到RAM,他在ROM中的地址是LMA,在RAM中的地址是VMA。

下文会使用objdumo -h指令查看object文件里面的section,以及对应的VMA和LMA。

每个object文件拥有一个symbols列表,里面包含的symbol可以是被定义或者未被定义的。每一个symbol有名字和地址。如果是C/C++程序编译出来的.o文件。所有的函数和全局静态变量都处于defined的状态,在输入文件中引用的每个未定义的函数或全局变量都将成为一个未定义的符号。

使用 objdumo -t指令可以查看对应object的symbols。

1.4 链接脚本格式

链接脚本是text文件,空格忽略。

1.5 简单的链接脚本例子

假设连接器的输入object里面只有代码.text段,数据.data段,未初始化的data段.bss。

假设代码希望放在0x10000,数据希望放在0x8000000。下面代码将会描述这样的链接脚本

SECTIONS
{
  . = 0x10000;
  .text : {*(.text)}
  . = 0x8000000;
  .data : {*(.data)}
  .bss : {*(.bss)}
}

第一行,使用’.'给memory map定位地址。如果不适用 "."来指定开始地址,那么将会从0开始分配地址。

第二行定义了一个output scetion,名字叫’.text’,后面花括号里面的内容是其他.o文件里面作为输入的section名称,输入的section会被存放到output section中。是通配符的含义,可以匹配任意文件名 ,(.text) 意味着所有输入文件中的.text段。

因为location counter 被配置为0x10000,因此连接器会把text的内容存放到0x10000中。

后面的几行与text段同理,.data段和.bss段都是从0x8000000开始的,并且是紧紧挨在一起的。

连接器会保证每个段的对齐方式,以此作为依据来增加loaction counter。

2 实践链接器过程

为了深度体验连接器的工作过程,我们创建add.c文件,data.c 和main.c文件三个文件,并且写自己定义的链接脚本将这个三个.c文件链接为一个输出文件

main.c
----------------
extern int add(int a , int b);
extern int data1;
extern int data2;
int main(void){
        add(data1,data2)
        return 0;
}

data.c
-----------------
int data1=10;
int data2=20;

add.c
-----------------
int add(int a , int b){
    return a+b;
}

使用arm gcc 生成每个.c对应的.o文件

arm-none-eabi-gcc -c main.c
arm-none-eabi-gcc -c data.c
arm-none-eabi-gcc -c add.c

2.1 观察main.o的内容

使用objdump工具观察编译生成的main.o文件

arm-none-eabi-objdump -h main.o

得到

main.o:     file format elf32-littlearm

Sections:
Idx Name          Size      VMA       LMA       File off  Algn
  0 .text         00000040  00000000  00000000  00000034  2**2
                  CONTENTS, ALLOC, LOAD, RELOC, READONLY, CODE
  1 .data         00000000  00000000  00000000  00000074  2**0
                  CONTENTS, ALLOC, LOAD, DATA
  2 .bss          00000000  00000000  00000000  00000074  2**0
                  ALLOC
  3 .comment      00000080  00000000  00000000  00000074  2**0
                  CONTENTS, READONLY
  4 .ARM.attributes 00000030  00000000  00000000  000000f4  2**0
                  CONTENTS, READONLY

为了更清晰的看到每个段的含义,使用

arm-none-eabi-objdump -s -d main.o

查看反汇编

Contents of section .text:
 0000 00482de9 04b08de2 28309fe5 002093e5  .H-.....(0... ..
 0010 24309fe5 003093e5 0310a0e1 0200a0e1  $0...0..........
 0020 feffffeb 0030a0e3 0300a0e1 04d04be2  .....0........K.
 0030 0048bde8 1eff2fe1 00000000 00000000  .H..../.........
Contents of section .comment:
 0000 00474343 3a202847 4e552054 6f6f6c73  .GCC: (GNU Tools
 0010 20666f72 2041726d 20456d62 65646465   for Arm Embedde
 0020 64205072 6f636573 736f7273 20372d32  d Processors 7-2
 0030 3031382d 71322d75 70646174 65292037  018-q2-update) 7
 0040 2e332e31 20323031 38303632 32202872  .3.1 20180622 (r
 0050 656c6561 73652920 5b41524d 2f656d62  elease) [ARM/emb
 0060 65646465 642d372d 6272616e 63682072  edded-7-branch r
 0070 65766973 696f6e20 32363139 30375d00  evision 261907].
Contents of section .ARM.attributes:
 0000 412f0000 00616561 62690001 25000000  A/...aeabi..%...
 0010 0541524d 3754444d 49000602 08010901  .ARM7TDMI.......
 0020 12041401 15011703 18011901 1a011e06  ................

Disassembly of section .text:

00000000 <main>:
   0:   e92d4800        push    {fp, lr}
   4:   e28db004        add     fp, sp, #4
   8:   e59f3028        ldr     r3, [pc, #40]   ; 38 <main+0x38>
   c:   e5932000        ldr     r2, [r3]
  10:   e59f3024        ldr     r3, [pc, #36]   ; 3c <main+0x3c>
  14:   e5933000        ldr     r3, [r3]
  18:   e1a01003        mov     r1, r3
  1c:   e1a00002        mov     r0, r2
  20:   ebfffffe        bl      0 <add>
  24:   e3a03000        mov     r3, #0
  28:   e1a00003        mov     r0, r3
  2c:   e24bd004        sub     sp, fp, #4
  30:   e8bd4800        pop     {fp, lr}
  34:   e12fff1e        bx      lr
        ...


看到有一个需要链接的位置

 ebfffffe        bl      0 <add>

有一个标签,bl目前跳转的地方是0地址,后期连接器应该是需要把这个值改回来的。

总体来看main.o需要链接两个全局变量和一个函数位置。函数位置看到了 后期应该会替换,两个全局变量尚且没看到,是38<main+0x38> 这个字符串吗很有可能。

因为看到把[pc, #40]的数据和[pc, #36]的数据最后放到了r0 r1寄存器中,然后启用的调用add函数,猜测通过r0 r1传递变量。具体的看后面链接成功之后的输出.o的内容。

从二进制可以显然的看出,comment ARM.attributes存放了一些工具链相关的信息,并不需要关心。

观察data.o 的内容

使用objdump工具观察编译生成的data.o文件

data.o:     file format elf32-littlearm

Sections:
Idx Name          Size      VMA       LMA       File off  Algn
  0 .text         00000000  00000000  00000000  00000034  2**0
                  CONTENTS, ALLOC, LOAD, READONLY, CODE
  1 .data         00000008  00000000  00000000  00000034  2**2
                  CONTENTS, ALLOC, LOAD, DATA
  2 .bss          00000000  00000000  00000000  0000003c  2**0
                  ALLOC
  3 .comment      00000080  00000000  00000000  0000003c  2**0
                  CONTENTS, READONLY
  4 .ARM.attributes 00000030  00000000  00000000  000000bc  2**0
                  CONTENTS, READONLY

显然data.c里面没有包含任何有用的代码信息,只是使用int定义了两个全局变量,int的长度是4个字节,两个int于是占用了8个字节和.data 段的长度信息一致。

arm-none-eabi-objdump -s -d data.o

查的反汇编

data.o:     file format elf32-littlearm

Contents of section .data:
 0000 0a000000 14000000                    ........        
Contents of section .comment:
 0000 00474343 3a202847 4e552054 6f6f6c73  .GCC: (GNU Tools
 0010 20666f72 2041726d 20456d62 65646465   for Arm Embedde
 0020 64205072 6f636573 736f7273 20372d32  d Processors 7-2
 0030 3031382d 71322d75 70646174 65292037  018-q2-update) 7
 0040 2e332e31 20323031 38303632 32202872  .3.1 20180622 (r
 0050 656c6561 73652920 5b41524d 2f656d62  elease) [ARM/emb
 0060 65646465 642d372d 6272616e 63682072  edded-7-branch r
 0070 65766973 696f6e20 32363139 30375d00  evision 261907].
Contents of section .ARM.attributes:
 0000 412f0000 00616561 62690001 25000000  A/...aeabi..%...
 0010 0541524d 3754444d 49000602 08010901  .ARM7TDMI.......
 0020 12041401 15011703 18011901 1a011e06  ................

显然的看出,data.o里面只有.data段的数据,并且长度为8个字节,小端模式,的确包含了0x0000000a 以及 0x00000014两个全局变量的数据。

观察add.o 的内容

使用objdump工具观察编译生成的add.o文件

arm-none-eabi-objdump -h add.o

得到

add.o:     file format elf32-littlearm

Sections:
Idx Name          Size      VMA       LMA       File off  Algn
  0 .text         00000030  00000000  00000000  00000034  2**2
                  CONTENTS, ALLOC, LOAD, RELOC, READONLY, CODE
  1 .data         00000000  00000000  00000000  00000064  2**0
                  CONTENTS, ALLOC, LOAD, DATA
  2 .bss          00000000  00000000  00000000  00000064  2**0
                  ALLOC
  3 .comment      00000080  00000000  00000000  00000064  2**0
                  CONTENTS, READONLY
  4 .ARM.attributes 00000030  00000000  00000000  000000e4  2**0
                  CONTENTS, READONLY

显然add.c里面没有包含任何有用的数据信息,只有代码信息,对应.text段的长度不为零,其他为零。

arm-none-eabi-objdump -s -d add.o

得到

add.o:     file format elf32-littlearm

Contents of section .text:
 0000 04b02de5 00b08de2 0cd04de2 08000be5  ..-.......M.....
 0010 0c100be5 08201be5 0c301be5 033082e0  ..... ...0...0..
 0020 0300a0e1 00d08be2 04b09de4 1eff2fe1  ............../.
Contents of section .comment:
 0000 00474343 3a202847 4e552054 6f6f6c73  .GCC: (GNU Tools
 0010 20666f72 2041726d 20456d62 65646465   for Arm Embedde
 0020 64205072 6f636573 736f7273 20372d32  d Processors 7-2
 0030 3031382d 71322d75 70646174 65292037  018-q2-update) 7
 0040 2e332e31 20323031 38303632 32202872  .3.1 20180622 (r
 0050 656c6561 73652920 5b41524d 2f656d62  elease) [ARM/emb
 0060 65646465 642d372d 6272616e 63682072  edded-7-branch r
 0070 65766973 696f6e20 32363139 30375d00  evision 261907].
Contents of section .ARM.attributes:
 0000 412f0000 00616561 62690001 25000000  A/...aeabi..%...
 0010 0541524d 3754444d 49000602 08010901  .ARM7TDMI.......
 0020 12041401 15011703 18011901 1a011e06  ................

Disassembly of section .text:

00000000 <add>:
   0:   e52db004        push    {fp}            ; (str fp, [sp, #-4]!)
   4:   e28db000        add     fp, sp, #0
   8:   e24dd00c        sub     sp, sp, #12
   c:   e50b0008        str     r0, [fp, #-8]
  10:   e50b100c        str     r1, [fp, #-12]
  14:   e51b2008        ldr     r2, [fp, #-8]
  18:   e51b300c        ldr     r3, [fp, #-12]
  1c:   e0823003        add     r3, r2, r3
  20:   e1a00003        mov     r0, r3
  24:   e28bd000        add     sp, fp, #0
  28:   e49db004        pop     {fp}            ; (ldr fp, [sp], #4)
  2c:   e12fff1e        bx      lr

看到汇编里面

add     r3, r2, r3

把r2和r3的数据相加存放在r3里面,实现了add的功能,然后用Mov把r3的数据放在了r0里面,实现return的功能?这一段汇编是实现了add功能的汇编代码。
思考:现在有三个.o文件,分别是data.o add.o main.o 其中data.o放了两个全局变量的具体取值,add.o存放了使得两个整形数相加的函数实现,main.o则是使用了data.o的数据,add.o的函数。main.o在链接之前并不知道数据的具体数值,也不知道调用函数的函数位置,因此事先会把不知道的信息空出来,等到链接的时候再合并。因此接下来要观察链接的结果。

为三个.o 文件编写链接脚本

假设,我们目标的memorymap ,数据段存放在0x80000位置,代码段存放再0x10000的位置。

于是写下如下代码
my.ld

SECTIONS { 
  . = 0x10000; 
  .text : {*(.text)}   
  . = 0x80000;   
  .data : {*(.data)}   
  .bss : {*(.bss)} 
}

链接

使用链接器链接

arm-none-eabi-ld add.o data.o main.o -T my.ld -o out

得到输出文件out
使用objdump观察out文件

/e/7-2018-q2/bin/arm-none-eabi-objdump.exe -h out

得到

out:     file format elf32-littlearm

Sections:
Idx Name          Size      VMA       LMA       File off  Algn
  0 .text         00000070  00010000  00010000  00010000  2**2
                  CONTENTS, ALLOC, LOAD, READONLY, CODE
  1 .data         00000008  00080000  00080000  00020000  2**2
                  CONTENTS, ALLOC, LOAD, DATA
  2 .comment      0000007f  00000000  00000000  00020008  2**0
                  CONTENTS, READONLY
  3 .ARM.attributes 00000030  00000000  00000000  00020087  2**0
                  CONTENTS, READONLY

看到链接后的out文件的text和data size是多个.o文件的和。

反汇编

out:     file format elf32-littlearm

Contents of section .text:
 10000 04b02de5 00b08de2 0cd04de2 08000be5  ..-.......M.....
 10010 0c100be5 08201be5 0c301be5 033082e0  ..... ...0...0..
 10020 0300a0e1 00d08be2 04b09de4 1eff2fe1  ............../.
 10030 00482de9 04b08de2 28309fe5 002093e5  .H-.....(0... ..
 10040 24309fe5 003093e5 0310a0e1 0200a0e1  $0...0..........
 10050 eaffffeb 0030a0e3 0300a0e1 04d04be2  .....0........K.
 10060 0048bde8 1eff2fe1 00000800 04000800  .H..../.........
Contents of section .data:
 80000 0a000000 14000000                    ........
Contents of section .comment:
 0000 4743433a 2028474e 5520546f 6f6c7320  GCC: (GNU Tools
 0010 666f7220 41726d20 456d6265 64646564  for Arm Embedded
 0020 2050726f 63657373 6f727320 372d3230   Processors 7-20
 0030 31382d71 322d7570 64617465 2920372e  18-q2-update) 7.
 0040 332e3120 32303138 30363232 20287265  3.1 20180622 (re
 0050 6c656173 6529205b 41524d2f 656d6265  lease) [ARM/embe
 0060 64646564 2d372d62 72616e63 68207265  dded-7-branch re
 0070 76697369 6f6e2032 36313930 375d00    vision 261907].
Contents of section .ARM.attributes:
 0000 412f0000 00616561 62690001 25000000  A/...aeabi..%...
 0010 0541524d 3754444d 49000602 08010901  .ARM7TDMI.......
 0020 12041401 15011703 18011901 1a011e06  ................

Disassembly of section .text:

00010000 <add>:
   10000:       e52db004        push    {fp}            ; (str fp, [sp, #-4]!)
   10004:       e28db000        add     fp, sp, #0
   10008:       e24dd00c        sub     sp, sp, #12
   1000c:       e50b0008        str     r0, [fp, #-8]
   10010:       e50b100c        str     r1, [fp, #-12]
   10014:       e51b2008        ldr     r2, [fp, #-8]
   10018:       e51b300c        ldr     r3, [fp, #-12]
   1001c:       e0823003        add     r3, r2, r3
   10020:       e1a00003        mov     r0, r3
   10024:       e28bd000        add     sp, fp, #0
   10028:       e49db004        pop     {fp}            ; (ldr fp, [sp], #4)
   1002c:       e12fff1e        bx      lr

00010030 <main>:
   10030:       e92d4800        push    {fp, lr}
   10034:       e28db004        add     fp, sp, #4
   10038:       e59f3028        ldr     r3, [pc, #40]   ; 10068 <main+0x38>
   1003c:       e5932000        ldr     r2, [r3]
   10040:       e59f3024        ldr     r3, [pc, #36]   ; 1006c <main+0x3c>
   10044:       e5933000        ldr     r3, [r3]
   10048:       e1a01003        mov     r1, r3
   1004c:       e1a00002        mov     r0, r2
   10050:       ebffffea        bl      10000 <add>
   10054:       e3a03000        mov     r3, #0
   10058:       e1a00003        mov     r0, r3
   1005c:       e24bd004        sub     sp, fp, #4
   10060:       e8bd4800        pop     {fp, lr}
   10064:       e12fff1e        bx      lr
   10068:       00080000        .word   0x00080000
   1006c:       00080004        .word   0x00080004

观察到如下两点

1、原先 2c 行 bl 0位置被连接器替换为了bl 10000。而0x10000刚好是add的代码地址
2、全局变量的地址,由函数首地址+0x38 和 函数首地址+0x3c获取,显然再这个例子函数首地址是0x10030,也就是到0x10068和0x1006c两个地址中获值。看到链接之后再0x10068和0x1006c这两个地址上放了存放数据的地址0x80000和0x80004。这个刚好和我们的链接脚本数据存放的位置符合。我们链接脚本中把数据放在了0x80000的位置

参考链接:ld - 链接脚本学习笔记与实践过程

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

链接脚本ld 的相关文章

  • C++ Mutable

    1 mutable 含义及常规使用 mutable 英文中表示 xff0c 易变的 xff0c 不定的 xff1b 性情不定的 xff0c 而在代码中表示 可变数据成员 由前面整理的 const详解 知道 xff0c 由const修饰的成员
  • 牛吃草问题

    1 概述 最近碰到一个面试题 xff0c 讲的是牛吃草的问题 xff0c 当时时间短 xff0c 脑袋出现了短路 xff0c 没有给出答案 回来特意查了一下答案 xff0c 发现了一篇比较好的文章 xff0c 现在重新抄写一份 xff0c
  • 开始记录学习中的点滴

    随着年龄的增长 xff0c 除了去了很多地方之外 xff0c 感觉个人没有特别明显的成长 xff0c 对于未来充满了更多的迷茫与困惑 对于程序员的我来说更是感觉到了自己的瓶颈 xff0c 知识储备没有增加多少 xff0c 随着时间的流逝 x
  • C++中Struct与Class的区别与比较

    概述 之前只知道在C 43 43 中类和结构体的区别只有默认的防控属性 xff08 访问控制 xff09 不同 xff0c struct是public的 xff0c 而class是private的 但经过上网查资料才发现 xff0c 除了这
  • 函数调用约定的详解

    概述 在工作的过程中 xff0c 我们总是需要调用底层函数或者使用第三方的库 xff0c 在使用的过程中我就发现了有一些函数前面总有一些 stdcall xff0c 之初我只知道那是调用约定 xff0c 但别人问我什么是调用约定 xff0c
  • #pragma的常用方法讲解

    概述 我们在写代码时 xff0c 总会遇到头文件多次包含的情况 xff0c 刚开始时我们使用宏定义进行控制 xff0c 之后发现有 pragma once这样简单的东西 xff0c 当时是很兴奋 xff0c 以为 pragma就这一种用法
  • C++数组的详细解析

    概述 数组在写程序时经常用到 xff0c 但是对于它和指针的关系 xff0c 自己经常搞混 xff0c 所有抽点时间对数组进行整理 1 数组的概念和使用 数组是用来存储相同类型的变量的顺序集合 所有的数组都是由连续的内存位置组成 最低的地址
  • 华为荣耀9升降级系统 | 华为荣耀9变砖后如何救砖 | 华为荣耀9获取BL解锁码以及如何解BL锁 | 华为荣耀9如何通过写ramdisk.img来获取root

    文章目录 1 按2 通过官方华为手机助手升降级以及修复系统和安装驱动3 使用百分之五模式刷高维禁用包355来安装指定的系统版本8 0 0 3554 故意 xff08 或意外 xff09 刷错包把手机变砖5 使用救砖模式刷高维禁用包355来安
  • C++指针详解

    概述 C C 43 43 语言之所以强大 xff0c 以及其自由性 xff0c 很大部分体现在其灵活的指针运用上 因此 xff0c 说指针是C C 43 43 语言的灵魂一点都不为过 有好的一面 xff0c 必然会有坏的一面 xff0c 指
  • C++ lambda表达式及其原理

    概述 C 43 43 11中引入了新的lamdba表达式 xff0c 使用也很简单 xff0c 我最喜欢的是不用给函数取名称 xff0c 每次给函数取名称都感觉自己读书太少 1 lambda表达式 lambda表达式可以理解为一个匿名的内联
  • GIT 修改用户名和密码

    1 概述 如果你使用GIT的SSH 方式连接远端 xff0c 并且设置了一个没有口令的秘钥 xff0c 这样就可以砸不输入用户名和密码的情况下安全地传输数据 然而 xff0c 这对 HTTP 协议来说是不可能的 每一个连接都是需要用户名和密
  • bmi055 标定_Kalibr tutorials

    Kalibr installation tutorial I was confused about installing Kalibr but there is no even one hint in README md I just pu
  • python上位机例程_python 上位机通信实例

    34 moduleinfo 34 34 card count 34 34 count phone 34 1 34 count 34 1 34 search count 34 34 count phone 34 6 34 count 34 6
  • linux post请求_Linux C++网络编程

    img 前言 要想找一份Linux c 43 43 方面的好工作 xff0c 在面试过程中游刃有余 xff0c 那么这篇文章就是为你定制的 因为作为一个校招的学生 xff0c 我在学习和面试过程中的经历总这个体系的文章 xff0c 希望可以
  • 200826-C语言打印文件中的文本内容

    1 Description 在桌面上创建一个txt文件 xff0c 输入一些文本内容 xff0c 我们的任务是把文本内容打印出来 在编程之前 xff0c 关于一些函数的定义我们需要了解下 fopen fopen的函数原型为 xff1a FI
  • matlab设置使用vs2008编译器,64位操作系统下如何将matlab与vs2008的c编译器

    在windows sever 2008 操作系统上分别装了 matlab2009 xff0c vs2008 xff0c 想把 m 文件编译成 exe 文件 xff0c 但matlab找不到c的编译器 如下 xff0c 请教如何解决 gt g
  • 用c语言实现https通信,C/C++实现HTTPS通信

    include 34 afxinet h 34 CInternetSession mysession CHttpConnection myconn CString VoidText CString strSentence strGetSen
  • iar stm32_详解STM32单片机的堆栈

    学习STM32单片机的时候 xff0c 总是能遇到 堆栈 这个概念 分享本文 xff0c 希望对你理解堆栈有帮助 对于了解一点汇编编程的人 xff0c 就可以知道 xff0c 堆栈是内存中一段连续的存储区域 xff0c 用来保存一些临时数据

随机推荐