Linux:符号和符号表

文章目录

  • 什么是符号?
  • 什么是符号表?
  • 全局符号和本地符号
    • 1. 全局符号:
      • symtab符号表
    • 2. 本地符号:
  • 符号在汇编阶段
  • 符号在链接阶段
    • 1.由模块 m 定义并能被其他模块引用的全局符号。
    • 2.由其他模块定义并被模块 m 引用的全局符号。
    • 3.只被模块 m 定义和引用的局部符号。
      • static 本地变量
  • QA:
    • 编译器和汇编器的区别?
    • 编译器包含汇编器吗?

什么是符号?

想象一下你在学校里,老师在黑板上写了一些字母和数字,比如"A"、“B”、“1”、“2”。这些字母和数字就是符号。在计算机编程或数学中,符号就是用来代表某个特定概念或值的标记。

举个例子,假设你写了一个计算机程序,里面有一个变量叫做"score",用来表示游戏中的分数。在这里,"score"就是一个符号,它代表了一个特定的值,即分数。

符号可以是字母、数字或其他字符的组合,它们被赋予特定的含义,让程序员或计算机能够理解并操作这些符号代表的信息。所以,通俗地说,符号就是一种用来代表东西的标记,让计算机或人能够更方便地理解和处理信息。

什么是符号表?

想象一下你在读一本书,遇到一个生词,你可能会查字典来找到这个词的解释和意义。符号表就有点像是一本程序的字典,但是不是用来解释生词的,而是用来解释程序中用到的各种符号、变量、函数等等。

在计算机程序中,我们使用各种符号(比如变量名、函数名)来表示不同的东西,就像字典中的单词一样。符号表就记录了这些符号对应的信息,比如变量的数据类型、函数的参数类型、以及它们在内存中的位置等等。

当计算机执行程序时,会根据符号表中的信息来理解和处理这些符号,就像你在阅读一本书时根据字典来理解生词一样。符号表有助于编程语言的解释器或编译器理解程序的结构和含义,使得计算机能够正确地执行你写的代码。

全局符号和本地符号

在编程中,有两种主要类型的符号:全局符号和本地符号。全局符号是在整个程序中都可见的,而本地符号仅在特定的作用域内可见。在链接器的上下文中,我们通常将这些符号称为外部符号和本地符号。

1. 全局符号:

  • 全局变量和函数是一种全局符号。它们可以在不同的文件中定义,并在整个程序中共享。
  • 链接器对全局符号感兴趣,因为它们需要在不同的目标文件之间解析引用关系,确保这些全局符号的定义能够正确地链接在一起。

symtab符号表

symtab 是符号表(Symbol Table)的缩写,用于存储程序中变量、函数和其他符号信息的数据结构。

关于 .symtab 中的符号表,它主要包含与全局符号相关的信息,因为链接器主要负责解决全局符号之间的引用关系。

本地符号,特别是本地非静态程序变量,通常不包含在符号表中,因为它们在运行时通过栈进行管理,链接器不需要关心这些细节。

这种分离全局和本地符号的处理方式有助于提高链接器的效率,并确保在链接阶段解决全局符号的引用关系时不会受到本地符号的干扰。

认识到本地链接器符号和本地程序变量不同是很重要的。
.symtab 中的符号表不包含对应于本地非静态程序变量的任何符号。这些符号在运行时在栈中被管理,链接器对此类符号不感兴趣。

.symtab 节中包含 ELF 符号表。这张符号表包含一个条目的数组。图 7-4 展示了每个条目的格式。
在这里插入图片描述
name是字符串表中的字节偏移,指向符号的以null结尾的字符串名字。

value 是符号的地址。对于可重定位的模块来说,value 是距定义目标的节的起始位置的偏移。对于可执行目标文件来说,该值是一个绝对运行时地址。

size 是目标的大小(以字节为单位)。

type 通常要么是数据,要么是函数。符号表还可以包含各个节的条目,以及对应原始源文件的路径名的条目。所以这些目标的类型也有所不同。

binding 字段表示符号是本地的还是全局的。

2. 本地符号:

  • 本地变量和本地函数是一种本地符号。它们通常只在定义它们的特定代码块(如函数)内部可见。
  • 链接器对本地符号不感兴趣,因为它们不需要在不同的目标文件之间解析引用关系。本地符号的生命周期通常限定在其定义的作用域内,例如在函数的栈帧中。

符号在汇编阶段

