将值分配给特定地址

发布于 2024-10-26 14:37:15 字数 510 浏览 0 评论 0原文

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

问题是

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

我对这个问题的最佳尝试(面试后很长一段时间后)是

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

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

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

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

请帮助我纠正、改进和完成我的答案。谢谢。

It is an interview question, which I came across at a book for interviews, and later in an interview.

The question is

How to assign value (say 0) to an address (say 0x12345678).

My best try for this question (after a long time after the interview) is

An address is a number which can be stored in a pointer, and we can assign a value to the address by a pointer, the value of which is the address, like:

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

However, it is not possible on a system with memory management, because the program does not have privilege to the specific address.

According to my own experience, the only time this kind of operation was valid was the experiment on an 8086 chip without any operation system, and the language I used that time was assembly.

Please help me correct, improve and complete my answer. Thanks.

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(5

逆光飞翔i 2024-11-02 14:37:15

您的代码是正确的,但如果操作系统将 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);
}

Your code is correct but might crush on runtime if the OS defines 0x12345678 as read-only.

While a "regular" OS does that, "lighter" ones do not.

You want to write a kernel-space hacking program to do it.

I solved it for linux if you like to take a look:


1) build this module (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) add it to kernels modules:

$insmod example.ko

3) find the module's 'major' in the list:

$cat /proc/devices

4) make node associated with the device:

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

'c' is for character device and 'minor' can be any of 0-255

5) use the device in your code as a file:

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);
}
心凉 2024-11-02 14:37:15

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

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

另一种方法是使用堆栈内存。只需定义一个变量 int *p = 0; &p 将为您提供该位置的地址。

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

希望这有帮助!

It is (nearly) impossible to know which memory locations are available to write to.

You can ask the OS to give you an available address by using malloc() function and later freeing that location up by using free().

Another way is to use the stack memory. Just define a variable int *p = 0; &p will give you the address of this location.

If you try to assign values to locations which are unavailable, you might end up with segmentation fault errors.

Hope this helps!

深海不蓝 2024-11-02 14:37:15

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

That sort of thing most definitely IS possible even in systems with memory management, if the pointer is outside accessible space for the current process, it'll fault, but that's what's supposed to happen. If not, the value is set and on you go. Other than that, you're example seems fine to me.

緦唸λ蓇 2024-11-02 14:37:15

答案是函数-> mmap() 。如果您的设备具有相同的实际地址,则可以将您的虚拟地址映射到实际地址,然后您可以使用虚拟地址进行操作。
在linux中,首先需要通过函数->打开设备内存空间作为文件open(),并设置文件的属性。将缓存页面映射到该虚拟文件并接收指针之后 ->映射()。在使用映射内存空间之前需要通过函数->同步DATA msync()。使用内存后,在关闭程序之前需要取消映射内存缓存 -> munmap() 并关闭虚拟文件 close()。关于详细功能描述请在google中搜索解释:)

The answer is function -> mmap() . If you has same really address of device, it's possible mapping your virtual address to really address and after it you can operate with virtual address.
In linux, firstly need open the device memory space as file by function -> open(), and set perditions of the file. After it mapping caching page to this virtual file and receive pointer -> mmap(). Before using mapping memory space needed synchronize the DATA by function -> msync(). After using the memory, before close program you need unmapping memory cache -> munmap() and close virtual file close(). About detail functions description search explain in google :)

戏剧牡丹亭 2024-11-02 14:37:15

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

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

希望有帮助

Maybe the answer is that there is no answer because it is impossible in a system with memory management.

In a system without memory management I would try with assembly code directly.

Hope it helps

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文