免费注册 查看新帖 |

Chinaunix

  平台 论坛 博客 文库
最近访问板块 发新帖
查看: 1892 | 回复: 5
打印 上一主题 下一主题

整合为一体 [复制链接]

论坛徽章:
0
跳转到指定楼层
1 [收藏(0)] [报告]
发表于 2013-07-26 15:23 |只看该作者 |倒序浏览
本帖最后由 landker 于 2013-07-26 15:26 编辑

在《现代编译原理——C语言描述(虎书)》中文版)中,对于第12章的内容不太明白,想请教一下。里面第191页中间处提到,如果要创建一个可运行的编译器,则需要使用到一个runtime.c的文件,实际上是一个对于操作系统的“系统调用”函数的使用。但这里就产生一个问题,所有的函数在定义时都要入符号表,那这些“系统调用”都在哪里声明了?例如:putchar函数(在runtime.c里的print函数里),它的声明在哪里?此外,该如何编译(即比如说,我要使用 printf,那我要链接哪些库?)?

这里附上 runtime.c 的 source
  1. #undef __STDC__
  2. #include <stdio.h>


  3. int *initArray(int size, int init)
  4. {int i;
  5. int *a = (int *)malloc(size*sizeof(int));
  6. for(i=0;i<size;i++) a[i]=init;
  7. return a;
  8. }

  9. int *allocRecord(int size)
  10. {int i;
  11. int *p, *a;
  12. p = a = (int *)malloc(size);
  13. for(i=0;i<size;i+=sizeof(int)) *p++ = 0;
  14. return a;
  15. }

  16. struct string {int length; unsigned char chars[1];};

  17. int stringEqual(struct string *s, struct string *t)
  18. {int i;
  19. if (s==t) return 1;
  20. if (s->length!=t->length) return 0;
  21. for(i=0;i<s->length;i++) if (s->chars[i]!=t->chars[i]) return 0;
  22. return 1;
  23. }

  24. void print(struct string *s)
  25. {int i; unsigned char *p=s->chars;
  26. for(i=0;i<s->length;i++,p++) putchar(*p);
  27. }

  28. void flush()
  29. {
  30. fflush(stdout);
  31. }

  32. struct string consts[256];
  33. struct string empty={0,""};

  34. int main()
  35. {int i;
  36. for(i=0;i<256;i++)
  37.    {consts[i].length=1;
  38.     consts[i].chars[0]=i;
  39.    }
  40. return tigermain(0 /* static link */);
  41. }

  42. int ord(struct string *s)
  43. {
  44. if (s->length==0) return -1;
  45. else return s->chars[0];
  46. }

  47. struct string *chr(int i)
  48. {
  49. if (i<0 || i>=256)
  50.    {printf("chr(%d) out of range\n",i); exit(1);}
  51. return consts+i;
  52. }

  53. int size(struct string *s)
  54. {
  55. return s->length;
  56. }

  57. struct string *substring(struct string *s, int first, int n)
  58. {
  59. if (first<0 || first+n>s->length)
  60.    {printf("substring([%d],%d,%d) out of range\n",s->length,first,n);
  61.     exit(1);}
  62. if (n==1) return consts+s->chars[first];
  63. {struct string *t = (struct string *)malloc(sizeof(int)+n);
  64.   int i;
  65.   t->length=n;
  66.   for(i=0;i<n;i++) t->chars[i]=s->chars[first+i];
  67.   return t;
  68. }
  69. }

  70. struct string *concat(struct string *a, struct string *b)
  71. {
  72. if (a->length==0) return b;
  73. else if (b->length==0) return a;
  74. else {int i, n=a->length+b->length;
  75.        struct string *t = (struct string *)malloc(sizeof(int)+n);
  76.        t->length=n;
  77.        for (i=0;i<a->length;i++)
  78.          t->chars[i]=a->chars[i];
  79.        for(i=0;i<b->length;i++)
  80.          t->chars[i+a->length]=b->chars[i];
  81.        return t;
  82.      }
  83. }

  84. int not(int i)
  85. { return !i;
  86. }

  87. #undef getchar

  88. struct string *getchar()
  89. {int i=getc(stdin);
  90. if (i==EOF) return &empty;
  91. else return consts+i;
  92. }
