【问题标题】:Assign a value to a specific address为特定地址赋值
【发布时间】:2011-03-23 01:56:11
【问题描述】:

这是一个面试问题,我是在一本面试书上遇到的,后来在一次面试中。

问题是

如何将值(例如 0)分配给地址(例如 0x12345678)。

我对这个问题的最佳尝试(经过很长时间的面试)是

地址是一个可以存储在指针中的数字,我们可以通过指针给地址赋值,指针的值就是地址,比如:

         int* p = 0x12345678;
         *p = 0;

但是,在具有内存管理的系统上是不可能的,因为程序没有特定地址的特权。

根据我自己的经验,这种操作唯一有效的一次是在没有任何操作系统的8086芯片上进行实验,当时我使用的语言是汇编。

请帮助我更正、改进和完善我的答案。谢谢。

【问题讨论】:

    标签: memory-address


    【解决方案1】:

    您的代码是正确的,但如果操作系统将 0x12345678 定义为只读,则可能会在运行时崩溃。

    虽然“常规”操作系统会这样做,但“更轻”的操作系统不会。

    您想编写一个内核空间黑客程序来完成它。

    如果你想看看,我已经为 linux 解决了:


    1)构建这个模块(example.ko):

    #include <linux/module.h>
    #include <linux/fs.h>       /* for file_operations  */
    #include <linux/uaccess.h>  /* copy_from & copy_to  */
    
    char*   g_value=0;
    size_t  size =0; 
    
    int driver_open(struct inode *inode, struct file *filp)
    {
        printk("open driver");
        return 0;
    }
    
    int driver_write(struct file*,          /*ignored*/
                    const char __user *umem,/*source in user-space's address*/
                    size_t size,            /*max size to be writen*/
                    loff_t*)                /*offset - ignored*/
    {
        unsigned long ret = 0;
    
        g_value = (char*) kmalloc(size, GFP_KERNEL);
    
        if (!g_value)
        {
            printk("ERROR:allocation failure\n");
            return -ENOMEM;
        }
    
        ret = copy_from_user(g_value,   /*destination*/
                            umem,       /*source*/
                            size);      /*size*/
    
        if (ret<0)
        {
            printk("ERROR:copy failure\n");
            return -EACCES;
        }
    
        return g_size = size;;
    }
    
    int driver_read(struct file*,       /*ignored*/
                     char __user *umem, /*destination in user-space's address*/
                     size_t size,       /*max size to be read*/
                     loff_t*)           /*offset - ignored*/
    {
    
        /*  don't use copy_to_user(umem,    &value, size)!!
            we want to do exectly what it is made to protect from */
    
        int i = ((g_size>size)?size:g_size)-1; /*MIN(g_size,size)-1*/
        for (; i>=0; --i)
        {
            umem[i]=g_value[i]; /*can be done more effectively, thats not the point*/
        }
    
        return size;
    }
    
    int driver_close(struct inode *inode, struct file *filp)
    {
        if (g_value)
            free(g_value);
        g_value = 0;
        printk("close driver");
        return 0;
    }
    
    /***interface***/
    
    struct file_operations driver_ops = {
        open: driver_open,
        write: driver_write,
        read:  driver_read,
        release: driver_close
    };
    
    /***implementation***/
    
    static int g_driver_fd = 0;
    
    static void driver_cleanup(void) 
    {
        printk("ERROR:driver exit\n");
        unregister_chrdev(g_driver_fd, "driver");
    }
    
    static int driver_init(void)
    {
    
        printk("driver init\n");
        g_driver_fd =  register_chrdev(0,"ROM-bypass", &driver_ops);
        if (g_driver_fd<0)
        {
            printk("ERROR:failed to register char driver\n");
            return -1;
        }
        return 0;
    }
    
    module_init(driver_init);
    module_exit(driver_cleanup);
    
    /***documentation***/
    
    MODULE_DESCRIPTION("write on OS's \"read only\" segment");
    MODULE_AUTHOR("Elkana Bronstein");
    MODULE_LICENSE("GPL");
    

    2) 将其添加到内核模块中:

    $insmod example.ko
    

    3) 在列表中找到模块的“主要”:

    $cat /proc/devices
    

    4) 使节点与设备关联:

    $mknod /dev/rom_bypass  c <major> <minor>
    

    'c' 用于字符设备,'minor' 可以是 0-255 中的任何一个

    5) 将代码中的设备用作文件:

    int main()
    {
    
        int fd;
        int value = 0;
    
        fd = open("/dev/rom_bypass",O_RDWR);    
        if (fd<0)
        {
            fprintf(stderr,"open failed");
            return -1;
        }
    
        /*write the desirable value into the device's buffer*/
        write(fd,&value,sizeof(value));
        /*read the device's buffer into the desirable object - without checking*/
        read(fd,0x12345678,sizeof(value));
    
        close(fd);
    }
    

    【讨论】:

      【解决方案2】:

      (几乎)不可能知道哪些内存位置可以写入。

      您可以使用 malloc() 函数请求操作系统为您提供可用地址,然后使用 free() 释放该位置。

      另一种方法是使用堆栈内存。只需定义一个变量 int *p = 0; &p 会给你这个位置的地址。

      如果您尝试将值分配给不可用的位置,则可能会出现分段错误错误。

      希望这会有所帮助!

      【讨论】:

      • 哦,我刚看到日期。我猜我迟到了 2 年:P
      【解决方案3】:

      即使在具有内存管理的系统中,这种事情也绝对是可能的,如果指针在当前进程的可访问空间之外,它就会出错,但这是应该发生的。如果没有,则设置该值,然后继续。除此之外,你的例子对我来说似乎很好。

      【讨论】:

      • 所以可能,你的意思是它可以编译但运行时异常执行?
      【解决方案4】:

      也许答案是没有答案,因为在具有内存管理的系统中这是不可能的。

      在没有内存管理的系统中,我会直接尝试使用汇编代码。

      希望对你有帮助

      【讨论】:

      • 这些实际上都包含在我的问题中。我想知道,对于像这样的(开放式)问题,我应该谈什么。
      猜你喜欢
      • 2017-09-07
      • 2021-12-20
      • 2013-05-06
      • 2013-09-26
      • 2012-08-31
      • 2016-05-18
      • 2013-03-10
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多