• 程序被加载到进程的哪个位置?


    程序被加载器加载到内存后,通过/proc/$pid/maps文件,我们可以观测到程序被加载的内存位置。那么,通过打印进程内存的方式,让我们确认程序是不是真的加载到内存,以及加载到内存的程序和硬盘中的文件有没有区别。

    编写测试程序:

    1. #include
    2. #include
    3. #include
    4. #include
    5. int main() {
    6. while(true) {
    7. sleep(3);
    8. printf("something\n");
    9. }
    10. return 0;
    11. }

    编译启动,然后打印程序的16进制

    这里只展示部分16进制,用于与内存中的16进制进行对比。

    编写内核代码:

    1. #include
    2. #include
    3. #include
    4. #include
    5. #include
    6. #include
    7. static pte_t *get_pte(struct task_struct *task, unsigned long address) {
    8. pgd_t *pgd;
    9. p4d_t *p4d;
    10. pud_t *pud;
    11. pmd_t *pmd;
    12. pte_t *pte;
    13. struct mm_struct *mm = task->mm;
    14. pgd = pgd_offset(mm,address);
    15. if (pgd_none(*pgd) || pgd_bad(*pgd)) {
    16. return NULL;
    17. }
    18. p4d = p4d_offset(pgd, address);
    19. if (p4d_none(*p4d) || p4d_bad(*p4d))
    20. return NULL;
    21. pud = pud_offset(p4d, address);
    22. if (pud_none(*pud) || pud_bad(*pud))
    23. return NULL;
    24. pmd = pmd_offset(pud, address);
    25. if (pmd_none(*pmd) || pmd_bad(*pmd))
    26. return NULL;
    27. pte = pte_offset_kernel(pmd, address);
    28. if (pte_none(*pte))
    29. return NULL;
    30. return pte;
    31. }
    32. static int hello_init(void) {
    33. struct task_struct *p;
    34. struct vm_area_struct *vma;
    35. int len;
    36. pte_t *pte;
    37. struct page *page;
    38. unsigned long addr;
    39. printk(KERN_ALERT "init fishing\n");
    40. for_each_process(p) {
    41. if (strcmp(p->comm,"a.out") == 0) {
    42. printk(KERN_ALERT "%s-->%p\n",p->comm, p->mm);
    43. for(vma = p->mm->mmap;vma!=NULL;vma = vma->vm_next) {
    44. printk(KERN_ALERT "%lx - %lx\n",vma->vm_start, vma->vm_end);
    45. pte = get_pte(p, vma->vm_start);
    46. if (pte == NULL)
    47. break;
    48. page = pte_page(*pte);
    49. addr = page_address(page);
    50. len = vma->vm_end - vma->vm_start;
    51. print_hex_dump(KERN_NOTICE,"",0,16,1,addr,len,false);
    52. break;
    53. }
    54. }
    55. }
    56. return 0;
    57. }
    58. static void hello_exit(void) {
    59. printk(KERN_ALERT "exit fishing\n");
    60. }
    61. subsys_initcall(hello_init);
    62. module_exit(hello_exit);
    63. MODULE_LICENSE("GPL");
    64. MODULE_AUTHOR("shakespeare");

    此处只打印了进程第一个vm_area_struct表达的内存。

    通过上述截图对比可知,程序的16进制被严格的加载到进程的内存空间,并且从进程的第一个vm_area_struct结构表达的内存处开始保存。

  • 相关阅读:
    数据分析-统计学
    postgres源码解析27 缓冲池页面置换算法
    关于华为产品生命周期
    操作系统——环境变量
    【6.824】分布式lab1 mapReduce
    Miniconda 使用进阶,把它添加到右键菜单中
    Java中可以用的大数据推荐算法
    用Python剪辑视频?太简单了
    在Vue3+TypeScript 前端项目中使用事件总线Mitt
    华南理工大学电子与信息学院23年预推免复试面试经验贴
  • 原文地址:https://blog.csdn.net/u010049696/article/details/133950852