Help with accessing C type data structures with nasm

Programming, for all ages and all languages.
Post Reply
jaswax
Posts: 23
Joined: Sat Jan 19, 2008 11:26 am
Location: Texas

Help with accessing C type data structures with nasm

Post by jaswax »

It has been a while since I have worked on my OS. I recently got back to it and have made some progress but I seem to have hit a wall.

Info:
OS Developed on Ubuntu Linux
using gcc, ld and nasm

I have the following type of structure defined:

Code: Select all

typedef struct userinfo
{
  char *username;
  unsigned int rights;     
  unsigned int lastloggedin;
  unsigned int locked; 
} USERINFO;
I have the following c code:

Code: Select all

int main (void)
{
  USERINFO *userlogin;

  userlogin = openfile("user.nfo");

  printf (userlogin->username);
  printf ("User rights: %d",userlogin->rights);
  printf ("User last logged in: %d",userlogin->lastloggedin);
  printf ("User rights: %d",userlogin->rights);
  printf ("Is the user locked out?: %d",userlogin->locked);
}
openfile use a routine written in nasm that pulls the data from user.nfo into a buffer. A pointer to the buffer is then returned by openfile and stored in userlogin.

The issue that I am having is with displaying the username. When I printf the username I either get nothing or I get garbage. I have no problems with the data for the other members of the struct.

I have written an elf executable written in c that I used to create the file user.nfo. I have also made a test program written in c that I used to see if I can read back the same data that I wrote into my user.nfo file These actions where done under linux. The tests show that under linux I am able to get back the data that I wrote to the user.nfo file and can access all data elements of the struct USERINFO but this is not true with all elements under my OS as described above.

