从内存读取并获取 char 数组。如果其中包含 1 个字节的 char 假定为 1 字节长度并且长度是一个数字,该怎么办

发布于 2025-01-13 06:02:15 字数 3240 浏览 0 评论 0原文

所以我正在读取 C 中应该是 BIOS 信息的内存。通过通常的读取,我得到一堆字符......这个想法是这些字符正在创建诸如锚“字符串”和 1 字节校验和和 1 字节长度之类的字段。但在C中数字是int或long。 INT 为 4 个字节。但我有 char 代表校验和,长度只占用 1 个字节(1 个字符 == 0x00 1 个字节如何将其读取为 int)

我正在这样做。 unsigned char checksum=mem[0];前1个字节字符代表校验和。但是校验和应该是一个数字,应该是unsigned int checksum = mem[0]..打印它打印0

然后继续这就是我如何从我的char数组获取1字节长度mem 位于索引 1 处。

length = mem[1];
//int x=mem[2]; 

假设如果我有两个字节数(字长数据)表示最大大小,我会在字符数组的索引 4 处这样做。

    char x1[3];
    memcpy(x1,&mem[4],2);
    x1[2]='\0';
    long v=strtol(x1,'\0',16);
    

上面显然是打印了我的最大值的错误结果尺寸。打印 0。而且看起来也不太对劲。 long 是 8 个字节,但我有两个字节应该代表 BIOS 中的最大大小字段。

以上可能只是错误的想法,如果我相信它是正确的或错误的。事实是我真的不知道如何处理这种转换。任何人都可以告诉我上面是错误的还是正确的。或者对我想要实现的目标有意义

这是我试图从 BIOS 中提取的 2.1 表信息。我的锚字符串打印正确,但数字字段打印不正确,我得到的最大尺寸为 0。长度为 31

https://www.dmtf.org /sites/default/files/standards/documents/DSP0134_3.0.0.pdf

这是代码

void get_it(char *arr)
{

    char *mem = (unsigned char *) &arr[0];
    int length, i;
    unsigned char checksum=mem[0];
    printf("checksum %d\n",checksum);
    
    length = mem[1];
    int x=mem[2];
    int y=0;
    y=mem[3];
    
    
    
    printf("\nlength = %d version = %x\n minor version = %d",length,x,mem[3]);
    char x1[3];
    memcpy(x1,&mem[4],2);
    x1[2]='\0';
    long v=strtol(x1,'\0',16);
    
    printf("max size %lx\n",v);
    printf("entry point revision = %d\n",mem[6]);
    printf("~~ %c %c %c %c %c\n",mem[12],mem[13],mem[14],mem[15],mem[16]);  
    /*checksum = 0;
    for(i = 0; i < length; i++) 
    {
       checksum += mem[i];
    }
    
    if(checksum == 0) break;
    
    mem += 16;
    */

    mem=mem+length;
    char type=*mem;
    printf("first type = %d",*mem);
    printf("length = %d",*(mem+1));
    
    int j=0;
    
    
    


}



int main()
{

    int fd=open("/dev/mychardev-0",O_RDWR);
    if(fd<=0)
    {   
        printf("fd %d\n",fd);
        exit(0);

    }

    size_t length=1048576;
    size_t x=0;
    char *buffer=malloc(sizeof(char )*length);
    while(x<length)
    {
        int valread=read(fd,buffer,length);
        printf("here\n");
        if(valread==0)
        {
            printf("zero bytes read\n");
            
            break;
        }
    
        if(valread<0)
        {
            printf("read return negative %d %d\n",valread,errno);

            break;
        }
        x=x+valread;
        
    }
    if(x>0)
    {
        size_t y=0;
        while(y<x)
        {

            if(*(buffer+y)=='_' && *(buffer+y+1)=='S' && *(buffer+y+2)=='M' && *(buffer+y+3)=='_')
            {
                                                
                
                printf("%c\n",buffer[y]);
                printf("%c\n",buffer[y+1]);
                printf("%c\n",buffer[y+2]);
                buffer=buffer+4;
                get_it(buffer);

            }
            y++;

        }
        printf("%x\n",buffer);
    }
    else
    {
        printf("ops no read\n");
    }
    return 0;
}

