Ubuntu下UnixC的第三天

dlopen(3) dlclose(3) dlerror(3) dlsym(3)
   
       #include <dlfcn.h>

       void *dlopen(const char *filename, int flags);

    参数 filename 指定了共享库的文件名
         flags 二选一 RTLD_LAZY :懒绑定,代码执行时才绑定
              RTLD_NOW : 立即绑定,在函数返回之前已经绑定


    返回值 成功时返回 非null   错误返回null
        使用时gcc后加上 -ldl. link with -ldl
     int dlclose(void *handle);
    功能:共享库文件的引用计数减一,减到0的时候自动卸载共享库
    参数:
        handle指定已经加载的共享库的地址
    返回值:成功返回0,否则非0
    以上这些函数的错误信息,可以使用dlerror(3)获取
   
    举例说明 动态加载动态库
    代码参见 dynamic.c
    #include<dlfcn.h>
    char *dlerror(void);
    功能:获取最近一次dlopen API函数执行的错误信息
    参数:
    返回值:如果返回NULL则表示没错误    否则返回字符串首地址,这个字符串是我们可以读懂的错误信息
     #include <dlfcn.h>

       void *dlsym(void *handle, const char *symbol);
    功能:获取共享库中某一函数的地址
    参数:
    handle-指定了共享库
    symbol- 指定了函数的名字
    返回值:成功 返回symbol加载到内存的地址
        失败

    void *
    void *malloc(1024)
    char *p=(char *)malloc(1024)
    三、程序中的错误处理
        程序执行过程中,调用库函数或者系统调用。这些函数错误的时候,如何获取这些函数执行的错误信息呢?
        系统维护着一个全局变量  int errno.当以上函数调用失败的时候,记录errno的值。根据errno的值获取函数执行失败的错误信息
            errno(3)
            #include<errno.h>
        代码引入错误处理,参见代码,file.c、
        strerror
         #include <string.h>

              char *strerror(int errnum);
        功能:返回errnum描述错误原因的信息
        参数:
        返回值: unknown error nnn
            返回跟错误编号对应的错误描述的字符串首地址
        perror(3)
         #include <stdio.h>

             void perror(const char *s);
        功能:输出一条系统错误消息
        参数:
            s:用户自定义字符串
        返回值:
       
        标准输入  键盘 FILE* stdin
        标准输出  显示器 FILE* stdout
        标准错误输出 显示器 FILE* stderr

        #define E_MSG(string,val) do{perror(string);return (val);}while(0)
   


今天内容
    一gdb调试器的使用
    可执行文件要想在执行的时候被调试,可执行文件中必须包含有调试信息。
    那如何给可执行文件加调试信息呢?
        gcc hello.c -g或者-ggdb
    启动调试器,调试可执行程序
    gdb a.out
    调试命令
    l 列出程序清单
    断点 让程序执行到断点的时候,停止
    b 行号|函数的名字  设置断点
    r 运行程序
    n 执行下一条语句
    p 变量的名字 输出变量的值
    q 退出调试
    s step 单步调试
    二、内存管理
    物理地址  虚拟地址
    cpu的寻址空间(能力) 0~4G-1
    页  页表  页框    页的单位是4k
    每次分配34页
    cpu可以有两种身份   有四种(操作系统只用两种) 内核态 用户态
    cpu工作在用户态的情况下,可以访问的虚拟地址空间是0~3G-1
    工作在内核态的情况下,可以访问的虚拟地址空间是3G~4G-1
    代码验证段错误  参见 segment.c
    每个进程都有自己独立的4G虚拟地址空间
    每个进程都有自己的一份页表 当进程需要访问内核1G的地址空间的时候,向操作系统申请访问,操作系统代理进程访问这些资源。
    数据区间  代码区间  栈区间
    代码段     数据段   栈段   
    代码段  不能写 只读 可执行
    数据段 能读能写 不能执行
    堆
    获取进程的pid
    getpid(2)
       #include <sys/types.h>
       #include <unistd.h>

       pid_t getpid(void);
    功能:获取当前进程的pid
    参数:
    返回值:当前进程的pid
    pid_t 数据类型
    举例说明  代码参见  memory.c
    /proc/进程的pid/maps

    BBS 未初始化的全局变量
    代码段 保存程序代码的
    静态存储 已经初始化的全局变量或者使用静态分配的变量
    栈 局部变量、参数表
    堆 动态内存
    三 使用mmap将物理地址映射到进程的虚拟地址空间
 

try.c

#include<stdio.h>
#include<string.h>
int main(int argc,char* argv[]){
int i=0;
if(strcmp(argv[1],"zhaocb")==0){
    printf("shihaoren\n");
}
printf("%d\n",argc);
for(i=0;i<argc;i++){
    printf("->%s\n",argv[i]);
}
return 0;
}
 

segment.c

#include<stdio.h>

int main(void){
    int val=300;
    int *p=(int *)0xa0000000;
    printf("p content is %p\n",p);
    printf("*p content is %d\n",*p);
    return 0;
}

 

file.c

#include<stdio.h>
#include<errno.h>
#include<string.h>
#include"E_MSG.h"
int main(int argc,char* argv[])
{
    //打开一个文件 argv[1]
    FILE *fp=fopen(argv[1],"r");
    if(fp==NULL){
#if 0    
        printf("file open failed number is %d...reason is %s\n",errno,strerror(errno));
 
        perror("fopen");
        return -1;
#endif
        E_MSG("fopen",-1);
    }
    printf("file fopen success...\n");
    fclose(fp);
    return 0;
    
}

E_MSG.h

#ifndef E_MSG_H_
#define E_MSG_H_
    #define E_MSG(string,val) do{perror(string);return (val);}while(0)
#endif
 

dynamic.c

#include<stdio.h>
#include<dlfcn.h>

int main(int argc,char *argv[]){
    //func是指针类型的变量,但是对func变量的内容作为地址,对这个地址里的内容访问的时候,遵循函数的访问规则。
    int (*func)(int,int);

    //动态加载共享库,argv[1]指定共享库文件的名字
    void *h=dlopen(argv[1],RTLD_NOW);
    if(h==NULL)//打开共享库文件失败
    {    
        printf("dlopen failed...\n");
        printf("%s\n",dlerror());
        return -1;
    }
    printf("dlopen success..\n");
    //在共享库中找函数的地址
    void *f= dlsym(h,"t_div");
    if(f==NULL)//没找到函数
    {
        printf("%s\n",dlerror());
        return -1;
    }
    //这个函数找到了,函数的入口地址,但是是void,不访问
    //如何访问这个函数的代码
    func=f;
    printf("6/2=%d\n",func(6,2));
    
    //关闭共享库文件
    dlclose(h);
    return 0;
}
 

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值