Page 1 of 1

Adressing specific pointer in C

Posted: Mon Jun 06, 2011 4:24 am
by Bietje
Hi hi,

I wrote some code in assembly to create an array of memory map entries. I store them at an address specified by es:di. I store the pointer of the array in a label:

Code: Select all

   lea edx, [es:di]
   mov [mmr], edx
Not sure if that is correct.. mmr looks like this:

Code: Select all

mmr:
   dd 0 		; pointer address
   dw 0 ;entry count
   db 24 ; entry size
I have a global routine which returns the address of mmr. That works, I can access the entry count and the entry size (tested it in C). But I can't get that pointer to the first entry working.. The entries are stored at the correct place because I have tested that in assembly with an segment:offset pointer.

-- Bietje

Edit:
Code I have tried so far:

Code: Select all

unsigned int testmm()
{
	unsigned char * mmr = getmmr(); // get the address of mmr
	unsigned char * entryarray = ((unsigned char*)((unsigned short)*(mmr))); // address to the first entry
	unsigned int acpi = *(entryarray+20); // get a known value from the first entry
	return acpi;
	
// 	struct mmap_entry entries[6];
}

Re: Adressing specific pointer in C

Posted: Mon Jun 06, 2011 5:16 am
by Solar
Bietje wrote:But I can't get that pointer to the first entry working.
"Doesn't work" is not a valid problem description. Setup, observed result, expected result.

Code: Select all

	unsigned char * mmr = getmmr(); // get the address of mmr
	unsigned char * entryarray = ((unsigned char*)((unsigned short)*(mmr))); // address to the first entry
Why are you casting to and fro?

Re: Adressing specific pointer in C

Posted: Mon Jun 06, 2011 5:17 am
by bluemoon

Code: Select all

unsigned char * entryarray = ((unsigned char*)((unsigned short)*(mmr))); // address to the first entry
First you de-reference mmr, which is an unsigned char, here you lost 3 bytes of data.
then you cast it to unsigned short, which is nowhere near the size of 32-bit pointer.

a better approach would be:

Code: Select all

struct MMR_T {
  MMR_ENTRY * entry;
  unsigned short count;
  unsigned char entry_size;
} __attribute__ ((packed));

MMR_T * mmr = (MMR_T*) getmmr();
MMR_ENTRY * e = mmr->entry;
OK, if you still want the messed up version, try this:

Code: Select all

unsigned char * entryarray = (unsigned char*) (*(unsigned int*)mmr);
Be warned that this code style is not portable, it assume many architecture dependency thing like the size of a pointer.


And again, this is more of a C question then anything related to OSDev...

Re: Adressing specific pointer in C

Posted: Mon Jun 06, 2011 7:31 am
by Bietje
Thank you for your reactions..

I have tried to use packed structs.. Didn't work.. Assembly code unchanged.

Code: Select all

unsigned int getmmapentries()
{
	struct GEBL_MMR * mmr = (struct GEBL_MMR *) getmmr();
	struct GEBL_ENTRY * entry = mmr->entry;
	return entry->acpi;
}
The structures are defined as follow:

Code: Select all

struct GEBL_ENTRY
{
	uint64_t base;
	uint64_t len;
	uint32_t type;
	uint32_t acpi;
} __attribute__((packed));

struct GEBL_MMR
{
	struct GEBL_ENTRY * entry; // should be a pointer to 0x50:0x0
	uint16_t ecount;
	uint8_t entry_size;
} __attribute__((packed));

Re: Adressing specific pointer in C

Posted: Mon Jun 06, 2011 7:42 am
by Solar
Solar wrote:"Doesn't work" is not a valid problem description. Setup, observed result, expected result.
Also, Machete Debugging.

Re: Adressing specific pointer in C

Posted: Mon Jun 06, 2011 7:50 am
by Love4Boobies
Bietje wrote:

Code: Select all

   lea edx, [es:di]
   mov [mmr], edx
LEA ignores segment override prefixes so you're wasting a byte there; perhaps you added it for readability? If so, suggest using comments instead. Anyway, unless you're working with 32-bit offsets (which is not what you want, as far as I can tell---are you sure?), there's room for even more improvement:

Code: Select all

movzx edx, di
mov [mmr], edx
bluemoon wrote:a better approach would be:

Code: Select all

struct MMR_T {
  MMR_ENTRY * entry;
  unsigned short count;
  unsigned char entry_size;
} __attribute__ ((packed));

MMR_T * mmr = (MMR_T*) getmmr();
MMR_ENTRY * e = mmr->entry;
I wouldn't call something that uses compiler-specific extensions a better approach.
bluemoon wrote:OK, if you still want the messed up version, try this:

Code: Select all

unsigned char * entryarray = (unsigned char*) (*(unsigned int*)mmr);
Be warned that this code style is not portable, it assume many architecture dependency thing like the size of a pointer.
Well, although this is better, there are exactly two problems here: the pointer's size (i.e., assuming that unsigned int * is a DWORD) and its alignment (i.e., assuming unsigned int * can be aligned like unsigned char * can). The appropriate way to do this is:

Code: Select all

unsigned char *mmr = getmmr();
unsigned char *entryarray;

memcpy(&entryarray, mmr, sizeof entryarray);
bluemoon wrote:And again, this is more of a C question then anything related to OSDev...
This is the General Programming sub-forum.