So I am reading memory that suppose to be bios info in C. And with usual read I get bunch of characters that.. The idea is those characters are making fields like Anchor "String" and 1 byte checksum and 1 Byte Length. But in C number is int or long. INT is 4 bytes. But I have char representing checksum and length is just taking 1 byte (1 character == 0x00 1 byte how to read it as int)

I am doing it like this . unsigned char checksum=mem[0]; first 1 byte character represent checksum. But check sum suppose to be a number which should be unsigned int checksum = mem[0].. The printing it prints 0

Then moving on this is how I get 1 byte length from my char array mem at index 1.

length = mem[1];
//int x=mem[2]; 

And suppose If I have two byte number (Word length data) representing max size I am doing it like this at index 4 in my character array..

    char x1[3];
    memcpy(x1,&mem[4],2);
    x1[2]='\0';
    long v=strtol(x1,'\0',16);
    

Above is obviously printing wrong result for my max size. printing 0. And it does not seems all right either. long is 8 bytes But I have two byte that should represent my max size field in bios.

May be above is just wrong thinking that if I believe its correct or wrong. the fact is I really dont know how to handle this sort of conversion. Can any one please let me is above is wrong or correct. Or makes sense for what I like to achieve

This is 2.1 table info from bios I am trying to extract. My anchor strings are printing correct but number fields not printing correct I am gett 0 for max size. 31 for length

https://www.dmtf.org/sites/default/files/standards/documents/DSP0134_3.0.0.pdf

This is the code

void get_it(char *arr)
{

    char *mem = (unsigned char *) &arr[0];
    int length, i;
    unsigned char checksum=mem[0];
    printf("checksum %d\n",checksum);
    
    length = mem[1];
    int x=mem[2];
    int y=0;
    y=mem[3];
    
    
    
    printf("\nlength = %d version = %x\n minor version = %d",length,x,mem[3]);
    char x1[3];
    memcpy(x1,&mem[4],2);
    x1[2]='\0';
    long v=strtol(x1,'\0',16);
    
    printf("max size %lx\n",v);
    printf("entry point revision = %d\n",mem[6]);
    printf("~~ %c %c %c %c %c\n",mem[12],mem[13],mem[14],mem[15],mem[16]);  
    /*checksum = 0;
    for(i = 0; i < length; i++) 
    {
       checksum += mem[i];
    }
    
    if(checksum == 0) break;
    
    mem += 16;
    */

    mem=mem+length;
    char type=*mem;
    printf("first type = %d",*mem);
    printf("length = %d",*(mem+1));
    
    int j=0;
    
    
    


}



int main()
{

    int fd=open("/dev/mychardev-0",O_RDWR);
    if(fd<=0)
    {   
        printf("fd %d\n",fd);
        exit(0);

    }

    size_t length=1048576;
    size_t x=0;
    char *buffer=malloc(sizeof(char )*length);
    while(x<length)
    {
        int valread=read(fd,buffer,length);
        printf("here\n");
        if(valread==0)
        {
            printf("zero bytes read\n");
            
            break;
        }
    
        if(valread<0)
        {
            printf("read return negative %d %d\n",valread,errno);

            break;
        }
        x=x+valread;
        
    }
    if(x>0)
    {
        size_t y=0;
        while(y<x)
        {

            if(*(buffer+y)=='_' && *(buffer+y+1)=='S' && *(buffer+y+2)=='M' && *(buffer+y+3)=='_')
            {
                                                
                
                printf("%c\n",buffer[y]);
                printf("%c\n",buffer[y+1]);
                printf("%c\n",buffer[y+2]);
                buffer=buffer+4;
                get_it(buffer);

            }
            y++;

        }
        printf("%x\n",buffer);
    }
    else
    {
        printf("ops no read\n");
    }
    return 0;
}

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

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

发布评论

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

