BPF verifier throws error "BPF program is too large" - c

I am trying to define a struct and trying to perform XOR encryption on it using a key of 2 bytes.
static __always_inline long int encrypt_decrypt(struct ipv6_destopt_pdmv2_unencrypted *pdm)
{
// xor all fields after flip bit with a key of size 2 bytes
__u16 key = 0x1234;
__u32 key1 = key << 16 | key;
// get first 8 bits of key
__u8 key2 = key >> 8;
__u8 key3 = key & 0xFF;
example_struct->a = example_struct->a ^ key2;
example_struct->b = example_struct->b ^ key3;
example_struct->c = example_struct->c ^ key1;
example_struct->d = example_struct->d ^ key;
example_struct->e = example_struct->e ^ key;
example_struct->f = example_struct->f ^ key;
example_struct->g = example_struct->g ^ key;
return 0;
}
The struct example_struct is given by,
struct example_struct
{
__u8 u;
__u8 v;
__u16 x;
__u16 y;
// following fields are encrypted
__u8 a;
__u8 b;
__u32 c;
__u16 d;
__u16 e;
__u16 f;
__u16 g;
__uint128_t more_stuff_1;
__u8 more_stuff_2;
__u8 more_stuff_3;
};
When I comment out the line example_struct->a = example_struct->a ^ key2;, the verifier does not throw any error, but when I include this one line, the verifier throws the error processed 1000001 instructions, bpf program too large. The number of instructions it shows when it throws this error in the bpf program itself is 534. Why is this happening?

Related

Dynamically Populate Struct in C

