Finding out the mem addr of objects within a type def struct?

Go To Last Post
17 posts / 0 new
Author
Message
#1
  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

I write some code, then compile it (with WINAVR / GCC).  Program variables that are created in ram have their memory addresses in that ram assigned by the compiler, and i can see what those addr are by looking in the .map file.  No problems there.

 

But, i have some type def'd structures, containing various different types, and although the starting address, and size, of the declared struct is in the .map, i can't seem to find out the addr of the individuals items within that struct?  Am i missing something obvious?  avr-nm just returns the addr of the struct from the .elf for example, but the compiler must know where everything is, so the info must be in there somewhere right??

 

Any pointers (sic) to where i should look?  ;-)

 

 

Psuedo code:

define a struture

Struct (
    unsigned char VarOne
    unsigned int  VarTwo
    unsigned long VarThree
    )mystruct
    
declare an instance of that structure
    mystruct StructureOne
    
    

The .map file will tell me that StrutureOne is 7 bytes long at starts at 0x00800010  for example

But it doesn't (i think) tell me where StrutureOne.VarTwo lives?  Ok, i KNOW it's at 0x00800011 because i can look at the layout of the structure, but surely there is someway of getting that info from the compiler?

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 1

but surely there is someway of getting that info from the compiler?

 

Why should there be?  Do you expect the compiler to tell you the address of every element in an array?

 

I'm curious, why do you want/need to know?

 

BTW, the debugger's Watch Window gives this information.

Greg Muth

Portland, OR, US

Xplained/Pro/Mini Boards mostly

 

Make Xmega Great Again!

 

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

max_torque_2008 wrote:
Ok, i KNOW it's at 0x00800011 because i can look at the layout of the structure

And that's exactly what the compiler does: it knows where the object starts, and it knows the layout - so it doesn't need to keep a separate record of the individual field addresses.

 

All the linker cares about is the size, and where it starts.

 

I guess you might be able to find this from the Debug info ... ?

Top Tips:

  1. How to properly post source code - see: https://www.avrfreaks.net/comment... - also how to properly include images/pictures
  2. "Garbage" characters on a serial terminal are (almost?) invariably due to wrong baud rate - see: https://learn.sparkfun.com/tutorials/serial-communication
  3. Wrong baud rate is usually due to not running at the speed you thought; check by blinking a LED to see if you get the speed you expected
  4. Difference between a crystal, and a crystal oscillatorhttps://www.avrfreaks.net/comment...
  5. When your question is resolved, mark the solution: https://www.avrfreaks.net/comment...
  6. Beginner's "Getting Started" tips: https://www.avrfreaks.net/comment...
  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

I must be missing something. If you want the address of &StructureOne.VarThree why wouldn't you do it exactly like that using the '&', address of, operator? 

 

Another approach is the base address plus offsetof(VarThree). 

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Items in a structure are always in the same order as they are declared in the structure.

So the first byte would be VarOne

2nd and 3rd byte would be VarTwo

Byte 4,5,6,7 would be VarThree.

 

There are some gotcha's.

If you are on a uC architecture with 16, 32, 64 or other word length there might be padding bytes between the var's.

Byte order within a var is not specified. It's usually Big or Little endian, but other weird combinations exist.

 

For exact definitions read the C standard.

 

Is this for looking at your data in a debugger?

You can do a quick verify by:

for(VarOne = 1; VarOne; VarOne<<=1) {}
for(VarTwo = 1; VarTwo; VarTwo<<=1) {}
for(VarTre = 1; VarTre; VarTre<<=1) {}
// Oops, forgot structure nama and a dot...

 

 

 

 

 

 

 

Doing magic with a USD 7 Logic Analyser: https://www.avrfreaks.net/comment/2421756#comment-2421756

Bunch of old projects with AVR's: http://www.hoevendesign.com

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

clawson wrote:
If you want the address of &StructureOne.VarThree why wouldn't you do it exactly like that using the '&', address of, operator?

That was my thought, too.

 

But it seems that he wants to know it from "outside" the execution of the program? Hence the talk about the map file.

 

But why he wants that remains a mystery.

 

Another case where stating the goal - rather than the (possibly flawed) step - would help.

 

http://www.catb.org/~esr/faqs/sm...

 

Paulvdh wrote:
Items in a structure are always in the same order as they are declared in the structure.

True.

 

If you are on a uC architecture with 16, 32, 64 or other word length there might be padding bytes between the var's.

Indeed. And there may be requirements on the alignment of the structure as a whole.

 

Byte order within a var is not specified.