编译器在处理源代码时,会将源代码转换为汇编语言代码,然后将汇编语言代码输出到.s文件中。在输出的.s文件中,编译器还会将源代码中所有的函数、变量和常量等符号标记,并生成一个符号表,包含了这些符号的信息,如位置、大小等。

这些符号将在后续的汇编和链接过程中起到重要的作用,比如在汇编过程中,汇编器会根据符号表中所包含的信息来解析和生成目标二进制代码。

汇编器的作用主要有以下几个方面:

  1. 将汇编语言代码转换为机器语言代码:汇编器通过读取汇编代码源文件并将其转换为机器语言代码,创建目标文件,这个文件包含二进制代码和其他与代码相关的元信息。

  2. 符号解析:汇编器通过符号表解析代码中出现的符号,如函数和变量,以便能够正确地连接和重定位代码。

  3. 代码调试:汇编器生成的目标文件中包含了关于代码的调试信息,可以被调试器用来调试代码。

  4. 优化代码:汇编器可以通过优化代码来提高代码的执行效率,例如,通过使用更快的指令集或者重排指令的执行顺序。

符号在链接阶段

每个可重定位目标模块,我们姑且命名一个目标模块为m。

那么,模块m都有一个符号表,它包含模块m 定义和引用的符号的信息。

在链接器的上下文中,有三种不同的符号:

1.由模块 m 定义并能被其他模块引用的全局符号。

全局链接器符号对应于非静态的 C函数和全局变量。

2.由其他模块定义并被模块 m 引用的全局符号。

这些符号称为外部符号,对应于在其他模块中定义的非静态 C 函数和全局变量。

3.只被模块 m 定义和引用的局部符号。

它们对应于带 static 属性的 C函数和全局变量。这些符号在模块 m 中任何位置都可见,但是不能被其他模块引用。

static 本地变量

有趣的是,定义为带有 C static 属性的本地过程变量是不在栈中管理的。

相反,编译器在.data或bss 中为每个定义分配空间,并在符号表中创建一个有唯一名字的本地链接器符号。

比如,假设在同一模块中的两个函数各自定义了一个静态局部变量 x:

下面是一个示例代码,展示了在同一模块中的两个函数各自定义了一个静态局部变量 x,并且这些变量在.data或bss段中分配空间,而不是在栈中管理:

#include <stdio.h>void function1() {static int x = 1;printf("Function 1: x = %d\n", x);x++;
}void function2() {static int x = 10;printf("Function 2: x = %d\n", x);x--;
}int main() {function1();function1();function2();function2();function1();return 0;
}

输出结果:

Function 1: x = 1
Function 1: x = 2
Function 2: x = 10
Function 2: x = 9
Function 1: x = 3

可以看到,每个函数的静态局部变量都保留了它们的状态,并且它们在每个函数调用之间都保留了它们的值。这是因为它们在.data或bss段中分配了空间,而不是在栈中管理。

注意:
利用 static 属性隐藏变量和函数名字: C程序员使用 static属性隐藏模块内部的变量和函数声明,就像你在Java 和C++中使用
public和 private 声明一样。

在C中,源文件扮演模块的角色。任何带有static属性声明的全局变量或者函数都是模块私有的。类似地,任何不带 static
属性声明的全局变量和函数都是公共的,可以被其他模块访问。尽可能用 static 属性来保护你的变量和函数是很好的编程习惯。

QA:

编译器和汇编器的区别?

编译器和汇编器都是程序开发中使用的工具,但它们的功能不同,具体区别如下:

  1. 编译器和汇编器的语言级别不同。编译器通常用来将高级语言(如C、C++、Java等)转换为汇编语言或者机器语言,而汇编器是把汇编语言转换为机器语言。

  2. 编译器和汇编器的输入和输出不同。编译器的输入是高级语言源代码,输出是汇编语言或者机器语言代码;而汇编器的输入是汇编语言代码,输出是机器语言代码。

  3. 编译器和汇编器的编译过程不同。编译器会对源代码进行词法分析、语法分析、优化和生成目标代码等多个阶段的处理,而汇编器只是简单地将汇编语言代码翻译成机器语言代码。

  4. 编译器和汇编器的处理粒度不同。编译器处理的粒度更大,它会对整个程序进行处理,包括程序中的所有函数、变量和常量等;而汇编器处理的粒度更小,它只是针对单个汇编模块进行处理。