评论(1

旧人哭 2025-01-20 06:02:15

但在 C 中数字是 int 或 long。

char 整数类型,可用于表示数字,与shortint长。

它的最大值为 CHAR_MAX

一个问题是 char 的符号是实现定义的。如有疑问,请明确使用 signed char (SCHAR_MAX) 或 unsigned char (UCHAR_MAX)。

或者,使用 固定宽度整数类型 可以更轻松地推断字节您正在使用的数据的宽度。

EPS 表中的字段的大小表示为 BYTE、WORD 和 DWORD。这些可以分别用 uint8_tuint16_tuint32_t 表示,因为您几乎肯定需要无符号整数。


此代码

char x1[3];
memcpy(x1,&mem[4],2);
x1[2]='\0';
long v=strtol(x1,'\0',16);

printf("max size %lx\n",v);

尝试将最大结构大小解析为由两个字符表示的数字,这是不正确的。 最大结构大小是一个 16 位整数

mem=mem+length; 没有多大意义,因为这会将您置于表格之外的内存中。我不确定接下来的两个 printf 调用正在尝试打印什么。

此外,您的示例包含一些错误代码(未使用的变量:iyj)。

其他一切都或多或少是正确的,尽管有些混乱。


下面是一个看起来可以在我的机器上运行的简单示例,使用 smbios_entry_point 表文件。您应该能够使用它作为参考来相应地调整您的程序。

$ uname -rmo
5.14.21-210.current x86_64 GNU/Linux
#include <fcntl.h>
#include <inttypes.h>
#include <stdint.h>
#include <stdio.h>
#include <string.h>
#include <unistd.h>

#define EPS_SIZE 31
#define TARGET_FILE "/sys/firmware/dmi/tables/smbios_entry_point"

void print_buffer(uint8_t *eps) {
    printf("Anchor string: %c%c%c%c\n", eps[0], eps[1], eps[2], eps[3]);
    printf("Checksum: %02Xh\n", eps[4]);
    printf("Entry point length: %02Xh\n", eps[5]);
    printf("Major version: %02Xh\n", eps[6]);
    printf("Minor version: %02Xh\n", eps[7]);

    uint16_t mss;
    memcpy(&mss, eps + 8, sizeof mss);
    printf("Maximum structure size: %" PRIu16 " bytes\n", mss);

    printf("Entry point revision: %02Xh\n", eps[10]);
    printf("Formatted area: %02Xh %02Xh %02Xh %02Xh %02Xh\n",
            eps[11], eps[12], eps[13], eps[14], eps[15]);
    printf("Intermediate anchor string: %c%c%c%c%c\n",
            eps[16], eps[17], eps[18], eps[19], eps[20]);
    printf("Intermediate checksum: %02Xh\n", eps[21]);

    uint16_t stl;
    memcpy(&stl, eps + 22, sizeof stl);
    printf("Structure table length: %" PRIu16 " bytes \n", stl);

    uint32_t sta;
    memcpy(&sta, eps + 24, sizeof sta);
    printf("Structure table address: 0x%08x\n", sta);

    uint16_t nsmbs;
    memcpy(&nsmbs, eps + 28, sizeof nsmbs);
    printf("Number of SMBIOS structures: %" PRIu16 "\n", nsmbs);

    printf("SMBIOS BCD revision: %02Xh %02Xh\n",
            eps[30] >> 4, eps[30] & 0x0f);
}

int main(void) {
    uint8_t buf[EPS_SIZE];
    int fd = open(TARGET_FILE, O_RDONLY);

    read(fd, buf, sizeof buf);
    close(fd);

    print_buffer(buf);
}

stdout:

Anchor string: _SM_
Checksum: C2h
Entry point length: 1Fh
Major version: 02h
Minor version: 07h
Maximum structure size: 184 bytes
Entry point revision: 00h
Formatted area: 00h 00h 00h 00h 00h
Intermediate anchor string: _DMI_
Intermediate checksum: DCh
Structure table length: 2229 bytes
Structure table address: 0x000ed490
Number of SMBIOS structures: 54
SMBIOS BCD revision: 02h 07h

您可能还对 dmidecode 及其源代码感兴趣。

But in C number is int or long.

char is an integral type which can be used to represent numbers, the same as short, int or long.

It has a maximum value of CHAR_MAX.

One problem is that the signedness of char is implementation-defined. When in doubt, be explicit with signed char (SCHAR_MAX) or unsigned char (UCHAR_MAX).

Alternatively, use fixed width integer types to make it easier to reason about the byte width of the data you are working with.

The fields in the EPS table are denoted as being of size BYTE, WORD, and DWORD. These can be represented by uint8_t, uint16_t, and uint32_t respectively, as you almost certainly want unsigned integers.


This code

char x1[3];
memcpy(x1,&mem[4],2);
x1[2]='\0';
long v=strtol(x1,'\0',16);

printf("max size %lx\n",v);

that attempts to parse the Maximum Structure Size as if it were a number represented by two characters is incorrect. The Maximum Structure Size is a 16-bit integer.

mem=mem+length; does not make much sense, as this would place you in memory beyond the table. I am not sure what the two printf calls that follow are trying to print.

Additionally, your example includes some errant code (unused variables: i, y, j).

Everything else is more-or-less correct, if messy.


Below is a simple example that seemingly works on my machine, using the smbios_entry_point table file. You should be able to use it as reference to adjust your program accordingly.

$ uname -rmo
5.14.21-210.current x86_64 GNU/Linux
#include <fcntl.h>
#include <inttypes.h>
#include <stdint.h>
#include <stdio.h>
#include <string.h>
#include <unistd.h>

#define EPS_SIZE 31
#define TARGET_FILE "/sys/firmware/dmi/tables/smbios_entry_point"

void print_buffer(uint8_t *eps) {
    printf("Anchor string: %c%c%c%c\n", eps[0], eps[1], eps[2], eps[3]);
    printf("Checksum: %02Xh\n", eps[4]);
    printf("Entry point length: %02Xh\n", eps[5]);
    printf("Major version: %02Xh\n", eps[6]);
    printf("Minor version: %02Xh\n", eps[7]);

    uint16_t mss;
    memcpy(&mss, eps + 8, sizeof mss);
    printf("Maximum structure size: %" PRIu16 " bytes\n", mss);

    printf("Entry point revision: %02Xh\n", eps[10]);
    printf("Formatted area: %02Xh %02Xh %02Xh %02Xh %02Xh\n",
            eps[11], eps[12], eps[13], eps[14], eps[15]);
    printf("Intermediate anchor string: %c%c%c%c%c\n",
            eps[16], eps[17], eps[18], eps[19], eps[20]);
    printf("Intermediate checksum: %02Xh\n", eps[21]);

    uint16_t stl;
    memcpy(&stl, eps + 22, sizeof stl);
    printf("Structure table length: %" PRIu16 " bytes \n", stl);

    uint32_t sta;
    memcpy(&sta, eps + 24, sizeof sta);
    printf("Structure table address: 0x%08x\n", sta);

    uint16_t nsmbs;
    memcpy(&nsmbs, eps + 28, sizeof nsmbs);
    printf("Number of SMBIOS structures: %" PRIu16 "\n", nsmbs);

    printf("SMBIOS BCD revision: %02Xh %02Xh\n",
            eps[30] >> 4, eps[30] & 0x0f);
}

int main(void) {
    uint8_t buf[EPS_SIZE];
    int fd = open(TARGET_FILE, O_RDONLY);

    read(fd, buf, sizeof buf);
    close(fd);

    print_buffer(buf);
}

stdout:

Anchor string: _SM_
Checksum: C2h
Entry point length: 1Fh
Major version: 02h
Minor version: 07h
Maximum structure size: 184 bytes
Entry point revision: 00h
Formatted area: 00h 00h 00h 00h 00h
Intermediate anchor string: _DMI_
Intermediate checksum: DCh
Structure table length: 2229 bytes
Structure table address: 0x000ed490
Number of SMBIOS structures: 54
SMBIOS BCD revision: 02h 07h

You may also be interested in dmidecode and its source code.

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