复制代码

论坛徽章:
0
2 [报告]
发表于 2013-07-26 15:26 |只看该作者
回复 1# landker


    ding

论坛徽章:
1
2015年迎新春徽章
日期:2015-03-04 09:53:17
3 [报告]
发表于 2013-07-26 17:40 |只看该作者
在说明 runtime.c 时,其实是想说明 libc 这样的东西和编译器是什么关系。
而举的例子又不是实现一个真正的runtime(因为实现一个真正的runtime内容很多,就会跑题),而是给现有runtime套上一层,做了一个假的runtime,这样就产生了误解。

真正的runtime是紧紧地包在操作系统内核上的。不会有putchar在哪? 这种问题。
比如流式输出 printf ,runtime除了维护流外,最终显示到控制台应该是靠 write(stdout_fd, ...); 系统调用,而这个系统调用不再连接外部库,是一个汇编实现,对于linux 是 80 号中断。

论坛徽章:
0
4 [报告]
发表于 2013-07-26 20:28 |只看该作者
本帖最后由 landker 于 2013-07-26 21:03 编辑
duanlin 发表于 2013-07-26 17:40
在说明 runtime.c 时,其实是想说明 libc 这样的东西和编译器是什么关系。
而举的例子又不是实现一个真正的 ...


楼上,

谢谢你的回复。我先试试。

论坛徽章:
0
5 [报告]
发表于 2013-07-27 15:03 |只看该作者
本帖最后由 landker 于 2013-07-27 15:12 编辑
duanlin 发表于 2013-07-26 17:40
在说明 runtime.c 时,其实是想说明 libc 这样的东西和编译器是什么关系。
而举的例子又不是实现一个真正的 ...


楼上,

write.asm我已完成,并编译链接等都通过了。但运行的时候(假如编译器的名字叫做 comp_cc,而被编译的原文件叫做 abc.tig。那在执行“comp_cc abc.tig”后,会生成 abc.asm这个汇编文件。在经过nasm和ld这2步后,编译链接成 abc 这个可执行文件),即在执行 abc(即 ./abc)时, 报“段错误 (核心已转储)”这个错误。

我想请教一下,在这种情况下,是否有“单步调试”的方法?如果有,那该如何调试?

此外,在生成abc这个可执行文件时,我是另外写了个简单的 start.asm,里面定义了 _start ,且规定了要跳转至的函数。还有,在makefile的的设置里,我是将 -Ttext 设定为 0x8048000。这些设置有问题吗?

论坛徽章:
1
2015年迎新春徽章
日期:2015-03-04 09:53:17
6 [报告]
发表于 2013-07-29 21:54 |只看该作者
调试是一个很大的话题,不论是pdb 还是dwarf,都有非常多的内容。要是自制编译器直接生成二进制代码,我想要让这个程序停下来不是很容易。因为你除了需要生成指令序列外,还要生成调试信息的段。如果是编译器生成某种其他汇编器的文本汇编程序,那就可以靠汇编器来生成调试信息。比如你可以用 nasm 生成带有调试信息的elf,那样就可以套gdb。

连接部分是自制的吗?看看连接有问题吗,重定位地址填非法了没?
另外如果程序里有访问外部共享库的东西的话,还要考虑你的程序加载器是否能和你的程序配合的正确。
您需要登录后才可以回帖 登录 | 注册

本版积分规则 发表回复

  

北京盛拓优讯信息技术有限公司. 版权所有 京ICP备16024965号-6 北京市公安局海淀分局网监中心备案编号:11010802020122 niuxiaotong@pcpop.com 17352615567
未成年举报专区
中国互联网协会会员  联系我们:huangweiwei@itpub.net
感谢所有关心和支持过ChinaUnix的朋友们 转载本站内容请注明原作者名及出处

清除 Cookies - ChinaUnix - Archiver - WAP - TOP