Re: Adressing specific pointer in C

Posted: Mon Jun 06, 2011 9:38 am
by bluemoon
Love4Boobies wrote:I wouldn't call something that uses compiler-specific extensions a better approach.
Better, in a relative sense; and in this context i'm comparing with the OP casting method.
No, I did not say it's best or even a good one.

And I think any decent compiler recognize some form of (pack), and it can be easily implemented with #define with different compiler's favor keyword.
(Is is possible to avoid (pack) in C code of OS project? or you actually mean other extension that I oversee?)

Re: Adressing specific pointer in C

Posted: Mon Jun 06, 2011 4:35 pm
by Bietje
Woeesj, a bit closer again. The following code does what I want it to do:

Code: Select all

uint32_t getmmapentries()
{
// 	struct GEBL_MMR * mmr = (struct GEBL_MMR *) getmmr();
	struct GEBL_ENTRY * entry = 0x500;
	return entry->acpi;
}
Suprisingly, the following does NOT work:

Code: Select all

uint32_t getmmapentries()
{
 	struct GEBL_MMR * mmr = (struct GEBL_MMR *) getmmr();
	struct GEBL_ENTRY * entry = mmr->entry;
	return entry->acpi;
}
With the 0x500 hardcoded in my assembly syntax

Code: Select all

mmr:
	dd 0x500 		; dw 0 -> segment
			; dw 0 -> offset
	dd 0 ;entry count
	dd 24 ; entry size
If I can get that last thing working, I can just calculate the physical address run time and store it in the mmr. But the pointer gets doesn't get dereferenced correctly or something like that I think..

Edit: SOLVED

A more interesting answer comes later, in a hurry now.

Re: Adressing specific pointer in C

Posted: Tue Jun 07, 2011 3:59 am
by Love4Boobies
bluemoon wrote:And I think any decent compiler recognize some form of (pack), and it can be easily implemented with #define with different compiler's favor keyword.
The standard was defined for decent compilers---using anything else means you're not really writing C. I remember Bjarne Stroustrup saying that compiler vendors like to add extra features to their compilers so that developers use them and then can't switch to other compilers because it's too late---the code base is too big to refactor everything. And yes, that also applies to GCC; we all know what the FSF's agenda is.

The reason for which this packing concept does not exist in C is that not all types have the same alignment requirements; that's why you also have to be very careful with pointers, otherwise you'll get undefined behavior. For some implementations this could be a portability issue, for others it could be a performance issue.
bluemoon wrote:(Is is possible to avoid (pack) in C code of OS project? or you actually mean other extension that I oversee?)
Of course. My code does proper serialization and can be compiled with any C compiler.
Bietje wrote:Suprisingly, the following does NOT work:
Not very surprising. Use a debugger and see why.

Re: Adressing specific pointer in C

Posted: Tue Jun 07, 2011 5:40 am
by bluemoon
Love4Boobies wrote:Of course. My code does proper serialization and can be compiled with any C compiler..
May I know how you do it, for example, on ethernet packet structure? I'd be grad to learn more methods.

A greb on FreeBSD and Linux source I found even they used (packed), and they seems not worry much on not conforming this standard.
By the way, when dealing with OS dev, IMO we sometime need to push to the edge on standards in trade of convenience; provided that the ugly code is controllable size.

Another example would be data alignment and the know fact that on x86, some operations are atomic on aligned data;
C as a HLL would never define any atomic operation and it may not even work on other architecture, but sometime you still got some architecture dependent code for some reasons.

Re: Adressing specific pointer in C

Posted: Tue Jun 07, 2011 7:24 am
by Love4Boobies
bluemoon wrote:
Love4Boobies wrote:Of course. My code does proper serialization and can be compiled with any C compiler..
May I know how you do it, for example, on ethernet packet structure? I'd be grad to learn more methods.
There's no one true way to achieve serialization---it depends on what it is you are doing. Two techniques that I find useful are to use arrays, and files (which are particularly useful in debugging); again, not everything is suitable in every scenario.
bluemoon wrote:A greb on FreeBSD and Linux source I found even they used (packed), and they seems not worry much on not conforming this standard.
I don't know about FreeBSD but Linux is indeed tied to GCC.
bluemoon wrote:By the way, when dealing with OS dev, IMO we sometime need to push to the edge on standards in trade of convenience; provided that the ugly code is controllable size.
If you need to write ugly code then you're either using your tools the wrong way or you're not using the right tools for the job.
bluemoon wrote:Another example would be data alignment and the know fact that on x86, some operations are atomic on aligned data;
C as a HLL would never define any atomic operation and it may not even work on other architecture, but sometime you still got some architecture dependent code for some reasons.
It's true that there are very few atomic things in C (e.g., sig_atomic_t) but the upcoming standard, currently dubbed C1X, adds full atomicity support via the _Atomic type and <stdatomic.h> in order to fix this issue. As for architecture-dependent code, it is indeed important for OS developers (and others)---this is one of the reasons for which the standard defines unspecified behavior, undefined behavior, implementation-defined behavior, and locale-specific behavior. Many other languages have similar concepts.

In traditional C, C89, and C99, alignment (which is unrelated to atomicity) can be forced via unions and bit-fields. However, C1X brings alignment closer to the programmer as well: aligned_alloc, _Alignas, alignof, and <stdalign.h>.