Page 1 of 1

C: Correctly using a memory address for an array of structs?

Posted: Sat Apr 27, 2024 6:55 pm
by a469bc
Hi,

I've been writing a hobby OS on aarch64 and so far have only used the stack. I've reached the point where I want to implement dynamic memory and I've realised by understanding of C pointers/memory is extremely poor (it seems), so I've been trying to write several barebones practice routines to learn a bit more. My main background is usually a non-freestanding C++ environment or JavaScript.

This is what I'm trying to do:

A. I have a page aligned 4K page set by the linker.

B. I want to use this page to store 32 128-byte sized records at this address.

C. The definition of a record is:

Code: Select all

struct {
  char [112] name;
  uint64_t   start;
  uint64_t   end;
}
D. I am trying something like this in the C file:

Code: Select all

extern volatile uint64_t _address_from_linker;

struct __attribute__((__packed__)) record {
  char     name[112];
  uint64_t start;
  uint64_t end;
};
typedef struct record record_t;

void*   m_Entries;
uint8_t m_EntriesCount = 0;

void records_init() {
  m_Entries = &_address_from_linker;
  m_EntriesCount = 0;

  size_t record_size = sizeof(record_t);
  log("record size: 0x%X, %d", record_size, record_size);

  log("records base addr: %p", m_Entries);

  records_add("Test1", 0x1000, 0x1FFFF);
  records_add("Test2", 0x2000, 0x2FFFF);
}

void records_add(const char* name, uint64_t start, uint64_t end) {
  record_t* rec = (record_t*)(m_Entries + sizeof(record_t) * m_EntriesCount);

  log("records_add at: %p", rec);

  memcpy(entry->name, name, strlen(name));
  rec->start = start;
  rec->end = end;

  m_EntriesCount++;
}

void records_print() {
  log("records print:");

  for(int i = 0; i < m_EntriesCount; i++) {
  	record_t* entry = (record_t*)m_Entries + sizeof(record_t) * m_EntriesCount;
  	log("%s %p %p", entry->name, entry->start, entry->end);
  }
}
E. My memcpy, strlen and log/printf functions are fine, and work as expected in other contexts / uses. This is in a barebones freestanding C enviroment so accessing memory at these addresses is fine, nothing else is overwriting the memory etc.

F. My output is this:

Code: Select all

record_size: 0x80, 128
records base addr: 0x0000000000090000
records_add at: 0x0000000000090000
records_add at: 0x0000000000090080
records print:
i: 0, name:  start: (nil) end: (nil)
i: 1, name:  start: (nil) end: (nil)
So my questions are:

1. What exactly am I doing wrong, mixing up pointer dereferencing / not dereferencing correctly?

2. What is the correct way to use an address provided by the linker as the base for an array of structs?

3. Is there is correct method of doing this where I have a typed array (so record_t records[] instead of a void*)?

4. The memory offset is correct, because size = 0x80, and the second entry (1) is being placed at 0x90080? Am I mixing up bytes / hex / decimal?

5. What is the correct way to do this overall?

Thank you kindly.

Re: C: Correctly using a memory address for an array of stru

Posted: Tue Jun 11, 2024 6:18 pm
by Octocontrabass
a469bc wrote:1. What exactly am I doing wrong, mixing up pointer dereferencing / not dereferencing correctly?
You're printing it wrong. Specifically, you're using m_EntriesCount instead of i, so you're always trying to access past the end of the array, and you're casting to record_t* before you add the offset, meaning the offset is multiplied by sizeof(record_t) twice instead of only once.
a469bc wrote:2. What is the correct way to use an address provided by the linker as the base for an array of structs?
3. Is there is correct method of doing this where I have a typed array (so record_t records[] instead of a void*)?
Something like this should work.
a469bc wrote:4. The memory offset is correct, because size = 0x80, and the second entry (1) is being placed at 0x90080? Am I mixing up bytes / hex / decimal?
It seems like you've got that part right.
a469bc wrote:5. What is the correct way to do this overall?
Depends on what you're trying to do. You don't need any pointer arithmetic if you're working with an array of structs, but pointer arithmetic is a requirement if you're trying to come up with a generic malloc-like allocator to use in your kernel.