当前位置:   article > 正文

8 链接器 自定义链接脚本,指定入口函数,指定代码段起始地址等等_链接脚本段指定位置

链接脚本段指定位置

本文学习自狄泰软件学院 唐佐林老师的 操作系统课程,本文图片来源于唐佐林老师课程PPT,只用于个人笔记学习


  • 1 链接脚本的概念和意义
  • 2 链接脚本的本质
  • 3 链接脚本的写法和注意事项
  • 4 实验1 : 自定义的链接脚本中自己指定的 代码段和数据段的地址没有遵循linux平台对应用程序的规定
  • 5 实验2 :链接脚本中指定全局变量地址
  • 6 实验3 :在链接脚本中定义标识符,并且在源码中使用
  • 7 Memory 命令 : 桌面环境的链接方式 VS 嵌入式环境的链接方式
  • 8 实验4 通过链接脚本指定应用程序的入口函数

在这里插入图片描述

在这里插入图片描述

在这里插入图片描述

在这里插入图片描述

在这里插入图片描述

实验1 : 自定义的链接脚本中自己指定的 代码段和数据段的地址没有遵循linux平台对应用程序的规定。

test.c

#include <stdio.h>

int s1;

int main()
{
    printf("&s1 = %p\n", &s1);
    
    return 0;
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10

test.lds

SECTIONS
{
    .text 0x3000000:
    {
        *(.text)
    }
    
    .data 0x4000000:
    {
        *(.data)
    }
    
    .bss :
    {
        *(.bss)
    }
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17

以默认的方式进行编译,然后运行:

mhr@ubuntu:~/work$ gcc -o test.out test.c
mhr@ubuntu:~/work$ ./test.out 
&s1 = 0x60103c
mhr@ubuntu:~/work$ 
  • 1
  • 2
  • 3
  • 4

使用自定义链接脚本进行编译

在这里插入图片描述

使用链接脚本编译运行后提示段错误,因为我们自定义的链接脚本中自己指定的 代码段和数据段的地址没有遵循linux平台对应用程序的规定。


实验2 :链接脚本中指定全局变量地址

test.c

#include <stdio.h>

int s1;

int main()
{
    printf("&s1 = %p\n", &s1);
    
    return 0;
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10

test.lds

SECTIONS
{
    .text 0x08048400:  说明:符合平台规定
    {
        *(.text)
    }
    
    . = 0x01000000;  说明:将当前位置指针 . 的值改变为 0x01000000
    
    s1 = .;  显示的重定位 s1这个标识符,即s1就是 0x01000000 地址的别名,即s1这个全局变量的地址位于 0x01000000
    
    .data 0x0804a800:  说明:符合平台规定
    {
        *(.data)
    }
    
    .bss :  
    {
        *(.bss)
    }
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21

使用自定义链接脚本编译并且运行

mhr@ubuntu:~/work$ gcc -o test-lds.out test.c test.lds
mhr@ubuntu:~/work$ ./test-lds.out 
&s1 = 0x1000000  
mhr@ubuntu:~/work$ 
  • 1
  • 2
  • 3
  • 4

果然s1这个全局变量的地址就是链接脚本中指定的 地址 0x1000000


实验3 :在链接脚本中定义标识符,,并且在源码中使用

test.c

#include <stdio.h>

int s1;
extern int s2;//使用标识符s2  在链接脚本中定义

int main()
{
    printf("&s1 = %p\n", &s1);
    printf("&s2 = %p\n", &s2);
    
    return 0;
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12

test.lds

SECTIONS
{
    .text 0x08048400:
    {
        *(.text)
    }
    
    . = 0x01000000;
    
    s1 = .;
    
    . += 4;  重新指定当前位置指针.的值
    
    s2 = .;  用改变后的当前位置指针的值来重定位s2这个标识符,即s2是 0x1000004地址的别名
    
    .data 0x0804a800:
    {
        *(.data)
    }
    
    .bss :
    {
        *(.bss)
    }
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25

使用自定义链接脚本编译并且运行

mhr@ubuntu:~/work$ 
mhr@ubuntu:~/work$ gcc -o test-lds.out test.c test.lds 
mhr@ubuntu:~/work$ ./test-lds.out 
&s1 = 0x1000000
&s2 = 0x1000004
mhr@ubuntu:~/work$ 
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6

在这里插入图片描述

自从有了MMU内存管理单元之后,编译,链接的时候所面的都是虚存地址,具体的存储区域在内存的什么地方是由mmu决定的,所以链接器就认为这些事情全部由mmu做就可以了,自己在链接的时候只需要给一个合法的重定位地址就可以了。虚存地址,就是逻辑上的一个非常大的存储空间,在桌面应用中,链接器这个认为大多数是对的,但是对于嵌入式环境而言,就有可能不存在mmu,直接基于物理存储空间开发,此时如果存在多个存储空间…

在这里插入图片描述
嵌入式环境的链接方式,在链接脚本中,通过memory 指令 指定 代码段放在只读属性的flash中直接运行,数据段放在Ram中。
在这里插入图片描述

在这里插入图片描述


通过链接脚本指定应用程序的入口函数
在这里插入图片描述

实验4 :通过链接脚本指定应用程序的入口函数

test.c

#include <stdio.h>
#include <stdlib.h>

int program()
{
    printf("D.T.Software\n");
    
    exit(0);
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9

test.lds : 链接器根据平台规范来确认其他段的信息,此处之编写代码段的信息,并且显示的重定位代码段到地址 0x08048400

ENTRY(program)

SECTIONS
{
    .text 0x08048400:
    {
        *(.text)
    }
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9

编译链接运行

mhr@ubuntu:~/work$ 
mhr@ubuntu:~/work$ gcc -o test.o -c  test.c
mhr@ubuntu:~/work$ 
mhr@ubuntu:~/work$ gcc -nostartfiles test.o -o test-lds.out test.lds
mhr@ubuntu:~/work$ ./test-lds.out
D.T.Software
mhr@ubuntu:~/work$ 


mhr@ubuntu:~/work$ 
mhr@ubuntu:~/work$ nm test-lds.out 
0000000008249028 D __bss_start
0000000008248ec0 d _DYNAMIC
0000000008249028 D _edata
0000000008249028 D _end
                 U exit@@GLIBC_2.2.5
0000000008249000 d _GLOBAL_OFFSET_TABLE_
0000000008048428 r __GNU_EH_FRAME_HDR
0000000008048400 T program   //program   函数的地址 0000000008048400 
                 U puts@@GLIBC_2.2.5
                 U _start
mhr@ubuntu:~/work$ 


mhr@ubuntu:~/work$ 
mhr@ubuntu:~/work$ objdump -h test-lds.out 

test-lds.out:     file format elf64-x86-64

Sections:
Idx Name          Size      VMA               LMA               File off  Algn
 ...
//所以 grogram确实被指定成了 代码段的入口函数
  9 .text         00000018  0000000008048400  0000000008048400  00048400  2**0
                  CONTENTS, ALLOC, LOAD, READONLY, CODE
...
mhr@ubuntu:~/work$ mhr@ubuntu:~/work$ 
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36
  • 37

在这里插入图片描述

声明:本文内容由网友自发贡献,不代表【wpsshop博客】立场,版权归原作者所有,本站不承担相应法律责任。如您发现有侵权的内容,请联系我们。转载请注明出处:https://www.wpsshop.cn/w/不正经/article/detail/346597
推荐阅读
相关标签
  

闽ICP备14008679号