精华内容
下载资源
问答
  • 1. 的概念 转载:https://blog.csdn.net/qq_38176439/article/details/69220124  我们注意到,“地址”这个名称中包含着“”的概念。这种说法可能对一些学习者产生了误导,使人误以为内存被划分成一...

    1. 段的概念

    转载:https://blog.csdn.net/qq_38176439/article/details/69220124

     我们注意到,“段地址”这个名称中包含着“”的概念。这种说法可能对一些学习者产生了误导,使人误以为内存被划分成一个一个的段,每一个段都有一个地址。如果我们在一开始形成了这种认知,将影响以后对汇编语言的深入理解和灵活应用。

     

        其实,内存并没有分段,段的划分来自于CPU。由于8086CPU用“基础地址(段地址×16)+偏移地址=物理地址”的方式给出内存单元的物理地址,使得我们可以用分段的方式来管理内存

     

     如下图所示,我们可以认为:地址10000H~100FFH的内存单元组成一个段,该段的起始地址(基础地址)为10000H,段地址为1000H,大小为100H;我们也可以认为地址10000H~1007F、10080H~100FHH的内存单元组成两个段,它们的起始地址(基础地址)为:10000H和10080H,段地址为:1000H和1008H,大小都为80H。


    分段

     

        以后,在编程时可以根据需要,将若干个地址连续的内存单元看做一个段,用段地址×16定位段的起始地址(基础地址),用偏移地址定位段中的内存单元

     

        有两点需要注意:段地址×16必然是16的倍数,所以一个段的起始地址也一定是16的倍数;偏移地址为16位,16位的寻址能力为64KB,所以一个段的长度最大为64KB。

     

    内存单元地址小结

     

        CPU访问内存单元时,必须向内存提供内存单元的物理地址。8086CPU在内部用段地址和偏移地址移位相加的方法形成最终的物理地址。

     

        思考下面的两个问题。

     

        (1)观察下面的地址,你有什么发现?

     

        

    物理地址

    段地址

    偏移地址

    21F60H

    2000H

    1F60

     

    2100H

    0F60

     

    21F0H

    0060H

     

    21F6H

    0000H

     

    1F00H

    2F60H

     

        结论:CPU可以用不同的段地址和偏移地址形成同一个物理地址

     

     比如CPU要访问21F60H单元,则它给出的段地址SA和偏移地址EA满足SA×16+EA=21F60H即可。

     

        (2)如果给定一个段地址,仅通过变化偏移地址来进行寻址,最多可以定位多少个内存单元?

     

     结论:偏移地址16位,变化范围为0~FFFFH,仅用偏移地址来寻址最多可以寻64KB个内存单元。

     

     比如给定段地址1000H,用偏移地址寻址,CPU的寻址范围为:10000H~1FFFFH。

     

     在8086PC机中,存储单元的地址用两个元素来描述,即段地址和偏移地址。

     

        “数据在21F60H内存单元中。”这句话对于8086PC机一般不这样讲,取而代之的是两种类似的说法:①数据存在内存2000:1F60单元中;②数据存在内存的20000H段中的1F60H单元中。这两种描述都表示“数据在内存21F60H单元中”。

     

        可以根据需要,将地址连续、起始地址为16的倍数的一组内存单元定义为一个段。

     

        问:什么是段地址?

        答:段地址是针对内存的分段而言的,将每一段的段首地址定义为段地址。段地址的存在是由系统的分段存储决定的,通过段地址和偏移地址就能对数据进行寻访。

     

     问:什么是偏移地址?

     答:偏移地址也称为偏移量,由于8086/8088CPU内部的ALU只能进行16位的运算,而8086/8088有20条地址线,直接寻址能力1MB。因此,8086/8088所使用的20位物理地址,是由相应的段地址加上偏移地址组成的。

     

     问:为什么给定段地址1000H,用偏移地址寻址,CPU的寻址范围为:10000H~1FFFFH?

        答:把段地址1000H,乘以16,就是在1000H后面加上个0,可得到10000H。

     把10000H,加上偏移量的范围0000H~FFFFH,

     即有CPU的寻址范围:10000H~1FFFFH。

        ----------

     偏移量的范围0000H~FFFFH,就是16位二进制数的变化范围。




    2. 段寄存器

    1. CS和IP。

    CS为代码段存器,IP为指令指针寄存器。CPU将CS:IP指向的内容当作当前的指令。

    2. DS

    存放要访问的数据的段地址。8086CPU自动取ds中的数据为内存单元的段地址。同时8086CPU不支持将数据直接送入段寄存器操作。
    eg:将10000H的内容,送入al。

    • mov ax,1000
    • mov ds,ax
    • mov al,[0]

    3. SS和SP

    SS是栈的栈底,SP是栈顶元素的位置。(可能存在越界现象)
    8086CPU提供了入栈和出栈的指令push和pop。
    8086CPU的入栈和出站都以字为单位。所以POP总是加减2。
    (详细的内容可以参看:https://blog.csdn.net/apollon_krj/article/details/70550667)



    3.数据段、程序段、栈段

    • 数据段:存放数据的段。使用时候,用DS寄存器。
    • 程序段:用来存放程序的段。使用的时候,用CS和IP寄存器。
    • 栈段:是一个栈。使用时,初始设置SS和SP寄存器。

    实战操作一波:把10000H~1000FH的空间当作栈;把20000H和20002H中的数据通过栈进行对换。程序的位置在30000H ~。

    debug -a 30000
    /*首先是在程序段中写程序*/
    
    //建立栈
    mov ax,1000
    mov ss,ax
    mov sp 0010//注意
    
    //找到数据段的位置
    mov ax,2000
    mov ds,ax
    
    //兑换内存中的数据
    push [0]
    push [2]
    pop [0]
    pop [2]
    
    
    //执行程序段
    -r cs
    3000
    -r ip
    0
    
    -t//多次执行
    

    注意:实验的时候,要注意各个寄存器的变化。Debug的T命令在执行修改寄存器SS的指令的时候,下一条指令也会紧接着执行。

    展开全文
  • 全局变量或静态变量,放在数据段, 局部变量放在栈中, 用new产生的对象放在堆中, 内存分为4段,栈区,堆区,代码区,全局变量区 BSS段:BSS段(bss segment)通常是指用来存放程序中未初始化的全局变量...

    1.函数代码存放在代码段。声明的类如果从未使用,则在编译时,会优化掉,其成员函数不占代码段空间。

    全局
    变量或静态变量,放在数据段,
    局部变量放在栈中,
    用new产生的对象放在堆中,

    内存分为4段,栈区,堆区,代码区,全局变量区

    BSS段:BSS段(bss segment)通常是指用来存放程序中未初始化的全局变量的一块内存区域。
    BSS是英文Block Started by Symbol的简称。BSS段属于静态内存分配。

    2.代码段、数据段、栈是CPU级别的逻辑概念,堆是语言级别的逻辑概念

    3.还有一个常量区,其中的内容不许修改。
    常见的 char *p = "hello"; 这里面的"hello"就保存在常量区

    4.如1楼所说,把代码段、数据段,栈,堆这些并列在一起不太合适
    代码段、数据段、堆栈段,这是一个概念
    堆、栈、全局区、常量区,这是另一个概念

    5.STACK(栈)临时局部
    HEAP(堆)动态
    RW(读写)全局
    RO(只读)代码
    Char* s=”Hello,World”; S中“H”存放在内存RO中且不能修改。

    6.CPU寄存器:CPU寄存器,其实就是来控制代码段和数据段的指令及数据读取的地方,当然,CPU也有自己存放数据的地方,那就是通用寄存器里的数据寄存器,通常是EDX寄存器,C语言里有个register,就是把数据放在这个寄存器里,这样读取数据就相当的快了,因为不用去内存找,就省去了寻址和传送数据的时间开销。他还有一些寄存器是用来指示当前代码段的位置、数据段的位置、堆栈段的位置等等(注意这里存放的只是相应的代码或数据在内存中的地址,并不是实际的值,然后根据这个地址,通过地址总线和数据总线,去内存中获取相应的值),不然在执行代码的时候,指令和数据从哪取呢?呵呵。。。他里面还有标志寄存器,用来标识一些状态位,比如标识算术溢出呀等等。。。。。

    ————————————————————————————————————————————————————————————————

    内存分段(笔记) 


    在冯诺依曼的体系结构中必须有:代码段,堆栈段,数据段
    因为冯氏结构,本质就是取址,执行的过程


    编译器和系统在为变量分配是从高地址开始分配的.
    全局变量和函数参数在内存中的存储是由低地值到高地址的.
    函数参数为什么会放到堆区呢?
    这是因为我们的函数是在程序运行中进行动态的调用的.
    在函数的编译阶段根本无法确定他会调用几次,会需要多少内存.
    即使可以确定那时候就为变量分配好内存着实也是一种浪费。
    所以编译器为函数参数选择动态的分配..即在每次调用函数时才为它动态的进行分配空间.


    ####################################################


    内存分为4段,栈区,堆区,代码区,全局变量区

    BSS段:BSS段(bss segment)通常是指用来存放程序中未初始化的全局变量的一块内存区域。
    BSS是英文Block Started by Symbol的简称。BSS段属于静态内存分配。

    数据段:数据段(data segment)通常是指用来存放程序中已初始化的全局变量的一块内存区域。数据段属于静态内存分配。

    代码段:代码段(code segment/text segment)通常是指用来存放程序执行代码的一块内存区域。
    这部分区域的大小在程序运行前就已经确定,并且内存区域通常属于只读, 某些架构也允许代码段为可写,即允许修改程序。
    在代码段中,也有可能包含一些只读的常数变量,例如字符串常量等。代码段是存放了程序代码的数据,
    假如机器中有数个进程运行相同的一个程序,那么它们就可以使用同一个代码段。

    堆(heap):堆是用于存放进程运行中被动态分配的内存段,它的大小并不固定,
    可动态扩张或缩减。当进程调用malloc等函数分配内存时,新分配的内存就被动态添加到堆上(堆被扩张);
    当利用free等函数释放内存时,被释放的内存从堆中被剔除(堆被缩减)
    栈(stack):栈又称堆栈, 是用户存放程序临时创建的局部变量,
    也就是说我们函数括弧“{}”中定义的变量(但不包括static声明的变量,static意味着在数据段中存放变量)。
    除此以外,在函数被调用时,其参数也会被压入发起调用的进程栈中,并且待到调用结束后,函数的返回值也会被存放回栈中。
    由于栈的先进先出特点,所以栈特别方便用来保存/恢复调用现场。从这个意义上讲,我们可以把堆栈看成一个寄存、交换临时数据的内存区。


    (1)内存分段和内存分页一样都是一种内存管理技术,分段:权限保护,分页:虚拟内存.


    (2)分段后,程序员可以定义自己的段,各段有独立的地址空间,象进程的地址空间互相独立一样.


    (3)同一个类的实例分配在一个段中,只有该类的方法可以访问,如果其他类的方法去访问,会因为段保护而出错.可以从硬件上实现类的数据保护和隐藏

    ####################################################################

    分段好处:

    cpu中的段寄存器-------段址(base)和偏移值的上限(limit)。
    段址:有效地址 中,如果有效地址大于limit,便会引发异常。这样就可以限制程序不能范围当前段外的数据,不能访问其他程序的数据。
    面向对象的好处:对象就是一块连续的内存中的数据




    寄存器是特殊形式的内存,嵌入到处理器内部。

             每个进程需要访问内存中属于自身的区域,因此,可将内存划分成小的段,按需分发给进程。
    寄存器用来存储和跟踪进程当前维护的段。偏移寄存器(Offset Registers)用来跟踪关键的数据放在段中的位置。

           在进程被载入内存中时,基本上被分裂成许多小的节(section)。我们比较关注的是6个主要的节:

    (1) .text 节

        .text 节基本上相当于二进制可执行文件的.text部分,它包含了完成程序任务的机器指令。
    该节标记为只读,如果发生写操作,会造成segmentation fault。在进程最初被加载到内存中开始,该节的大小就被固定。

    (2).data 节

    .data节用来存储初始化过的变量,如:int a =0 ; 该节的大小在运行时固定的。

    (3).bss 节

    栈下节(below stack section ,即.bss)用来存储为初始化的变量,如:int a; 该节的大小在运行时固定的。

    (4) 堆节

    堆节(heap section)用来存储动态分配的变量,位置从内存的低地址向高地址增长。内存的分配和释放通过malloc() 和 free() 函数控制。

    (5) 栈节

    栈节(stack section)用来跟踪函数调用(可能是递归的),在大多数系统上从内存的高地址向低地址增长。
    同时,栈这种增长方式,导致了缓冲区溢出的可能性。

    (6)环境/参数节

         环境/参数节(environment/arguments section)用来存储系统环境变量的一份复制文件,
    进程在运行时可能需要。例如,运行中的进程,可以通过环境变量来访问路径、shell 名称、主机名等信息。
    该节是可写的,因此在格式串(format string)和缓冲区溢出(buffer overflow)攻击中都可以使用该节。
    另外,命令行参数也保持在该区域中。


    ################################################################################

    以win32程序为例。
    程序执行时,操作系统将exe文件映射入内存。exe文件格式为头数据和各段数据组成。

    头数据说明了exe文件的属性和执行环境,段数据又分为数据段,代码段,资源段等,段的多少和位置由头数据说明。
    也就是说,不仅仅只是代码段和数据段。这些段由不同的编译环境和编译参数控制,由编译器自动生成exe的段和文件格式。
    当操作系统执行exe时,会动态建立堆栈段,它是动态的,并且属于操作系统执行环境。

    也就是说,程序在内存的映射一个为exe文件映射,包括数据段、代码段等它是不变的。
    另一个为堆栈段,它是随程序运行动态改变的。

    1、编译器把源代码转化成分立的目标代码(.o或者.obj)文件,这些文件中的代码已经是可执行的机器码或者是中间代码。
    但是其中变量等事物的地址只是一些符号。   
    2、接下来是通过链接器处理这些目标代码,主要目的就是把分立的目标代码连接成一份完整的可执行代码,
    并将其中的地址符号换成相对地址。如果这时候产生错误,我们就可以得到一份地址符号列表,而不是变量列表。   
    3、执行程序的时候操作系统分配足够的内存空间,建立好系统支撑结构后把二进制可执行代码读入内存中。
    在读入过程中内存首址就成了程序的“绝对地址”(实际上还是相对地址,不过是操作系统里的相对地址了)。
    于是绝对地址+相对地址(就是偏移量)就得到了变量的地址。   
    因此,CS的值是由系统填入的,而其它S寄存器的值则是根据程序代码中附加的信息计算后得到的。

    展开全文
  • 程序内存空间(代码段、数据段、堆栈段)

    万次阅读 多人点赞 2016-08-24 20:55:12
    在冯诺依曼的体系结构中必须有:代码段,堆栈段,数据段。 进程的虚拟地址空间图示如下: 堆栈段:  1. 为函数内部的局部变量提供存储空间。  2. 进行函数调用时,存储“过程活动记录”。  3. 用作暂时...

    在冯诺依曼的体系结构中,一个进程必须有:代码段,堆栈段,数据段。

    进程的虚拟地址空间图示如下:


    堆栈段:

      1. 为函数内部的局部变量提供存储空间。

      2. 进行函数调用时,存储“过程活动记录”。

      3. 用作暂时存储区。如计算一个很长的算术表达式时,可以将部分计算结果压入堆栈。

    数据段(静态存储区):

      包括BSS段(Block Started by Symbol)的数据段。BSS段存储未初始化或初始化为0的全局变量、静态变量,具体体现为一个占位符,并不给该段的数据分配空间,只是记录数据所需空间的大小。数据段存储经过初始化的全局和静态变量。

    #define DEBUG "debug"  
      
    int space[1024][1024];  
    int data = 1;  
    int no_data = 0;  
      
    int main()  
    {  
      char *a = DEBUG;  
      return 1;  
    }  
      使用nm查看后
    0000000000600660 d _DYNAMIC  
    00000000006007f8 d _GLOBAL_OFFSET_TABLE_  
    0000000000400578 R _IO_stdin_used  
                     w _Jv_RegisterClasses  
    0000000000600640 d __CTOR_END__  
    0000000000600638 d __CTOR_LIST__  
    0000000000600650 D __DTOR_END__  
    0000000000600648 d __DTOR_LIST__  
    0000000000400630 r __FRAME_END__  
    0000000000600658 d __JCR_END__  
    0000000000600658 d __JCR_LIST__  
    0000000000600820 A __bss_start  
    0000000000600818 D __data_start  
    0000000000400530 t __do_global_ctors_aux  
    00000000004003e0 t __do_global_dtors_aux  
    0000000000400580 R __dso_handle  
                     w __gmon_start__  
    0000000000600634 d __init_array_end  
    0000000000600634 d __init_array_start  
    0000000000400490 T __libc_csu_fini  
    00000000004004a0 T __libc_csu_init  
                     U __libc_start_main@@GLIBC_2.2.5  
    0000000000600820 A _edata  
    0000000000a00840 A _end  
    0000000000400568 T _fini  
    0000000000400358 T _init  
    0000000000400390 T _start  
    00000000004003bc t call_gmon_start  
    0000000000600820 b completed.6347  
    000000000060081c D data  
    0000000000600818 W data_start  
    0000000000600828 b dtor_idx.6349  
    0000000000400450 t frame_dummy  
    0000000000400474 T main  
    0000000000600830 B no_data  
    0000000000600840 B space
      可以看到变量data被分配在data段,而被初始化为0的no_data被分配在了BSS段。

      .bss是不占用.exe文件空间的,其内容由操作系统初始化(清零);而.data却需要占用,其内容由程序初始化。

      注意:.data和.bss在加载时合并到一个Segment(Data Segment)中,这个Segment是可读可写的。

    代码段:

      又称为文本段。存储可执行文件的指令;也有可能包含一些只读的常数变量,例如字符串常量等。

      .rodata段:存放只读数据,比如printf语句中的格式字符串和开关语句的跳转表。也就是你所说的常量区。例如,全局作用域中的 const int ival = 10,ival存放在.rodata段;再如,函数局部作用域中的printf("Hello world %d\n", c);语句中的格式字符串"Hello world %d\n",也存放在.rodata段。

      但是注意并不是所有的常量都是放在常量数据段的,其特殊情况如下:

      1)有些立即数与指令编译在一起直接放在代码段。

    int main()  
    {  
      int a = 10;  
      return 1;  
    }  

      a是常量,但是它没有被放入常量区,而是在指令中直接通过立即数赋值

      2)对于字符串常量,编译器会去掉重复的常量,让程序的每个字符串常量只有一份。

    char *str = "123456789";  
    char *str1 = "helloworld";  
      
    int main()  
    {  
      char* a = "helloworld";  
      char b[10] = "helloworld";  
      return 1;  
    }  

      汇编代码如下:

                    .file   "hello.c"  
    .globl str  
            .section        .rodata  
    .LC0:  
            .string "123456789"  
            .data  
            .align 8  
            .type   str, @object  
            .size   str, 8  
    str:  
            .quad   .LC0  
    .globl str1  
            .section        .rodata  
    .LC1:  
            .string "helloworld"  
            .data  
            .align 8  
            .type   str1, @object  
            .size   str1, 8  
    str1:  
            .quad   .LC1  
            .text  
    .globl main  
            .type   main, @function  
    main:  
    .LFB0:  
            .cfi_startproc  
            pushq   %rbp  
            .cfi_def_cfa_offset 16  
            .cfi_offset 6, -16  
            movq    %rsp, %rbp  
            .cfi_def_cfa_register 6  
            movq    $.LC1, -8(%rbp)  
            movl    $1819043176, -32(%rbp)  
            movl    $1919907695, -28(%rbp)  
            movw    $25708, -24(%rbp)  
            movl    $1, %eax  
            leave  
            .cfi_def_cfa 7, 8  
            ret  
            .cfi_endproc  
    .LFE0:  
            .size   main, .-main  
            .ident  "GCC: (GNU) 4.4.6 20110731 (Red Hat 4.4.6-3)"  
            .section        .note.GNU-stack,"",@progbits  
      可以看到str1和a同时指向.rodata段中同一个LC1

      3)用数组初始化的字符串常量是没有放入常量区的。

      4)用const修饰的全局变量是放入常量区的,但是使用const修饰的局部变量只是设置为只读起到防止修改的效果,没有放入常量区。
      5)有些系统中rodata段是多个进程共享的,目的是为了提高空间的利用率。

      注意:程序加载运行时,.rodata段和.text段通常合并到一个Segment(Text Segment)中,操作系统将这个Segment的页面只读保护起来,防止意外的改写。

    堆:

      就像堆栈段能够根据需要自动增长一样,数据段也有一个对象,用于完成这项工作,这就是堆。堆区域是用来动态分配的内存空间,用 malloc 函数申请的,用free函数释放。calloc、realloc和malloc类似:前者返回指针的之前把分配好的内存内容都清空为零;后者改变一个指针所指向的内存块的大小,可以扩大和缩小,它经常把内存拷贝到别的地方然后将新地址返回。



    栈、堆辨析:

    1、栈区(stack):由编译器自动分配释放 ,存放函数的参数值、局部变量的值等。其操作方式类似于数据结构中的栈。 
    2、堆区(heap):由程序员分配释放, 若程序员不释放,程序结束时可能由操作系统回收 。注意它与数据结构中的堆是两回事,分配方式倒是类似于链表。 



    程序示例:

    1、举个例子说明各种变量存放在什么区: 

    #include <stdlib.h>
    
    int a=123; //a在全局已初始化数据区 
    
    char *p1; //p1在BSS区(未初始化全局变量) 
    
    int main()
    {
    	int b; //b为局部变量,在栈区 
    
    	char s[]="abc"; //s为局部数组变量,在栈区 
    			//"abc"为字符串常量,存储在已初始化数据区 
    
    	char *p1,*p2; //p1,p2为局部变量,在栈区 
    
    	char *p3="123456"; //p3在栈区,"123456"在常量区(.rodata)
    
    	static int c=456; //c为局部(静态)数据,在已初始化数据区 
    
    	//静态局部变量会自动初始化(因为BSS区自动用0或NULL初始化)
    
    	p1=(char*)malloc(10); //分配得来的10个字节的区域在堆区 
    
    	p2=(char*)malloc(20); //分配得来的20个字节的区域在堆区 
    
    	free(p1);
    
    	free(p2);
    
    	p1=NULL; //显示地将p1置为NULL,避免以后错误地使用p1
    
    	p2=NULL;
    }

    2、我们再写一个程序,输出各变量的内存空间:

    #include <stdio.h>
    #include <stdlib.h>
    
    extern void afunc(void);
    
    extern etext,edata,end;
    
    int bss_var;//未初始化全局变量存储在BSS段
    
    int data_var=42;//初始化全局存储在数据段
    
    #define SHW_ADR(ID,I) printf("The %s is at address: %8x\n",ID,&I);//打印地址宏
    
    int main(int argc,char *argv[])
    {
    	char *p,*b,*nb;
    
    	printf("etext address: %8x\tedata address: %8x\tend address: %8x\t\n",&etext,&edata,&end);
    
    	SHW_ADR("main",main);//查看代码段main函数位置
    
    	SHW_ADR("afunc",afunc);//查看代码段afunc函数位置
    
    	printf("\nbss Locatoin:\n");
    	SHW_ADR("bss_var",bss_var);//查看BSS段变量地址
    
    	printf("\ndata Location:\n");
    	SHW_ADR("data_var",data_var);//查看数据段变量地址
    
    	printf("\nStack Loation:\n");
    	afunc();
    	printf("\n");
    
    	p=(char*)alloca(32);//从栈中分配空间
    
    	if(p!=NULL)
    	{
    		SHW_ADR("string p in stack start",*p);
    		SHW_ADR("string p in stack end",*(p+32*sizeof(char)));
    	}
    
    	b=(char*)malloc(32*sizeof(char));//从堆中分配空间
    	nb=(char*)malloc(16*sizeof(char));//从堆中分配空间
    
    	printf("\nHeap Location:\n");
    	SHW_ADR("allocated heap start",*b);//已分配的堆空间的起始地址
    	SHW_ADR("allocated heap end",*(nb+16*sizeof(char)));//已分配的堆空间的结束地址
    
    	printf("\np,b and nb in stack\n");
    	SHW_ADR("p",p);//显示栈中数据p的地址
    	SHW_ADR("b",b);//显示栈中数据b的地址
    	SHW_ADR("nb",nb);//显示栈中数据nb的地址
    
    	free(b);//释放申请的空间,以避免内存泄露
    	free(nb);
    }
    
    void afunc(void)
    {
    	static int level=0;//初始化为0的静态数据存储在BSS段中
    
    	int stack_var;//局部变量,存储在栈区
    
    	if(++level==5)
    		return;
    
    	SHW_ADR("stack_var in stack section",stack_var);
    	SHW_ADR("leval in bss section",level);
    
    	afunc();
    }
    
    /* Output
    etext address:  80488bf	edata address:  8049b48	end address:  8049b58	
    The main is at address:  80485be
    The afunc is at address:  8048550
    
    bss Locatoin:
    The bss_var is at address:  8049b54
    
    data Location:
    The data_var is at address:  8049b40
    
    Stack Loation:
    The stack_var in stack section is at address: ff9cdf80
    The level in bss section is at address:  8049b50
    The stack_var in stack section is at address: ff9cdf50
    The level in bss section is at address:  8049b50
    The stack_var in stack section is at address: ff9cdf20
    The level in bss section is at address:  8049b50
    The stack_var in stack section is at address: ff9cdef0
    The level in bss section is at address:  8049b50
    
    The string p in stack start is at address: ff9cdf70
    The string p in stack end is at address: ff9cdf90
    
    Heap Location:
    The allocated heap start is at address:  9020078
    The allocated heap end is at address:  90200c8
    
    p,b and nb in stack
    The p is at address: ff9cdfac
    The b is at address: ff9cdfa8
    The nb is at address: ff9cdfa4
    */

    内存管理函数:
    这里插入一段对void*的解释:
    void*这不叫空指针,这叫无确切类型指针.这个指针指向一块内存,却没有告诉程序该用何种方式来解释这片内存.所以这种类型的指针不能直接进行取内容的操作.必须先转成别的类型的指针才可以把内容解释出来.

    还有'\0',这也不是空指针所指的内容.'\0'是表示一个字符串的结尾而已,并不是NULL的意思.

    真正的空指针是说,这个指针没有指向一块有意义的内存,比如说:
    char* k;
    这里这个k就叫空指针.我们并未让它指向任意内存.
    又或者
    char* k = NULL;
    这里这个k也叫空指针,因为它指向NULL也就是0,注意是整数0,不是'\0'.

    一个空指针我们也无法对它进行取内容操作.
    空指针只有在真正指向了一块有意义的内存后,我们才能对它取内容.也就是说要这样
    k = "hello world!";
    这时k就不是空指针了.

    void *malloc(size_t size)
    (typedef unsigned int size_t;)
    malloc在内存的动态存储区中分配一个长度为size字节的连续空间,其参数是无符号整型,返回一个指向所分配的连续空间的起始地址的指针。分配空间不成功(如内存不足)时返回一个NULL指针。

    void free(void *ptr)
    free释放掉内存空间。

    void *realloc(void *ptr,size_tsize)
    当需要扩大一块内存空间时,realloc试图直接从堆的当前内存段后面获得更多的内在空间,并返回原指针;如果空间不够就使用第一个能够满足这个要求的内存块,并将当前数据复制到新位置,释放原来的数据块;如果申请空间失败,返回NULL。

    void *calloc(size_t nmemb, size_t size)
    calloc是malloc的简单包装,它把动态分配的内存空间进行初始化,全部清0。此函数的实现描述:
    void *calloc(size_t nmemb, size_t size)
    {
        void *p;

        size_t total;
        total=nmemb*size;

        p=malloc(total);
        if(p!=NULL)//申请空间

            memset(p,'\0',total);//初始化\0


        return p;
    }

    void *alloca(size_t size);
    alloca在栈中分配size个内存空间(函数返回时自动释放掉空间,无需程序员手动释放),并将空间初始化为0。


    Reference:

    https://en.wikipedia.org/wiki/Data_segment

    展开全文
  • 数据段、代码段、BSS段、堆栈段

    万次阅读 2018-05-15 13:44:11
    进程(执行的程序)会占用一定数量的内存,它...对任何一个普通进程来讲,它都会涉及到5种不同的数据段。Linux进程的五个段下面我们来简单归纳一下进程对应的内存空间中所包含的5种不同的数据区都是干什么的。BSS...

     进程(执行的程序)会占用一定数量的内存,它或是用来存放从磁盘载入的程序代码,或是存放取自用户输入的数据等等。不过进程对这些内存的管理方式因内存用 途 不一而不尽相同,有些内存是事先静态分配和统一回收的,而有些却是按需要动态分配和回收的。对任何一个普通进程来讲,它都会涉及到5种不同的数据段。

    Linux进程的五个段

    下面我们来简单归纳一下进程对应的内存空间中所包含的5种不同的数据区都是干什么的。

    BSS段:BSS段(bss segment)通常是指用来存放程序中未初始化的全局变量的一块内存区域。BSS是英文Block Started by Symbol的简称。BSS段属于静态内存分配。

    数据段:数据段(data segment)通常是指用来存放程序中已初始化的全局变量的一块内存区域。数据段属于静态内存分配。

    代码段:代码段(code segment/text segment)通常是指用来存放程序执行代码的一块内存区域。这部分区域的大小在程序运行前就已经确定,并且内存区域通常属于只读, 某些架构也允许代码段为可写,即允许修改程序。在代码段中,也有可能包含一些只读的常数变量,例如字符串常量等。

    堆(heap):堆是用于存放进程运行中被动态分配的内存段,它的大小并不固定,可动态扩张或缩减。当进程调用malloc等函数分配内存时,新分配的内存就被动态添加到堆上(堆被扩张);当利用free等函数释放内存时,被释放的内存从堆中被剔除(堆被缩减)若程序员不释放,则会有内存泄漏,系统会不稳定,Windows系统在该进程退出时OS释放,Linux则只在整个系统关闭时OS才去释放(参考Linux内存管理)。

    栈(stack)栈又称堆栈, 是用户存放程序临时创建的局部变量,也就是说我们函数括弧“{}”中定义的变量(但不包括static声明的变量,static意味着在数据段中存放变 量)。除此以外,在函数被调用时,其参数也会被压入发起调用的进程栈中,并且待到调用结束后,函数的返回值也会被存放回栈中。由于栈的先进先出特点,所以 栈特别方便用来保存/恢复调用现场。从这个意义上讲,我们可以把堆栈看成一个寄存、交换临时数据的内存区。

    它是由操作系统分配的,内存的申请与回收都由OS管理。

    PS:

    全局的未初始化变量存在于.bss段中,具体体现为一个占位符;全局的已初始化变量存 于.data段中;而函数内的自动变量都在栈上分配空间。.bss是不占用.exe文件空间的,其内容由操作系统初始化(清零);而.data却需要占 用,其内容由程序初始化,因此造成了上述情况。

    bss段(未手动初始化的数据)并不给该段的数据分配空间,只是记录数据所需空间的大小。

    data(已手动初始化的数据)段则为数据分配空间,数据保存在目标文件中。 数据段包含经过初始化的全局变量以及它们的值。BSS段的大小从可执行文件中得到 ,然后链接器得到这个大小的内存块,紧跟在数据段后面。当这个内存区进入程序的地址空间后全部清零。包含数据段和BSS段的整个区段此时通常称为数据区



    展开全文
  • TCP数据段格式

    千次阅读 2017-05-18 17:28:23
    摘自:《深入理解计算机网络》 王达著 机械工业出版社 相关知识链接 1. IPV4数据报头部格式 2. IPv6数据报头部格式 3. IPv4数据报的封装与解封装 ...9. TCP的主要特性TCP数据段格式前面讲过,TCP的协议
  • 代码段/数据段/堆栈段

    千次阅读 2018-10-21 20:05:19
    BSS段:BSS段(bss segment)通常是指用来存放程序中未初始化的...数据段数据段(data segment)通常是指用来存放程序中已初始化的全局变量的一块内存区域。  数据段属于静态内存分配(rodata(只读数据段))。...
  • 同类学习笔记总结: (一)、8086汇编学习之基础...我们主要分析一下在单个的程序与多个的程序中,每个寄存器的值是如何安排的,的位置关系,内存大小等问题。一、只有一个的程序:程序实例: 利用栈将程
  • 数据帧、数据包、数据报以及数据段 OSI参考模型的各层传输的数据和控制信息具有多种格式,常用的信息格式包括帧、数据包、数据报、段、消息、元素和数据单元。  信息交换发生在对等OSI层之间,在源端机中每一层把...
  • 在百度里面看到这样一个...汇编中把数据段和代码段定义在同一段内有好处么? 悬赏分:10 -解决时间:2009-11-12 14:58 在汇编语言,把代码段和数据段放在同一段内,在伪指令 定义变量时位置有何要求么? 放在S
  • 5个数据段  进程(执行的程序)会占用一定数量的内存,它或是用来存放从磁盘载入的程序代码,或是存放取自用户输入的数据等等。不过进程对这些内存的管理方式因内存用途 不一而不尽相同,有些内存是事先静态分配...
  • BSS段:BSS段(bss segment)通常...数据段数据段(data segment)通常是指用来存放程序中已初始化的全局变量的一块内存区域。数据段属于静态内存分配。 代码段:代码段(code segment/text segment)通常是指用...
  • 数据段和只读数据段

    千次阅读 2015-06-18 20:54:31
    3.3.2 数据段和只读数据段 .data段保存的是那些已经初始化了的全局静态变量和局部静态变量。前面的SimpleSection.c代码里面一共有两个这样的变量,分别是global_init_varabal与static_var。这两个变量每个4个...
  • 数据段、数据报、数据包、帧的区别与联系

    万次阅读 多人点赞 2018-08-14 13:49:54
    数据包,就是从最上层,一层一层封装,直到网络层的,最后借由数据链路层发送出去的数据单元。 帧,是数据链路层的传输单元。 这么一看,数据包和帧好像没什么不一样,好像数据传递的都是一样的。可是为什么会把...
  •  一 预备知识在区分一个程序的堆栈、bss、text、RO、RW、ZI等概念时,首先区分一下程序进程和程序文件,然后了解一下哈弗结构和冯诺依曼结构。 程序进程就是程序运行时的程序,程序文件是编译后生成的可执行文件...
  • 数据帧、数据包、数据报以及数据段

    万次阅读 多人点赞 2016-09-11 20:04:59
    数据帧、数据包、数据报以及数据段  OSI参考模型的各层传输的数据和控制信息具有多种格式,常用的信息格式包括帧、数据包、数据报、段、消息、元素和数据单元。   信息交换发生在对等OSI层之间,在源...
  • 首先看一代码: 1 #include 2 3 int glob_val; //global uninitialized 4 int glob_val2 = 2; //global initialized 5 //int glob_val5 = 4; 6 //int glob_val6 = 4; 7 static in
  • 汇编语言代码段和数据段

    千次阅读 2017-12-17 11:32:59
    在8086cpu环境下,一个地址和一个内存单元就对应着一个B,代码段指的是长度为小于64kb的、地址连续、起始地址为16(十进制)的倍数的内存单元当作专门存放代码的,数据段指的是长度小于64kb的、地址连续、起始地址为...
  • 一、描述符的分类 在上一篇博文中已经说过,为了使用,我们必须要创建描述符。80X86中有各种各样的描述符,下图展示了它们的分类。 看了上图,你也许会说:天啊,怎么这么多描述符啊!我可怎么记住呢...
  • BR DB ‘Hello’,68,-20,3 DUP(4) -20是什么意思,在寄存器中存的内容是EC
  • 汇编语言数据段查找ASCII码并回显

    千次阅读 2017-08-29 20:25:58
    实验要求:在数据段预先存放16个十六进制的ASCII码,首地址为ASC。从键盘输入一位十六进制数到BX,用ASC[BX](寄存器相对寻址)寻址方式找到对应数位的ASCII码,并取出显示。汇编代码片段:data segment asc db '0'...
  • TCP数据段格式+UDP数据段格式详解

    万次阅读 2015-07-25 16:59:03
    要想对TCP有着较为详细的...TCP数据包可分为TCP包头和来自应用层的数据两部分 TCP格式 中间的标志位就是用于协议的一些机制的实现的比特位大家可以看到有6比特,它们依次如下:  URG、ACK、PSH、RST、SYN、FIN。
  • data segment mess db 'computer software $' data ends exit segment buff db 19dup(?) exit ends code segment assume ds:data,es:exit,cs:code start: mov ax,data mov ds,ax ...mov es,ax
  • 该算法实现对列表中大于某个阈值(比如level=5)的连续数据段的提取,具体效果如下: 找出list里面大于5的连续数据段: list = [1,2,3,4,2,3,4,5,6,7,4,6,7,8,5,6,7,3,2,4,4,4,5,3,6,7,8,9,8,6,1] 输出: [[6, 7...
  • 代码段 数据段 附加段 堆栈段

    千次阅读 2014-04-15 23:01:47
    程序员在编写汇编程序时会将存储器分段 ...数据段用来保存程序所用的数据,段地址存放在DS中 附加段ES配合DI主要用来进行字符串的操作 堆栈段SS和SP BP 配合对堆栈进行操作
  • 一、内存基本构成 ...它主要存放静态数据、全局数据和常量。  栈区:在执行函数时,函数内局部变量的存储单元都可以在栈上创建,函数执行结束时这些存储单元自动被释放。栈内存分配运算内置于处理器的
  • 数据段的第一个四字节 (DWORD) 包含状态代码。 解决方法:修改注册表禁用PerfNet性能计数器。具体方法:打开注册表,在HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Services\PerfNet\Performance\下添加DWORD(32...
  • 在Linux进程地址空间布局中,从物理上,数据(user data, sys data) 和指令,都是“数据”,但是从逻辑上来讲,来是有区别的...从逻辑层面(操作系统)把数据分成不同的(不同的区域)来存储: 一、代码(codesegmen...

空空如也

空空如也

1 2 3 4 5 ... 20
收藏数 3,325,988
精华内容 1,330,395
关键字:

数据段