在linux上进行编译调试

news2025/1/20 10:50:59

1.相关疑问

1. 为什么在代码里使用了一个未定义过的函数(如add()),在编译阶段不会报错,在链接阶段会报错呢?

答:先说几个代码编译的结论:

  • 单个\.c源文件文件被编译成机器码文件时,源文件中的所有变量名以及数组名都会变成地址偏移量;
  • 类型信息都会变成指令的长度(int\-\>subl, 地址\-\>subg);
  • 循环会变成goto的方式实现;
  • 函数的调用变成了使pc指针移动到被调方函数的地址;

由以上第四条可知,函数的调用依赖于被调函数的地址,编译后的文件可以使用nm xxx.o来查看所有函数的地址和函数名的对应情况,在链接之前可以看到此时有的函数名还没有对应的地址,而将这些函数名和地址关联起来的操作就是链接阶段要做的事,在链接阶段无法为主调方找到被调方函数地址时就会报链接错误。
在这里插入图片描述

2. gcc编译器

1. 预处理指令

  • #include:引入头文件

  • #define:定义宏常量和宏函数

  • #if:根据指定条件判断是否编译后续代码块(可作为测试代码开关

    // 使用示例:
    #define DEBUG 1
    #if DEBUG
        // Debugging code
        printf("Debug mode is active.\n");
    #endif
    
  • #ifdef:判断某个标识符是否已经定义(可作为测试代码开关

    #ifdef ON //表示如果定义了ON,或命令行编译时用-D传了ON,就执行下面的输出
        printf("ON is defined!\n");
    #else
        printf("ON is not defined!\n");
    #endif
        printf("main exit\n");
    

    可以在命令行定义预处理器宏gcc -o test test.c -DON

  • #ifndef:判断某个标识符是否没有已经定义(可用于头文件保护

    #ifndef TEST_H
        #define TEST_H
    #endif
    
  • #endif:结束条件编译的代码块

2. gcc常用指令

补充

列出所有函数:nm test.o

查看可执行程序链接了哪些库:ldd test

  • 预处理:

    gcc -E test.c -o test.i
    
  • 编译:

    gcc -S test.c -o test.s
    
  • 汇编:

    // 方式一:从汇编文件到机器码文件
    as test.s -o test.o
    // 方式二:从预处理文件到机器码文件
    gcc-13 -C test.i -o test.o
    // 方式三:从源文件到机器码文件
    gcc-13 -C test.c -o test.o
    
  • 链接:gcc -o test test.c 输出可执行文件

    // 方式一:编译+链接(从源文件到可执行文件)
    gcc -o test test.c
    // 方式二:链接
    gcc -o test test.o
    // 方式三:指定链接路径
    gcc test1.o -o test1 -ladd
    // 还可以使用ld命令可以调用静态链接器
    ld test.o [其他系统库文件] -o test
    
  • 定义宏:

    gcc test1.o -o test1 -D DEBUG
    
  • 制定优化级别:

    gcc test1.o -o test1 -O0 // 推荐O1级别
    
  • 为gdb补充符号信息:

    gcc test1.o -o test1 -O0 -g // 要用gdb调试时最好指定不优化,避免机器码和代码不一致影响调试
    
  • 提示警告:

    gcc test1.o -o test1 -Wall // 注意Wall是大写W
    
  • 指定头文件搜路径:

    gcc test1.o -o test1 -I "../h" //默认从当前路径下搜索
    

3. gdb调试

补充

用gdb调试时,传递命令行参数的两种方式:

  • 方式一:进入gdb后:用set args xxx
  • 方式二:进入gdb前:使用gdb --args test xxx启动