编译器包含汇编器吗?

在一些编译器中,汇编器的功能是由编译器自身来实现的,这些编译器被称为“集成编译器”或“自包含编译器”(self-contained compiler)。这种编译器可以直接将高级语言源代码转化成目标机器的机器语言代码,而不需要借助其他汇编器的支持。

但也有一些编译器是不包含汇编器的。在这种情况下,编译器只负责将高级语言源代码转换成汇编语言代码,然后再使用独立的汇编器将汇编语言代码转换成机器语言代码。这种分离的方式可以让用户有更多的选择,可以灵活地选择不同的汇编器来适应不同的需求。

是否包含汇编器取决于不同的编译器实现,而不是编译器的必要组成部分。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/216177.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

Linux【2】:清理几天前的文件夹YYYYMMDD

Linux【2】&#xff1a;清理几天前的文件夹YYYYMMDD 1、清理指定日期【文件名】前文件夹脚本2、清理指定日期【文件日期】前的文件3、find命令说明 1、清理指定日期【文件名】前文件夹脚本 脚本如下#!/bin/bash #移除模糊目录下的日期文件夹 RemoveDir/root/tlogs/* dtdate %Y…

Ruoyi-vue上传下载文件

1. Controller /*** 修改文书发布记录*/RepeatSubmit //禁止重复提交Log(title "文书发布记录", businessType BusinessType.UPDATE)PostMapping("update") //RequestParam("xxx") RequestBody RequestPart("xxx") 这3个注解都…

深入了解ThreadLocal:避免内存泄漏的陷阱与最佳实践

多线程编程中&#xff0c;数据共享与隔离一直是开发者需要面对的挑战之一。而Java中的ThreadLocal提供了一种优雅的解决方案&#xff0c;允许每个线程都拥有自己独立的数据副本&#xff0c;从而避免了共享数据带来的线程安全问题。然而&#xff0c;正如事物总有两面性一样&…

Kimichat使用案例:将一大片无序文本内容整理成有序的Excel表格

Kimichat是一个国产的AI大模型应用。2024年10月9日&#xff0c;专注于通用人工智能领域的公司月之暗面&#xff08;Moonshot Al&#xff09;宣布在“长文本”领域实现了突破&#xff0c;推出了首个支持输入20万汉字的大模型moonshot&#xff0c;以及搭载该模型的智能助手产品Ki…

ORCLE APEX和EBS集成的2个小问题

from跳转后&#xff0c;没有跳转到指定页 从EBS菜单跳转登录后&#xff0c;没有跳转到APEX的指定页&#xff0c; 原因&#xff1a;再USER_INTERFACE定义的地方&#xff0c;HOME URL 被设置成了固定值 0&#xff0c;如上图 解决方法&#xff1a;定义APP级别的ITEM,在自动登录的…

使用Dockerfile Maven Plugin 将Docker镜像Push到AWS ECR (Elastic Container Registry)

文章目录 小结问题解决AWS ECR (Elastic Container Registry)的登录问题 pull access denied for jdk, repository does not exist问题 Could not acquire image ID or digest following builddockerfile-maven-plugin 使用 参考 小结 本文记录使用Dockerfile Maven Plugin 将…

通过一道CTF题目来认识一下Frida

本文作者&#xff1a;杉木涂鸦智能安全实验室 Frida https://github.com/frida/frida Frida是一个动态代码插入工具&#xff0c;可用于各种应用程序的调试和逆向工程。它提供了多种安装选项&#xff0c;包括Python和Node.js绑定&#xff0c;并提供了详细的命令行参数和选项。…

JVM虚拟机系统性学习-运行时数据区(虚拟机栈、本地方法栈)

虚拟机栈 虚拟机栈为每个线程所私有的&#xff0c;如下图&#xff1a; 栈帧是什么&#xff1f; 栈帧存储了方法的局部变量表、操作数栈、动态链接和方法返回地址等信息 栈内存为线程私有的空间&#xff0c;每个方法在执行时都会创建一个栈帧&#xff0c;执行该方法时&…

Java的NIO工作机制

文章目录 1. 问题引入2. NIO的工作方式3. Buffer的工作方式4. NIO数据访问方式 1. 问题引入 在网络通信中&#xff0c;当连接已经建立成功&#xff0c;服务端和客户端都会拥有一个Socket实例&#xff0c;每个Socket实例都有一个InputStream和OutputStream&#xff0c;并通过这…