Say you have a struct in C:
typedef struct ID_Info {
uint16_t model_number;
uint16_t serial_number;
uint16_t firmware_version;
} ;
ID_Info id_info;
Now, say I need to set each uint16 variable in this struct to the values of data received byte by byte. So for example, if I received the following bytes: 0x00, 0x11, 0x22, 0x33, 0x44 and 0x55 in some data array data[], I now need to set the values as follows:
id_info.model_number = data[1]*256 + data[0]; // 0x1100
id_info.serial_number = data[3]*256 + data[2]; // 0x3322;
id_info.firmware_version = data[5]*256 + data[4]; // 0x5544;
This is easy enough to hard code as shown above. However, I'd like to be able to do this without hard-coding values and iteratively if possible. Therefore, if I needed to add a variable to the struct, my code and loop would automatically know I need to iterate for two more bytes (assuming a unit16). So this loop would need to iterate foreach member in the struct. Furthermore, is there a way to infer the variable type to know how many bytes I need? Say I needed to add a uint8, and in this case the code could know I only need one byte.
So maybe the pseudo-code would look something like this:
int i = 0;
foreach(member in id_info)
if(member is uint8)
id_info.member = data[i];
i =+ 1;
else if (member is uint16)
id_info.member = data[i] + 256*data[i+1];
i =+ 2;
else
throw error
This way I could easily add and removed struct members without many changes to the code. Thanks in advance for any insight!
If it's not a performance issue (your sample data looks like it isn't), instead of a hard-coded structure with C types, you could define a structure where the type information is encoded, perhaps based on an enum, the name information as a string, and that along with a large enough value type.
The enum type might look like this:
typedef enum {
ui16, ui8
} Type;
One entry could be defined as:
struct entry {
Type type;
char *name;
long value;
};
It is assumed that long is large enough for the largest data type.
A small, self-contained C test program based on your example might then look like the following:
#include <stdio.h>
typedef enum {
ui16, ui8
} Type;
struct entry {
Type type;
char *name;
long value;
};
struct entry id_info[] = {
{ui16, "model_number", 0},
{ui16, "serial_number", 0},
{ui16, "firmware_version", 0}
};
int main(void) {
unsigned char data[] = {0x00, 0x11, 0x22, 0x33, 0x44, 0x55};
int x = 0;
for (int i = 0; i < sizeof(id_info) / sizeof(id_info[0]); i++) {
struct entry *current = &id_info[i];
switch (current->type) {
case ui8:
current->value = data[x];
x++;
break;
case ui16:
current->value = data[x] + 256 * data[x + 1];
x += 2;
break;
}
}
//and now print it
for (int i = 0; i < sizeof(id_info) / sizeof(id_info[0]); i++) {
struct entry *current = &id_info[i];
switch (current->type) {
case ui8:
printf("uint8_t %s: %02lx\n", current->name, current->value);
break;
case ui16:
printf("uint16_t %s: %04lx\n", current->name, current->value);
break;
}
}
return 0;
}
The program would produce the following output on the debug console:
uint16_t model_number: 1100
uint16_t serial_number: 3322
uint16_t firmware_version: 5544
One way to do this is with preprocessor macros.
With this method, it is easy to add new elements. And, the import/export functions will be automatically updated.
#ifndef NOINC
#include <stdio.h>
#include <stdint.h>
#include <stddef.h>
#endif
// define all struct members
#define ALLSTRUCT(_cmd) \
_cmd(uint16_t,"%u",model_number) \
_cmd(uint16_t,"%u",serial_number) \
_cmd(uint16_t,"%u",firmware_version)
// define symbol
#define SYMDEF(_typ,_fmt,_sym) \
_typ _sym;
// define struct
typedef struct ID_Info {
ALLSTRUCT(SYMDEF)
} ID_Info;
ID_Info id_info;
// deserialize
#define SYMIN(_typ,_fmt,_sym) \
do { \
str->_sym = *(_typ *) ptr; \
ptr += sizeof(_typ); \
} while (0);
// serialize
#define SYMOUT(_typ,_fmt,_sym) \
do { \
*(_typ *) ptr = str->_sym; \
ptr += sizeof(_typ); \
} while (0);
// print
#define SYMPRT(_typ,_fmt,_sym) \
printf(" " #_sym "=" _fmt " (%8.8X)\n",str->_sym,str->_sym);
// struct_out -- output struct to byte array
uint8_t *
struct_out(const ID_Info *str,uint8_t *ptr)
{
ALLSTRUCT(SYMOUT)
return ptr;
}
// struct_in -- input struct from byte array
const uint8_t *
struct_in(ID_Info *str,const uint8_t *ptr)
{
ALLSTRUCT(SYMIN)
return ptr;
}
// struct_prt -- print struct to byte array
void
struct_prt(const ID_Info *str)
{
printf("struct_prt:\n");
ALLSTRUCT(SYMPRT)
}
// prtu8 -- print byte array
void
prtu8(const uint8_t *ptr,size_t count,const char *sym)
{
printf("%s:",sym);
for (size_t idx = 0; idx < count; ++idx)
printf(" %2.2X",ptr[idx]);
printf("\n");
}
int
main(void)
{
uint8_t data_in[] = { 0x00, 0x11, 0x22, 0x33, 0x44, 0x55 };
uint8_t data_out[sizeof(data_in)];
// show original byte array
prtu8(data_in,sizeof(data_in),"data_in");
// import data into struct
struct_in(&id_info,data_in);
// show struct values
struct_prt(&id_info);
// export data from struct
struct_out(&id_info,data_out);
// show exported byte array
prtu8(data_out,sizeof(data_out),"data_out");
// reimport the struct data
struct_in(&id_info,data_out);
// show struct data
struct_prt(&id_info);
return 0;
}
Here is the [redacted] preprocessor output:
typedef struct ID_Info {
uint16_t model_number;
uint16_t serial_number;
uint16_t firmware_version;
} ID_Info;
ID_Info id_info;
uint8_t *
struct_out(const ID_Info * str, uint8_t * ptr)
{
do {
*(uint16_t *) ptr = str->model_number;
ptr += sizeof(uint16_t);
} while (0);
do {
*(uint16_t *) ptr = str->serial_number;
ptr += sizeof(uint16_t);
} while (0);
do {
*(uint16_t *) ptr = str->firmware_version;
ptr += sizeof(uint16_t);
} while (0);
return ptr;
}
const uint8_t *
struct_in(ID_Info * str, const uint8_t * ptr)
{
do {
str->model_number = *(uint16_t *) ptr;
ptr += sizeof(uint16_t);
} while (0);
do {
str->serial_number = *(uint16_t *) ptr;
ptr += sizeof(uint16_t);
} while (0);
do {
str->firmware_version = *(uint16_t *) ptr;
ptr += sizeof(uint16_t);
} while (0);
return ptr;
}
void
struct_prt(const ID_Info * str)
{
printf("struct_prt:\n");
printf(" " "model_number" "=" "%u" " (%8.8X)\n", str->model_number, str->model_number);
printf(" " "serial_number" "=" "%u" " (%8.8X)\n", str->serial_number, str->serial_number);
printf(" " "firmware_version" "=" "%u" " (%8.8X)\n", str->firmware_version, str->firmware_version);
}
void
prtu8(const uint8_t * ptr, size_t count, const char *sym)
{
printf("%s:", sym);
for (size_t idx = 0; idx < count; ++idx)
printf(" %2.2X", ptr[idx]);
printf("\n");
}
int
main(void)
{
uint8_t data_in[] = { 0x00, 0x11, 0x22, 0x33, 0x44, 0x55 };
uint8_t data_out[sizeof(data_in)];
prtu8(data_in, sizeof(data_in), "data_in");
struct_in(&id_info, data_in);
struct_prt(&id_info);
struct_out(&id_info, data_out);
prtu8(data_out, sizeof(data_out), "data_out");
struct_in(&id_info, data_out);
struct_prt(&id_info);
return 0;
}
Here is the test program output:
data_in: 00 11 22 33 44 55
struct_prt:
model_number=4352 (00001100)
serial_number=13090 (00003322)
firmware_version=21828 (00005544)
data_out: 00 11 22 33 44 55
struct_prt:
model_number=4352 (00001100)
serial_number=13090 (00003322)
firmware_version=21828 (00005544)

Attempting to allocate a union to a void* in a struct

The goal is to create a structure that contains 3 fields. One of those fields needs to be a uint32_t union but the flags will be different for each element. I believe the best way to do this is to create a separate union for each peripheral and assign it to a void pointer in the parent struct (somehow).
The Current Plan:
//--------------Register for AAA
typedef union
{
struct
{
uint32_t spare : 32; //< Bits 0-31 not used
}Bits;
uint32_t FullData;
}ABC_EMPTY_DATA;
ABC_EMPTY_DATA AAA_Data;
//--------------Register for BBB
typedef union
{
struct
{
uint32_t use32BitColor : 1; //< Bit0
uint32_t enableTimer : 1; //< Bit1
uint32_t fooTheBar : 1; //< Bit2
uint32_t spare : 29; //< Bits 3-31 not used
}Bits;
uint32_t FullData;
}ABC_BBB_DATA;
ABC_EMPTY_DATA BBB_Data;
//--------------Register for CCC
typedef union
{
struct
{
uint32_t useInternalFrameTick : 1; //< Bit0
uint32_t useExternalFrameTick : 1; //< Bit1
uint32_t spare : 30; //< Bits 2-31 not used
}Bits;
uint32_t FullData;
}ABC_CCC_DATA;
ABC_CCC_DATA CCC_Data;
//-------The Peripherals with register element
typedef struct
{
char *Name;
unsigned int HexCmd;
void *Data; //Connect to corasponding XXXX_Data
}ABC_dataStructs;
//----- Initializing Peripherals
typedef struct
{
ABC_dataStructs AAA = {.Name = "AAA", .HexCmd = 0x00, .Data = (void*) &AAA_Data};
ABC_dataStructs BBB = {.Name = "BBB", .HexCmd = 0x00, .Data = (void*) &BBB_Data};
ABC_dataStructs CCC = {.Name = "CCC", .HexCmd = 0x00, .Data = (void*) &CCC_Data};
}ABC_CommandList;
void main(){
ABC_CommandList everything;
everything.CCC.FullData = 0x000F;
everything.BBB.use32BitColor = 0;
int myint = everything.AAA.HexCmd;
}
Currently, I am having initializeing the values within the struct
ABC_dataStructs AAA = {.Name = "AAA", .HexCmd = 0x00, .Data = (void*) &AAA_Data};
is invalid
Also and more importantly the assigning of the union is not working as intended. The current result only allows for everything.AAA.Data without being able to assign/read individual bits.
I also tried to explain the intent of the SW in order to avoid an "XY problem" and if I am approaching this wrong or you think of something better let me know. Thank You.
Note: C struct, union pointer to struct has another approach of putting structs in the unions instead of unions to the structs, but it doesn't help with my main issue of assigning these to a void*
The problem you're having with the initialization is that you're defining a type and attempting to initialize it as if it's a variable at the same time. You need to first define the struct, then initialize an instance of it:
typedef struct
{
ABC_dataStructs AAA;
ABC_dataStructs BBB;
ABC_dataStructs CCC;
}ABC_CommandList;
void main(){
ABC_CommandList everything = {
.AAA = {.Name = "AAA", .HexCmd = 0x00, .Data = &AAA_Data},
.BBB = {.Name = "BBB", .HexCmd = 0x00, .Data = &BBB_Data},
.CCC = {.Name = "CCC", .HexCmd = 0x00, .Data = &CCC_Data},
};
...
Note also that it's not required to cast to/from a void *.
Then the problem here:
everything.CCC.FullData = 0x000F;
everything.BBB.use32BitColor = 0;
Is that CCC and BBB are of type ABC_dataStructs, and that type does not have fields named FullData or use32BitColor. You would need to cast the Data member to the proper pointer type, then dereference that:
((ABC_CCC_DATA *)everything.CCC.Data)->FullData = 0x000F;
((ABC_BBB_DATA *)everything.BBB.Data)->use32BitColor = 0;
All that being said, there's a better way of modeling this data. What you really want is a union of the 3 register types. Then ABC_dataStructs would contain that union along with a separate field which flags which union to use.
typedef struct
{
uint32_t spare : 32; //< Bits 0-31 not used
} ABC_EMPTY_DATA;
typedef struct
{
uint32_t use32BitColor : 1; //< Bit0
uint32_t enableTimer : 1; //< Bit1
uint32_t fooTheBar : 1; //< Bit2
uint32_t spare : 29; //< Bits 3-31 not used
} ABC_BBB_DATA;
typedef struct
{
uint32_t useInternalFrameTick : 1; //< Bit0
uint32_t useExternalFrameTick : 1; //< Bit1
uint32_t spare : 30; //< Bits 2-31 not used
} ABC_CCC_DATA;
typedef struct
{
char *Name;
unsigned int HexCmd;
union {
ABC_EMPTY_DATA AAA;
ABC_BBB_DATA BBB;
ABC_CCC_DATA CCC;
uint32_t FullData;
};
}ABC_dataStructs;
Then you can define the following:
ABC_CommandList everything = {
.AAA = {.Name = "AAA", .HexCmd = 0x00, .AAA = {}},
.BBB = {.Name = "BBB", .HexCmd = 0x00, .BBB = { .use32BitColor = 0 }},
.CCC = {.Name = "CCC", .HexCmd = 0x00, .FullData = 0x000F },
};

What are for square brackets in an addressed-of pointer?

I've been searching for a while what are for square-brackets in an addressed-of pointer, but I continue without understanding it. Here are the lines of the function, where "id" variable is an uint32_t pointer that has been previously passed as an argument.
#define LIST_STARTED (0x0001) /*defined out of the function*/
#define LIST_FIRST (0x0002) /*defined out of the function*/
uint32_t *pointer = id;
uint16_t *flags = &((uint16_t *)pointer)[0];
uint16_t *index = &((uint16_t *)pointer)[1];
bool started = *flags & LIST_STARTED;
bool first = *flags & LIST_FIRST;
if (!started){
/* does something */
*flags = MSEC_PRM_MGMT_LIST_STARTED;
return true;
}
if (!first){
/* does something */
*flags |= MSEC_PRM_MGMT_LIST_FIRST;
*index = 1;
return true;
}
if (*index == final_index)
/* does something */
return false;
*index += 1;
I understand what the logic of the function is, but I don't understand what do the following lines. I put "all" the code above in case it helps you.
uint16_t *flags = &((uint16_t *)pointer)[0];
uint16_t *index = &((uint16_t *)pointer)[1];
I would appreciate if someone could help me!
Thank you!
I edit to say that this C code works fine in an Embedded System, I'm not modifying it, I was just watching its behaviour.
The following code tries to read a uint32_t object as an array of two uint16_t objects:
uint32_t *id = ...;
uint32_t *pointer = id;
uint16_t *flags = &((uint16_t *)pointer)[0];
uint16_t *index = &((uint16_t *)pointer)[1];
and that is undefined behaviour to read a uint32_t object as 2 uint16_t objects through flags and index pointers because that breaks strict aliasing rules.
The correct way is:
uint16_t flags = *id; // The lowest order bits of id.
uint16_t index = *id >> 16; // The highest order bits of id.
In the above assignments of uint32_t to uint16_t it truncates the highest order bits of id.
uint32_t *pointer = id;
uint16_t *flags = &((uint16_t *)pointer)[0];
it is an equivalent of.
uint32_t *pointer = id;
uint16_t *flags = (uint16_t *)pointer;
The definition:
uint16_t *index = &((uint16_t *)pointer)[1];
Is an equivalent of:
uint16_t *temp = (uint16_t *)pointer;
uint16_t *index = temp + 1;
//or
uint16_t *index = &temp[1];
This is called: pointer punning and it is considered dangerous and not portable.
You can use unions for safe punning (at least when using gcc or its derivatives)
typedef union
{
uint64_t u64;
uint32_t u32[2];
uint16_t u16[4];
uint8_t u8[8];
struct
{
uint8_t n1: 4;
uint8_t n2: 4;
}u4[8];
}union_pune_t;
uint16_t foo16(uint32_t *p32)
{
union_pune_t *d64 = (void *)p32;
return d64 -> u16[1];
}
uint8_t foo8(uint32_t *p32)
{
union_pune_t *d64 = (void *)p32;
return d64 -> u8[5];
}
uint8_t foon4(uint32_t *p32)
{
union_pune_t *d64 = (void *)p32;
return d64 -> u4[9].n2;
}

Enabling paging causes PAGE_FAULT immeditially after setting flag on cr0

I'm working on own OS, it's a lot of fun but i'm stucked with paging, I had wrote simple(very simple) pagination code, but when I turn pagination on, there is page fault. Some details:
I'm using C for kernel
I'm using qemu as VM
I had own crosscompiler
I don't use any external libs
After loading and jumping into kernel code I setup interrupts and remap PIC, It's working and i reckon it's not the issue, after that I'm trying to enable paging
Here is paging.h
#ifndef PAGING_H
#define PAGING_H
#include "../cpu/types.h"
#include "../cpu/isr.h"
#define PAGE_SIZE 4096
typedef struct page{
u32 present :1;
u32 rw :1;
u32 kernel_space :1;
u32 accessed :1;
u32 dirty :1;
u32 unused :7;
u32 frame :20;
} page_t;
typedef struct page_table{
page_t pages[1024];
} page_table_t;
typedef struct page_directory{
u32 page_tables[1024];
} page_dir_t;
typedef struct page_directory_interface{
page_dir_t dir;
page_table_t* page_tables;
u32 page_dir_ph_address;
} page_dir_interface_t;
void init_paging();
void switch_page_dir(page_dir_t* new_dir);
page_t* get_page(u32 addres, page_dir_t* dir, u8 make);
void page_fault(registers_t regs);
#endif
I'm using page_t struct from some tutorial, because I reckon it's quite convinent, other parts, I've writed on my own twice, on both cases code results with PageFault. Here's paging.c:
#include "./paging.h"
#include "../util/panic.h"
#include "./memory.h"
#include "../drivers/screen.h"
page_dir_t* kernel_dir, cur_dir;
//helper function for convinient printing
void pint(u32 a){
char * tmp;
itoa(a, tmp);
kprint(tmp);
kprint("\n");
}
void init_paging(){
kernel_dir = kmalloc(sizeof(page_dir_t));
memset(kernel_dir, 0, 4096);
pint(sizeof(page_dir_t));
pint(&kernel_dir->page_tables[0]);
pint(kernel_dir);
int i;
for(i=0; i<1024; i++){ //setting up page directories for kernel
// read and write and kernel_mode and not present
kernel_dir->page_tables[i] = (u32)kmalloc(sizeof(page_table_t)) | 0x2;
}
map_page_table(kernel_dir->page_tables[0], 1, 1); //map ram to pages;
kernel_dir->page_tables[0] |= 0x3; //set as present
enable_paging();
}
void map_page_table(page_table_t* p_table, int kernel, int rw){
int i;
page_t tmp_page;
tmp_page.present = 1;
tmp_page.rw = (rw) ? 1 : 0;
tmp_page.kernel_space = (kernel) ? 1: 0;
for(i=0; i<1024; i++){
tmp_page.frame |= kmalloc(PAGE_SIZE);
p_table->pages[i] = tmp_page;
}
}
void enable_paging(){
u32 cr0_temp_value;
__asm__ __volatile__("mov %0, %%cr3":: "r"(&kernel_dir->page_tables));
__asm__ ("mov %%cr0, %0": "=r"(cr0_temp_value));
cr0_temp_value |= 0x80000000;
__asm__ __volatile__("mov %0, %%cr0":: "r"(cr0_temp_value));
}
And here is memory.c:
#include "./memory.h"
#include "../cpu/types.h"
#include "../../cathesimc/def.h"
u32 placement_addr = 0x10000;
void memcpy(char* src, char* dst, unsigned int bytes){
int i=0;
for (i=0; i< bytes; i++){
dst[i] = src[i];
}
}
void memset(u8* dest, u8 val, u32 len){
u8* tmp = (u8*)dest;
for(;len != 0; len--) *tmp++ = val;
}
//#TODO poprawic tego biedackiego malloca
u32 kmalloc_intrnl(size_t size, short int align, u32 *phys_addr){
if(align != 0 && (placement_addr & 0xFFFFF000)){
placement_addr &= 0xFFFFF000;
placement_addr += 0x1000;
}
if(phys_addr) *phys_addr = placement_addr;
u32 ret = placement_addr;
placement_addr += size;
return ret;
}
u32 kmalloc(size_t size){
return kmalloc_intrnl(size, 0, NULL);
}
u32 kmalloc_a(size_t size){
return kmalloc_intrnl(size, 1, NULL);
}
u32 kmalloc_p(size_t size, u32* phys_addr){
return kmalloc_intrnl(size, 0, phys_addr);
}
u32 kmalloc_ap(size_t size, u32* phys_addr){
return kmalloc_intrnl(size, 1, phys_addr);
}
My kernel is below 0x10000, it has about 16kb so 0x10000 is safe start of mapped space and memory from that address is definetely not used, I only set up one page table because I want to make paging barebones, and then take care about allocation and freeing, so my only goal for now is to find out what mistake I has making.
============EDIT==============
I have made intensive investigation, and I found that malloc has strange bahaviour, below are snippets of code with explaination
//as we can se from kmalloc() code above, kmalloc starts with
//placement_addr == 0x10000 when kernel starts
void init_paging(){
kernel_dir = kmalloc(sizeof(page_dir_t)); //page_dir_t has size 4096 and that is first malloc in kernel code
memset(kernel_dir, 0, 4096);
pint(sizeof(page_dir_t));
phex(sizeof(page_dir_t));
pint(&kernel_dir->page_tables[0]);
phex(&kernel_dir->page_tables[0]); //prints 0x10000 as expected
int i;
for(i=0; i<1024; i++){ //setting up page directories for kernel
// read and write and kernel_mode and not present
kernel_dir->page_tables[i] = (u32)kmalloc(sizeof(page_table_t)) | 0x2;
}
phex(kernel_dir->page_tables[0]); //0x11002 as expected
phex(kernel_dir->page_tables[1023]); //0x410002 as expected
kprint("pages\n");
map_page_table(kernel_dir->page_tables[0], 1, 1); //map ram to pages;
kernel_dir->page_tables[0] |= 0x3; //set as present
kprint("lol");
enable_paging();
}
void map_page_table(page_table_t* p_table, int kernel, int rw){
int i;
page_t tmp_page;
tmp_page.present = 1;
tmp_page.rw = (rw) ? 1 : 0;
tmp_page.kernel_space = (kernel) ? 1: 0;
//since now troubles starts this forloop below prints adresses:
// iteration0 0x11000
// iteration1 0x12000
// iteration2 0x13000
// iteration3 0x14000
// iteration4 0x15000
// iteration5 0x16000
// iteration6 0x17000
// iteration7 0x18000
for(i=0; i<8; i++){
tmp_page.frame = kmalloc(PAGE_SIZE);
phex(tmp_page.frame);
p_table->pages[i] = tmp_page;
}
}
I think that's definetly might be source of problems but I have no idea why placement_addr changes when i call another function, and why then it changes to 0x11000

C code: left shift is shifting but dropping top bits

I'm doing a small embedded project where I have 40 bits transferred through a SPI type interface. I pull these bits off of a 32 bit bus and place the upper 32 bits into a uint32_t variable and the lower 8 bits into a uint8_t variable. I'm trying to combine them into a single uint64_t. However when I shift by 8, it drops the top 8 bits. Here is my code.
uint64_t getError()
{
uint32_t * disp_addr = (uint32_t*)(MYDISPLAY);
uint64_t error_upper;
uint8_t error_lower;
uint64_t error= 0;
error_lower = *(disp_addr+1);
error_upper = *(disp_addr+0);
error = ((uint64_t) error_upper) <<8 | error_lower;
return error;
}
This code is working except for the fact that it's dropping my top 8 bits.
Any thoughts or hints would be greatly appreciated. Thanks.
edit
uint64_t getError()
{
uint32_t * disp_addr = (uint32_t*)(MYDISPLAY);
uint64_t error_upper;
uint8_t error_lower;
uint64_t error= 0;
error_lower = 0x34;
error_upper = 0xABCDEF12;
error = ((uint64_t) error_upper) <<8 | error_lower;
printf("%010x", error);
//return error;
}
Results:
00cdef1234
The printf format specifier is incorrect.
#include <stdio.h>
typedef unsigned __int64 uint64_t;
typedef unsigned char uint8_t;
int main(void) {
uint64_t error_upper, error;
uint8_t error_lower;
error_lower = 0x34;
error_upper = 0xABCEDF12;
error = (error_upper << 8) | error_lower;
printf("%x\n", error);
printf("%llx\n", error);
return 0;
}
Program output:
cedf1234
abcedf1234
Why are you saying that the upper byte is cut?
If I use your code and print the result is ok:
uint32_t temp = 0x01020304;
uint32_t *disp_addr = &temp;
uint64_t error_upper;
uint8_t error_lower;
uint64_t error= 0;
error_lower = *(disp_addr+1);
error_upper = *(disp_addr+0);
error = (error_upper<<8) | error_lower;
printf("\n%08X%08X\n", (uint32_t)(error>>32), error);
Output is
0000000102030401
Are you using %d to printout the value?
Look carefully at
uint32_t *disp_addr = &temp;
...
error_lower = *(disp_addr+0);
Because disp_addr is a ptr to uint32_t you are storing a 32bit value in a 8bit variable. Depending on your machine endiannes and how you load disp_addr you may be loading the wrong data.
You probably wanted to do:
uint32_t *disp_addr = &temp;
...
error_lower = *(uint8_t *)(disp_addr+0);
which is not the same.

Resources