Indeed, but that's the same for all data - irrespective of whether it's within a struct or not.

 

 

Is this for looking at your data in a debugger?

Good question.

 

But any decent debugger should be able to work directly with StrutureOne.VarTwo - you shouldn't have to manually mess about with absolute addresses.

 

As already noted:

 

Greg_Muth wrote:
the debugger's Watch Window gives this information. 

Top Tips:

  1. How to properly post source code - see: https://www.avrfreaks.net/comment... - also how to properly include images/pictures
  2. "Garbage" characters on a serial terminal are (almost?) invariably due to wrong baud rate - see: https://learn.sparkfun.com/tutorials/serial-communication
  3. Wrong baud rate is usually due to not running at the speed you thought; check by blinking a LED to see if you get the speed you expected
  4. Difference between a crystal, and a crystal oscillatorhttps://www.avrfreaks.net/comment...
  5. When your question is resolved, mark the solution: https://www.avrfreaks.net/comment...
  6. Beginner's "Getting Started" tips: https://www.avrfreaks.net/comment...
  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

The reason i "need to know" the address of individual elements of memory is that i have a DIY software tool chain for calibration and data exchange, to allow my embedded projects to exchange data with an external device (usually a windows tablet communicating over CAN or other serial link to the target).  I have a little tool that takes the .elf, uses avr-nm to create a .sym file, and then automatically sorts that data into different types, spits that all out to a .xml, and finally my coms application loads the xml, that allows the operator seamless access to the targets RAM!  (by controlling the contents of the .xml, i can give my clients different levels of access to the memory of the device)

 

At the moment, i'm having to also parse my "calibration data" raw c files that i have manually formatted into a separate .xml to identify calibratable parameters (these are loaded from an struct in the eeprom into a mirrored ram structure at run time) but because of that structure, i can directly identify member addresses from the 'elf

 

 

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Since, as has been noted, the debugger can do it - I'd again suggest that you look at the debug info...

Top Tips:

  1. How to properly post source code - see: https://www.avrfreaks.net/comment... - also how to properly include images/pictures
  2. "Garbage" characters on a serial terminal are (almost?) invariably due to wrong baud rate - see: https://learn.sparkfun.com/tutorials/serial-communication
  3. Wrong baud rate is usually due to not running at the speed you thought; check by blinking a LED to see if you get the speed you expected
  4. Difference between a crystal, and a crystal oscillatorhttps://www.avrfreaks.net/comment...
  5. When your question is resolved, mark the solution: https://www.avrfreaks.net/comment...
  6. Beginner's "Getting Started" tips: https://www.avrfreaks.net/comment...
  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 1

Since you have comms, why not implement a command protocol to manipulate the internal data.
eg. you send SET_VAR3=5544 and after sanity-checking the target puts 5544 into StructureOne.VarThree

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Here's another idea: Write a separate program for the AVR, using the same struct declaration. Create (define) one such struct in the program. Then let the program taker the address of the struct, and also the addresses of all the struct members, and send that info (e.g. using UART) to PC. You now have all the info you need about the struct layout.

As of January 15, 2018, Site fix-up work has begun! Now do your part and report any bugs or deficiencies here

No guarantees, but if we don't report problems they won't get much of  a chance to be fixed! Details/discussions at link given just above.

 

"Some questions have no answers."[C Baird] "There comes a point where the spoon-feeding has to stop and the independent thinking has to start." [C Lawson] "There are always ways to disagree, without being disagreeable."[E Weddington] "Words represent concepts. Use the wrong words, communicate the wrong concept." [J Morin] "Persistence only goes so far if you set yourself up for failure." [Kartman]

Last Edited: Sun. Aug 27, 2017 - 01:09 AM
  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 1

I would say to abstract the addresses across the serial channel. Translate at the AVR end into the actual variables. Will give you lots more flexibility. What if you do a new build in the future and those addresses change. Then your absolute address scheme would be a bunch of bull dung.

 

Jim

 

Until Black Lives Matter, we do not have "All Lives Matter"!

 

 

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Agree with mikech and ka7ehk - make yourself a proper command protocol, rather than hacking about with absolute addresses.

Top Tips:

  1. How to properly post source code - see: https://www.avrfreaks.net/comment... - also how to properly include images/pictures
  2. "Garbage" characters on a serial terminal are (almost?) invariably due to wrong baud rate - see: https://learn.sparkfun.com/tutorials/serial-communication
  3. Wrong baud rate is usually due to not running at the speed you thought; check by blinking a LED to see if you get the speed you expected
  4. Difference between a crystal, and a crystal oscillatorhttps://www.avrfreaks.net/comment...
  5. When your question is resolved, mark the solution: https://www.avrfreaks.net/comment...
  6. Beginner's "Getting Started" tips: https://www.avrfreaks.net/comment...
  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Looks like it is indeed time to sit back scratch your head and look at the overal system.