1. 常用指令

  1. 用-g生成可执行文件:gcc –o test test.c -O0 –g

  2. 进入调试器:gdb test

  3. 显示代码:

    • 默认显示:l/list //默认显示10行
    • 显示指定信息:l/list [文件名:]行号or函数名 //[]表示可有可无
  4. 运行:r/run

  5. 退出:q/quit

  6. 断点相关:

    • 设置断点:b/break 4 //在第四行设置断点
    • 列出断点:i b/info break // 查看断点号
    • 删除断点:delete 断点号
    • 停止断点:disable 断点号
    • 激活断点:enable 断点号
  7. 跳转:

    • 下一步不进入函数:n/next //F10
    • 下一步进入函数:s/step //F11
    • 到下一个断点:c/continue
    • 跳出当前函数:finsh
  8. 查看信息:

    • 打印变量:p/print
    • 自动显示的表达式内容:display 表达式 (自动显示内存:display /1xw &i``)
    • 停止显示某个表达式:undisplay 表达式 或者 undisplay 编号(通过info display查看编号)
    • 查看调用堆栈:b t/back trace
    • 查看内存:x<n/f/u> //n表示内存的长度 f表示内存的格式 u表示内存的单位
    • 清空信息: Ctrl + L 组合键,或者输入 shell clear 命令(shell命令用于调用系统断点shell

2. 调试core文件

  1. 启用 core 文件自动生成
    • 查看core文件是否存在限制:ulimit -a
    • 关闭限制:ulimit -c unlimited
  2. 运行程序并生成 core 文件
    • 如果未生成,则使用man core查看帮助文档解决;
  3. 使用 GDB 调试 core 文件:gdb test core;
  4. 查看调试信息
    • 查看调用栈:bt
    • 查看栈帧信息:frame 0
    • 显示寄存器的值:info registers
    • 分析内存:x

4. 静态库和动态库

库文件其实就是别人造好的“轮子”,别人写好并编译好后给用户使用的二进制代码。

静态库文件在程序的链接阶段被需要,而动态库文件在程序运行过程中也被需要。

1. 静态库

在程序链接阶段,库文件会被打包进最终的可执行程序。

gcc编译时,如果存在同名的动态(.so)和静态(.a)库文件,默认是使用动态文件,此时要使用静态库文件就必须要使用-static参数指定优先静态链接,如果找不对应的\.a文件会链接失败。

特点:省心,但体积大且更新不方便。

打包命令

// 1. 得到编译后的机器码文件
gcc -c add.c -o add.o 
// 2. 生成静态库文件(库文件必须以lib开头)
ar crsv libadd.a add.o
// 3. 将静态库文件移动到"/usr/lib"或"/usr/local/lib"下,推荐前者
sudo mv libadd.a /usr/lib
// 4. 使用即可
gcc main.o -o main -ladd

2. 动态库

链接阶段不打包进程序,在程序运行时加载。

特点:体积小、更新方便(动态更新),但容易存在依赖问题。

打包命令

// 1. 生成位置无关的目标代码,使用-fpid(Position Independent Code)
gcc -c add.c -o add.o -fpic
// 2. 生成动态库文件(库文件必须以lib开头)
gcc -shared add.o -o libadd.so
// 3. 将静态库文件移动到"/usr/lib"或"/usr/local/lib"下,推荐前者
sudo mv libadd.so /usr/lib
// 4. 使用即可
gcc main.o -o main -ladd

3. 产品动态更新

原理:利用版本号和软连接实现

  • 第一步:生成带版本好的.so动态库文件,如:libadd.so.0.0.0、libadd.so.0.1.0
  • 第二步:建立最新版本的软连接,sudo ln -s libadd.so.0.1.0 libadd.so

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

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

相关文章

如何把openwrt的ipk软件包安装到ubuntu上

前提&#xff1a;都是arm64的架构的软件包。 下载openwrt的ipk软件包 1. 从https://pkgs.org/ 查找下载软件包&#xff1a; 本文以swconfig软件包为例&#xff0c;下载swconfig和相关的依赖软件包&#xff1a; swconfig_12_aarch64_cortex-a72.ipk libuci20130104_2021-10-2…

认识与探索大模型时代的RPA应用及进化(上)

AI Agent当前仍然处于技术爬坡与实验阶段&#xff0c;特别是在企业领域&#xff0c;真正的成熟应用还处于广泛探索与原型验证阶段&#xff0c;离成熟还尚待时日。而同时另外一种在最近几年广受欢迎的自动化解决方案-RPA&#xff08;机器人流程自动化&#xff09;也在LLM时代不断…

python使用迭代生成器yield减少内存占用的方法

嗨喽&#xff0c;大家好呀~这里是爱看美女的茜茜呐 在python编码中for循环处理任务时&#xff0c;会将所有的待遍历参量加载到内存中。 其实这本没有必要&#xff0c;因为这些参量很有可能是一次性使用的&#xff0c; 甚至很多场景下这些参量是不需要同时存储在内存中的&…

IM-CNN

SHAP means ‘Shapley additive explanation’ 辅助信息 作者未提供代码

基于ncurse的floppy_bird小游戏

1. 需求分析 将运动分解为鸟的垂直运动和杆的左右运动。 2. 概要设计 2.1 鸟运动部分 2.2 杆的运动 3. 代码实现 #include <stdio.h> #include <ncurses.h>#include <stdlib.h> #include <time.h>int vx 0; int vy 1;int bird_r; int bird_c;int…

HTML5和CSS3的新特性

HTML5的新特性主要是针对于以前的不足&#xff0c;增加了一些新的标签、新的表单和新的表单属性等 1&#xff0c;HTML5新增的语义化标签 <header> 头部标签 <nav> 导航标签 <article> …

1 月 28日算法练习-前缀和

小郑的蓝桥平衡串 思路&#xff1a;把 L 看成 1&#xff0c;Q 看成 -1&#xff0c;利用前缀和来得到输入串的前缀子串中LQ 的和&#xff0c;利用前缀和差的性质得到子串&#xff0c;通过枚举看它是否平衡。 将L看做1&#xff0c;Q看做&#xff0d;1&#xff0c;只有当某个区间…

Django实战

一、开发登录表单 def login_form(request):html <html><body><form method"post">用户名:<input name "username" type"text"></input></br>密码&#xff1a;<input name "password" type…

ARM常用汇编指令

文章目录 前言一、处理器内部数据传输指令MOV&#xff1a; 将数据从一个寄存器复制到另一个寄存器。MRS&#xff1a; 将特殊寄存器(CPSR,SPSR)中的数据传给通用寄存器。MSR&#xff1a; 将通用寄存器中的数据传给特殊寄存器(CPSR,SPSR)。 二、存储器访问指令LDR:用于从内存中加…

5G赋能智慧文旅:科技与文化的完美结合,打造无缝旅游体验,重塑旅游业的未来

一、5G技术&#xff1a;智慧文旅的强大引擎 5G技术的起源可以追溯到2010年&#xff0c;当时世界各国开始意识到4G技术已经达到了瓶颈&#xff0c;无法满足日益增长的移动通信需求。2013年&#xff0c;国际电信联盟&#xff08;ITU&#xff09;成立了5G技术研究组&#xff0c;开…

力扣LCR 180. 文件组合(双指针)

Problem: LCR 180. 文件组合 文章目录 题目描述思路及解法复杂度Code 题目描述 思路及解法 本题目可以利用滑动窗口的技巧&#xff08;滑动窗口就是双指针的运用&#xff09;解决&#xff0c;具体实现如下 1.逻辑上生成窗口&#xff1a;让两个指针i&#xff0c;j分别初始化为1…

IPv6报文格式(全网最详细)

IPv6报文格式 报文格式 图1 IPv6报文头格式 表1 IP头字段解释 字段长度含义Version4比特 4&#xff1a;表示为IPV4&#xff1b;6&#xff1a;表示为IPV6。Traffic class8比特流量类别。该字段及其功能类似于IPv4的业务类型字段。该字段以区分业务编码点&#xff08;DSCP&…

203.移除链表元素(力扣LeetCode)

文章目录 203.移除链表元素题目描述原链表删除元素虚拟头节点 203.移除链表元素 题目描述 给你一个链表的头节点 head 和一个整数 val &#xff0c;请你删除链表中所有满足 Node.val val 的节点&#xff0c;并返回 新的头节点 。 示例 1&#xff1a; 输入&#xff1a;head …

基于Micropython利用ESP32-C3驱动墨水屏显示图片

从咸鱼上淘了两块2.9寸的墨水屏价签&#xff0c;可以结合ESP32-C3做个低功耗的时钟温湿度计。 1、所需硬件 合宙的ESP32-C3&#xff1a; 电子价签拆出来的2.9寸墨水屏&#xff1a; ——电子价签型号为&#xff1a;Stellar-L&#xff0c;墨水屏型号为&#xff1a;E029A01。电子…

Less-1(sqlmap自动注入攻击)--sqli

环境准备 打开火狐浏览器&#xff0c;进入sqli第一关的页面 工具准备 sqlmap 参数解释 -u URL 指定目标URL进行注入测试。--dataDATA指定POST请求的数据进行注入测试--cookieCOOKIE指定用于身份验证的cookie进行注入测试-p PARAMETER指定要测试的参数--levelLEVEL设置测试的深…

[260. 只出现一次的数字 III](C语言题解)(位运算)(力扣)

> Problem: [260. 只出现一次的数字 III](260. 只出现一次的数字 III - 力扣&#xff08;LeetCode&#xff09;) # 思路 > 想到数组中只有一个数只出现了一次的解法&#xff1a;**所有数异或&#xff0c;最后答案就是那个只出现一次的数**&#xff0c;该题只需将两个不…

Java技术栈 —— Hadoop入门(二)

Java技术栈 —— Hadoop入门&#xff08;二&#xff09; 一、用MapReduce对统计单词个数1.1 项目流程1.2 可能遇到的问题1.3 代码勘误1.4 总结 一、用MapReduce对统计单词个数 1.1 项目流程 (1) 上传jar包。 (2) 上传words.txt文件。 (3) 用hadoop执行jar包的代码&#xff0c;…

HarmonyOS 鸿蒙应用开发 (七、HTTP网络组件 axios 介绍及封装使用)

在HarmonyOS应用开发中&#xff0c;通过HTTP访问网络&#xff0c;可以使用官方提供的ohos.net.http模块。但是官方提供的直接使用不太好使用&#xff0c;需要封装下才好。推荐使用前端开发中流行的axios网络客户端库&#xff0c;如果是前端开发者&#xff0c;用 axios也会更加顺…

FOC系列(五)----STM32F405RGT6控制板焊接与初步编写代码

声明&#xff1a;本人水平有限&#xff0c;博客可能存在部分错误的地方&#xff0c;请广大读者谅解并向本人反馈错误。    首先祝大家新年快乐&#xff0c;因为我也快放假了&#xff0c;驱动板只能是开学之后再去测试了&#xff0c;本篇博客应该是本专栏年前的最后一篇了 一…

QT 范例阅读:Vector Deformation

效果图&#xff1a; 主要代码&#xff1a; 实现放大镜效果QPainter painter;//两种方式if (1) {m_lens_image QImage(bounds.size(), QImage::Format_ARGB32_Premultiplied);m_lens_image.fill(0);painter.begin(&m_lens_image);} else {m_lens_pixmap QPixmap(bounds.si…