You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Linux内核中是否存在宏可判断内存地址的分配来源?

Linux内核地址类型判断的方法与宏

Linux内核中没有直接提供ADDR_IS_STACK_ADDR这类统一命名的宏,但可以通过内核原生接口或自定义宏实现地址类型的判断,以下是针对各类地址的具体方案:

1. 判断地址是否来自栈

内核每个进程的栈有固定范围,可通过当前进程的task_struct获取栈起始地址,结合THREAD_SIZE(栈大小)判断:

#include <linux/sched.h>

#define ADDR_IS_STACK_ADDR(ptr) \
  ((unsigned long)(ptr) >= (unsigned long)current->stack && \
   (unsigned long)(ptr) < (unsigned long)current->stack + THREAD_SIZE)
  • 注意:该宏仅适用于当前进程的栈地址判断,若需检查其他进程的栈地址,需替换current为对应进程的task_struct指针。

2. 判断地址是否来自kmalloc

kmalloc分配的内存属于内核线性映射区(直接映射物理内存),不在vmalloc范围内,可通过以下逻辑判断:

#include <linux/vmalloc.h>

#define ADDR_IS_KMALLOC_ADDR(ptr) \
  (is_kernel_addr((unsigned long)(ptr)) && \
   !is_vmalloc_addr((unsigned long)(ptr)))
  • 若需更精准判断,可结合slab分配器接口kmem_cache_find,但上述宏已满足大部分场景需求。

3. 判断地址是否来自vmalloc

内核直接提供is_vmalloc_addr()宏(定义于<linux/vmalloc.h>),可直接用于判断:

#include <linux/vmalloc.h>

if (is_vmalloc_addr(v)) {
    pr_debug("%p is allocated via vmalloc\n", v);
}

4. 判断地址是否来自.text段(函数指针)

内核代码段的起始和结束由_text、_etext符号标记,可通过对比地址区间判断:

extern char _text[], _etext[];

#define ADDR_IS_TEXT_ADDR(ptr) \
  ((unsigned long)(ptr) >= (unsigned long)_text && \
   (unsigned long)(ptr) < (unsigned long)_etext)
  • 若需判断内核模块的代码段地址,需使用is_module_addr()宏(定义于<linux/module.h>)。

5. 其他地址分类判断

  • 内核模块地址:使用is_module_addr()宏直接判断地址是否属于已加载的内核模块。
  • 用户空间地址:可通过access_ok()接口,或检查地址是否小于PAGE_OFFSET(不同架构略有差异,如x86_64使用TASK_SIZE_MAX)。
  • 物理直接映射区(如__get_free_pages分配):同kmalloc地址逻辑,属于内核线性映射区,virt_to_phys()可直接转换为物理地址。

示例代码(修改为实际可用版本)

#include <linux/sched.h>
#include <linux/slab.h>
#include <linux/vmalloc.h>
#include <linux/printk.h>
#include <linux/module.h>

extern char _text[], _etext[];

#define ADDR_IS_STACK_ADDR(ptr) \
  ((unsigned long)(ptr) >= (unsigned long)current->stack && \
   (unsigned long)(ptr) < (unsigned long)current->stack + THREAD_SIZE)

#define ADDR_IS_KMALLOC_ADDR(ptr) \
  (is_kernel_addr((unsigned long)(ptr)) && \
   !is_vmalloc_addr((unsigned long)(ptr)))

#define ADDR_IS_TEXT_ADDR(ptr) \
  ((unsigned long)(ptr) >= (unsigned long)_text && \
   (unsigned long)(ptr) < (unsigned long)_etext)

void foo()
{
    int bar;
    void *v = vmalloc(123);
    void *k = kmalloc(123, GFP_KERNEL);

    if (ADDR_IS_STACK_ADDR(&bar))
        pr_debug("%p is on the stack\n", &bar);
    if (k && ADDR_IS_KMALLOC_ADDR(k))
        pr_debug("%p is from kmalloc\n", k);
    if (v && is_vmalloc_addr(v))
        pr_debug("%p is from vmalloc, physical addr: %p\n", 
                 v, virt_to_phys(v));
    if (ADDR_IS_TEXT_ADDR(foo))
        pr_debug("%p is in .text section\n", foo);

    kfree(k);
    vfree(v);
}

内容的提问来源于stack exchange,提问作者KJ7LNW

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.06.21 10:11:18