This weeked I'm looking a bit into PlatformIO and it looks Awesome.

The general idea is that (on this level) (almost) everything has already been invented and you mainly have to glue it together a bit.

 

Just to give you some ideas:

Pull in some of the 1800 libs (when using PlatformIO (this is just an example)), and then use something like JSON over slip or even ftp to write the info you need directly to a file.

Or as Jim / Johan suggests. Convert your data into text strings, write over serial and catch with a terminal emulator.

Doing magic with a USD 7 Logic Analyser: https://www.avrfreaks.net/comment/2421756#comment-2421756

Bunch of old projects with AVR's: http://www.hoevendesign.com

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Thing is, the basic cogs that drive my interface is all written as fully proven and automatic.  i hit build on the compiler, that builds the code, and the 'elf is parsed through my converter app and spits out a matching .xml.  I have a fixed function in the target that reports the id of the code running in that target (hardware, firmware and calibration) and my cal tool connects to the target, uploads the identifiers, then goes and finds the matching data descriptor .xml, and allows the user to call up both variables and change RM/EPPROM etc..

 

At the moment, it relies on my manually building the calibration data file, with certain text formators and descriptors in the commented section of each line that describes that parameter for the 'xml parser.  If i could pull that info directly from the compiler it would simplify the coding exercise.

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

If the tool connects to the target why can't it simply ask it what &StructureOne.VarThree is? Why do you need to preprocess the address separately? The linker will preprocess it when the code is linked so in the code it'll simply have the precaculated 0x1234 or whatever anyway to return when asked.
.
BTW, even if something external gets the address what can it possibly do with it? Is this all about a "monitor" that interrogates internal vars?
.
If it is then why not simply send the entire struct and as long as the PC end knows the struct layout (same packing, same endianism) it can pick out the value anyway.

Last Edited: Sun. Aug 27, 2017 - 06:07 PM
  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

I do something like that in my applications, using my own utility. I'm not sure if there is an out-of-the-box solution. I know that there is a library, libdwarf, but even then I imagine that it might still not be easy to get the data you want.

To get an idea what you can get, look at the following:

avr-readelf --debug-dump file.elf

For example, if you have typedef {} MyStruct, then there will something like this in the dump:

 <1>: Abbrev Number: 2 (DW_TAG_typedef)
       DW_AT_name        : (indirect string, offset: 0x202b): MyStruct	
       DW_AT_decl_file   : 28	
       DW_AT_decl_line   : 19	
       DW_AT_type        : <0x9af>	

DW_AT_type points to the definition. If you look there, you will see something like:

 <1><9af>: Abbrev Number: 8 (DW_TAG_structure_type)
    <9b0>   DW_AT_byte_size   : 9	
    <9b1>   DW_AT_decl_file   : 28	
    <9b2>   DW_AT_decl_line   : 11	
    <9b3>   DW_AT_sibling     : <0xa19>	
 <2><9b7>: Abbrev Number: 10 (DW_TAG_member)
    <9b8>   DW_AT_name        : (indirect string, offset: 0x1d35): myVar1	
    <9bc>   DW_AT_decl_file   : 28	
    <9bd>   DW_AT_decl_line   : 12	
    <9be>   DW_AT_type        : <0xa1>	
    <9c2>   DW_AT_data_member_location: 2 byte block: 23 0 	(DW_OP_plus_uconst: 0)
 <2><9c5>: Abbrev Number: 10 (DW_TAG_member)
    <9c6>   DW_AT_name        : (indirect string, offset: 0x1d3c): myVar2	
    <9ca>   DW_AT_decl_file   : 28	
    <9cb>   DW_AT_decl_line   : 13	
    <9cc>   DW_AT_type        : <0xa1>	

And so on. Again, not going to be easy.

Eugene

Last Edited: Sun. Aug 27, 2017 - 09:39 PM
  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

It took me a while to get an idea of what you're doing.

I think you missed awneil #8

elf files are not always the same, have different sections.

You can instruct the compiler to put debug info in the elf file and that debug info let you combine names with memory adresses.

I don't know much of that stuff, but it's all open source and documented.

Doing magic with a USD 7 Logic Analyser: https://www.avrfreaks.net/comment/2421756#comment-2421756

Bunch of old projects with AVR's: http://www.hoevendesign.com