Any ideas with this or help is much appreciated. [-o<
hrniels
Member
Member
Posts: 53
Joined: Wed Nov 05, 2008 5:18 am
Location: Marburg, Germany

Re: Help with accessing C type data structures with nasm

Post by hrniels »

Could you please post the implementation of openfile and perhaps the assembler-routine, too?

Another possibility is that printf doesn't work correctly. Have you checked the values you get with a different approach? E.g. with a debugger.
User avatar
qw
Member
Member
Posts: 792
Joined: Mon Jan 26, 2009 2:48 am

Re: Help with accessing C type data structures with nasm

Post by qw »

My guess is that the functions reads the user name (a string) into userlogin->username (a pointer), clobbering the entire structure. To be sure, we need to see the code for openfile.
User avatar
Troy Martin
Member
Member
Posts: 1686
Joined: Fri Apr 18, 2008 4:40 pm
Location: Langley, Vancouver, BC, Canada
Contact:

Re: Help with accessing C type data structures with nasm

Post by Troy Martin »

Hobbes wrote:My guess is that the functions reads the user name (a string) into userlogin->username (a pointer), clobbering the entire structure. To be sure, we need to see the code for openfile.
You're right. A char* is generally only 4 (or 8) bytes long, being a pointer, so you'd want to point the pointer to the filename section of the buffer.
Image
Image
Solar wrote:It keeps stunning me how friendly we - as a community - are towards people who start programming "their first OS" who don't even have a solid understanding of pointers, their compiler, or how a OS is structured.
I wish I could add more tex
jaswax
Posts: 23
Joined: Sat Jan 19, 2008 11:26 am
Location: Texas

Re: Help with accessing C type data structures with nasm

Post by jaswax »

So as to not leave you hanging:

I have to go to work now. I will post the requested code when I get back.

Thank you for the replies so far.
jaswax
Posts: 23
Joined: Sat Jan 19, 2008 11:26 am
Location: Texas

Re: Help with accessing C type data structures with nasm

Post by jaswax »

Ok, I am back. Long work day - 12 hours!

I went back and looked at my code that writes the data to user.nfo. I think what actually happened is that the pointer and data for my structure was still in memory even thou it was also on disk so that when I tested it it only looked liked it was working. My code to read and write was in the same executable. So when I went to read the data the I wrote from the file only the pointer to username was there and not the actual name. I wrote a separate test program under linux to only read the data from the file and I get the same results as in my os.

Here is the code:

Code: Select all

#include <stdio.h>
#include <stdlib.h>

#include "userlib.h"

int main(void)
{
  USERINFO      *userlogin;
  FILE                  *fp;

  uselogin = malloc(sizeof(USERINFO));

  fp = fopen ("user.nfo", "w");
  if (fp == NULL)
  {
     printf ("Can't open drive for output.\n");
     exit (2);
  }

  userlogin->username = "Joe";
  userlogin->rights = 4;
  userlogin->lastloggedin = 1527;
  userlogin->locked = 0;

  fwrite (userlogin, sizeof(USERINFO), 5, fp);

  fclose (fp);

  fp = fopen ("user.nfo", "r");
  if (fp == NULL)
  {
     printf ("Can't open drive for output.\n");
     exit (2);
  }

  fread (userlogin, sizeof(USERINFO), 5, fp);

  printf ("Current User: %s\n",userlogin->username);

  printf ("The time last logged in was: %d\n",userlogin->lastloggedin);

  fclose (fp);

  return 0;
}
I think that what I don't understand is how to save the actual data pointed to by username to the file user.nfo. I know that only the pointer to the data in memory is being saved in the file.

All of the above routines are from stanard libc and not libs that I have rewritten for my os.

So now my questions is how do I save the data to the file and not the pointer to the data?
User avatar
qw
Member
Member
Posts: 792
Joined: Mon Jan 26, 2009 2:48 am

Re: Help with accessing C type data structures with nasm

Post by qw »

The easiest way is to make username an array of fixed size, though this limits the length of the user name:

Code: Select all

#define MAX_USERNAME_LENGTH 12 /* Or any other reasonable value */

typedef struct userinfo
{
  char username[MAX_USERNAME_LENGTH + 1]; /* Plus terminating null character */
  unsigned int rights;     
  unsigned int lastloggedin;
  unsigned int locked; 
} USERINFO;
Also change this:

Code: Select all

userlogin->username = "Joe";
to:

Code: Select all

strcpy(userlogin->username, "Joe");
Just make sure that "Joe" does not exceed MAX_USERNAME_LENGTH characters.
hrniels
Member
Member
Posts: 53
Joined: Wed Nov 05, 2008 5:18 am
Location: Marburg, Germany

Re: Help with accessing C type data structures with nasm

Post by hrniels »

I see two ways:
  1. You store the string at the end of struct with a variable length (which you save, too). For example:

    Code: Select all

    typedef struct userinfo
    {
      unsigned int rights;
      unsigned int lastloggedin;
      unsigned int locked;
      unsigned int userLen;
      char username[];
    } USERINFO;
    (Alternatively "username[1]", depending on wether you want to use the gcc-extension or not)
  2. You use a max-length. E.g.:

    Code: Select all

    typedef struct userinfo
    {
      char username[MAX_USER_LEN];
      ...
User avatar
qw
Member
Member
Posts: 792
Joined: Mon Jan 26, 2009 2:48 am

Re: Help with accessing C type data structures with nasm

Post by qw »

Hrniels,
Option 1 would break sizeof (USERINFO).

Jaswax,
Another option is to use fprintf() and fscanf() instead of fwrite() and fread(). This will save the data in readable format. (EDIT: readable by humans.)

BTW the third argument to fread() and fwrite() is NOT the number of items in your structure! It now tells to read and write five structures instead of one. This way, you may destroy your heap. You should change 5 into 1.

Roel
Last edited by qw on Thu Sep 17, 2009 5:18 am, edited 2 times in total.
hrniels
Member
Member
Posts: 53
Joined: Wed Nov 05, 2008 5:18 am
Location: Marburg, Germany

Re: Help with accessing C type data structures with nasm

Post by hrniels »

Hobbes wrote:Hrniels,
Option 1 would break sizeof (USERINFO).
Sure. But this way you have a variable length for the name. Depends on your needs whats the better option... :)
User avatar
Owen
Member
Member
Posts: 1700
Joined: Fri Jun 13, 2008 3:21 pm
Location: Cambridge, United Kingdom
Contact:

Re: Help with accessing C type data structures with nasm

Post by Owen »

type something[] at the end of a structure isn't a GCC extension; it's C99. GCC has an (obsolete) extension which does the same thing whereby you specify [0] instead, however, that's just preserved for backwards compatibility.
hrniels
Member
Member
Posts: 53
Joined: Wed Nov 05, 2008 5:18 am
Location: Marburg, Germany

Re: Help with accessing C type data structures with nasm

Post by hrniels »

Owen wrote:type something[] at the end of a structure isn't a GCC extension; it's C99. GCC has an (obsolete) extension which does the same thing whereby you specify [0] instead, however, that's just preserved for backwards compatibility.
Ah, right. I mixed that up :oops:
User avatar
Solar
Member
Member
Posts: 7615
Joined: Thu Nov 16, 2006 12:01 pm
Location: Germany
Contact:

Re: Help with accessing C type data structures with nasm

Post by Solar »

Ad-hoc. I didn't test this.

Code: Select all

#include <stdio.h>
#include <stdlib.h>

#include "userlib.h"

int main(void)
{
  USERINFO      *userlogin;
  FILE                  *fp;
  const char * username = "Joe";

  userlogin = malloc( sizeof( USERINFO ) );  // Typo in your original code

  fp = fopen ("user.nfo", "w+");
  if (fp == NULL)
  {
     printf ("Can't open drive for output.\n");
     exit (2);
  }

  userlogin->username = malloc( strlen( username ) + 1 ); // +1 for terminating \0
  strcpy( userlogin->username, username );
  userlogin->rights = 4;
  userlogin->lastloggedin = 1527;
  userlogin->locked = 0;

  fprintf( fp, "%d|%s|%d|%d|%d\n", strlen( username ), userlogin->username, userlogin->rights, userlogin->lastloggedin, userlogin->locked );

  rewind(fp);
  free( userlogin->username );
  userlogin->rights = 0;
  userlogin->lastloggedin = 0;
  userlogin->locked = 0;

  int i;
  if ( fscanf( fp, "%d|", &i ) == 0 )
  {
     puts( "Data corruption!" );
     exit( 2 );
  }

  userlogin->username = malloc( i + 1 );
  if ( userlogin->username == NULL )
  {
     puts( "Out of memory!" );
     exit( 2 );
  }
  fgets( userlogin->username, i, fp );
  if ( fscanf( fp, "|%d|%d|%d\n", &userlogin->rights, &userlogin->lastloggedin, &userlogin->logged ) != 3 )
  {
    puts( "Data corruption!" );
    exit( 2 );
  }

  printf ("Current User: %s\n",userlogin->username);
  printf ("The time last logged in was: %d\n",userlogin->lastloggedin);

  fclose (fp);
  return 0;
}
Every good solution is obvious once you've found it.
jaswax
Posts: 23
Joined: Sat Jan 19, 2008 11:26 am
Location: Texas

Re: Help with accessing C type data structures with nasm

Post by jaswax »

Thanks for all of the replies. I experimented with everyone's suggestions. I largely used Solar's idea.

The only other thing I would like to know is if there is a way to get the information to align on word boundaries? Not critical but I would like to know.

=D>
Post Reply