选择法排序

本题要求将给定的n个整数从大到小排序后输出。 输入格式&#xff1a; 输入第一行给出一个不超过10的正整数n。第二行给出n个整数&#xff0c;其间以空格分隔。 输出格式&#xff1a; 在一行中输出从大到小有序的数列&#xff0c;相邻数字间有一个空格&#xff0c;行末不得有…

企业IT安全:内部威胁检测和缓解

什么是内部威胁 内部威胁是指由组织内部的某个人造成的威胁&#xff0c;他们可能会造成损害或窃取数据以谋取自己的经济利益&#xff0c;造成这种威胁的主要原因是心怀不满的员工。 任何内部人员&#xff0c;无论是员工、前雇员、承包商、第三方供应商还是业务合作伙伴&#…

SSL证书HTTPS保护服务

SSL证书属于数字证书的其中一种&#xff0c;广泛用于https协议&#xff0c;从而可以让数据传输在加密前提下完成&#xff0c;确保HTTPS网络安全是申请SSL证书必要工作。 SSL证书是主要用于https是一种加密协议&#xff0c;仔细观察网站地址会发现目前主流的网址前面都会有http…

【玩转TableAgent数据智能分析】利用TableAgent进行教育数据分析

文章目录 前言九章云极&#xff08;DataCanvas&#xff09;介绍前期准备样例数据集体验1. 样例数据集-Airbnb民宿价格&评价 体验1.1 体验一1.2 体验二 教育数据的分析&#xff08;TableAgent&ChatGLM对比&#xff09;1. 上传文件2. 数据分析与对比2.1 分析一2.1.1 Tabl…

web服务器之——建立两个基于ip地址访问的网站

目录 准备工作&#xff1a;web服务器搭建 第一步&#xff1a;挂载 第二步&#xff1a;编辑配置文件 第三步&#xff1a;安装软件包 第四步&#xff1a;启动httpd 查看配置文件&#xff1a; 第五步&#xff1a;设置防火墙状态&#xff1a; 重启服务: 查看状态&#xff1…

Leetcode—2961.双模幂运算【中等】

2023每日刷题&#xff08;五十六&#xff09; Leetcode—2961.双模幂运算 实现代码 class Solution { public:int func(int a, int b) {int ans 1;for(int i 0; i < b; i) {ans * a;ans % 10;}return ans;}int func2(int a, int b, int m) {int ans 1;for(int i 0; i …

评论送书:以企业架构为中心的SABOE数字化转型五环法

01 传统企业数字化转型面临诸多挑战 即将过去的2023年&#xff0c;chatGPT大模型、数据资产入表等事件的发生&#xff0c;标志着数字经济正在加速发展。数字经济是人类社会继农业经济、工业经济之后的第三种经济形态&#xff0c;将推动生产方式、生活方式和治理方式深刻变革&a…

2-Spring

2-Spring 文章目录 2-Spring项目源码地址Spring概述Spring特点&#xff08;优点&#xff09;Spring相关学习网站基于Maven的Spring框架导入Spring的组成及拓展 Spring-IOC--原型理解IOC-原型--示例开发示例-常规开发示例-Set函数&#xff08;IOC原型&#xff09;开发示例-对比思…

C++STL的list(超详解)

文章目录 前言构造函数capacitylist的访问insertswapsort 前言 看一下list, 在任意位置可以进行O(1)插入删除的操作。 它怎么实现这个东西&#xff1f;它其实就是一个带头双向循环链表。 #成员函数 构造函数 这里面的构造函数学完string和vector之后已经相当熟悉了。 capaci…

axios请求拦截和响应拦截

Axios的请求拦截器和响应拦截器都是非常有用的工具&#xff0c;它们可以在请求发送到服务器之前或响应返回到客户端之前进行干预。 请求拦截器&#xff1a; 请求拦截器是在发送请求之前执行的&#xff0c;可以在请求拦截器中对请求进行一些预处理&#xff0c;比如设置统一的请…

如何将用户有过行为的item用list形式记录下来,另外如何计算list里的个数

导语&#xff1a; 最近做项目&#xff0c;发现有些语法想一想是知道&#xff0c;但实际操作起来跟想的情况不一样哈哈。不是遇见bug就是输出的结果不是自己想要的&#xff0c;CSDN跟知乎找了很多没怎么解决&#xff0c;后面多摸索多实操终于解决&#xff01; test_data[item_…