assembler alignment woes

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

I want to interleave data and code, and maintain a linked list of it, in the .text section. The problem I'm having is that the assmebler does not seem to align assembler instructions by itself, and if I align the code part manually my list generation pointer arithmetic fails.

Simples example:

	.text
	.set here, .          ; remember start of definition
	.byte 4               ; size of data
	.ascii "fool"         ; data

	;.balign 2, 0         ; <-- part 1 of my woes
	.global fool          ; code definition
	.type fool, @function
fool:
	ret
	.byte (. - here)      ; <-- part 2 of my woes

The way the example is shown the assembler generates fool at an odd adress, which the AVR doesn't like at all (can't call it, can't jump to it, ...). Other than that the assembler generates the layout I am aiming for.

If I uncomment the alignment then the link pointer generation (last line) fails with:

Quote:
$ /usr/local/avr-4.2.2/bin/avr-gcc -mmcu=atmega8 -Os -nostartfiles -o y x.S
x.S: Assembler messages:
x.S:11: Error: illegal relocation size: 1

Using a .word instead of .byte fixes the problem but wastes a byte (the result is guaranteed < 256).

I could manually pad but I would rather understand why it works without alignment and doesn't with it. Can somebody tell me where I'm going wrong and how I would do this correctly?

Markus

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

If you mimic the way that a C compiler does it:

Make strings NUL terminated.
Align everything on word boundaries.
You will always get the correct start address, and you use standard string algorithms e.g. "while (c = *s++)"

If you are intending to keep other data (i.e. NUL is valid data), then I would personally just choose a word for the data length.

If you are using several initialised data structures, I would advise writing a macro that ties the address, the data and a data label together. This way you will not fall foul of typos.

The other technique is to change sections every time you are storing data. The linker will concatenate each section. You will always have aligned instructions. The data section entries need not be aligned. Although it does make messier code if you have to check for word boundaries everywhere.

Are you really running that short of flash space ?

David.

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

Currently I have more space than code ;).

One of the goals I'm trying to achieve is that data and code are interleaved in their layout, so I can't use different sections. Basically I want a list of code and their metadata. If I separate them I need a pointer from the metadata to the code, which is (at least) 2 bytes.

In the end this should become a simple Forth which is comprised of a lot of small functions (called words). Every byte safed in the definition has quite an impact on the overall size.

Thanks for the input.

Markus

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

If you are implementing a Forth, it makes everything a lot cleaner if you always push or pop the same size of object off of your stack. Are you intending to do floating point ?

I would guess that a string or composite object would be a pointer reference rather than a variable size lump to physically push onto a stack.

Good luck anyway.

David.

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

david.prentice wrote:
Good luck anyway.
Thanks, I can use that!

You are correct about the stack and string handling. The memory layout described above is for the dictionary (which I want to live in flash, entirely). That is also the reason for the here calculation in the assmbler.

Markus

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

How about Plan B-

.text
 //store current location
.set func_start, .
 //store size of string (byte #1)
.byte 4
 //store string
.ascii "fool"
.set data_size, . - func_start
 //now check if padding needed to align on word
.if (data_size & 1)
 //was odd, so we need to pad it
.byte 0
.endif

 //we are now word aligned again
.global fool
.type fool, @function
 fool:
     ret
    .byte (. - func_start)
    //we are now NOT word aligned

//all the rest of the functions will not be word
//aligned at the start of the function
//so the padding test needs to check if NOT odd

 //store current location
.set func_start, .
 //store size of string
.byte 6
 //store string
.ascii "fool_2"
.set data_size, . - func_start
 //now check if padding needed to align on word
.if !(data_size & 1)
 //was even, so we need to pad it
 //because we were not aligned at the start
.byte 0
.endif

 //we are now word aligned again
.global fool2
.type fool2, @function
 fool2:
     ret
    .byte (. - func_start)

//linker will align here

the first function will be aligned at the start of its function, the rest of the functions will not be aligned at the start because the .byte after the ret always leaves it not aligned. So the first function checks for an odd alignment (odd number of data bytes at the start of the function), where the rest will check for even alignment (which means its odd).

I'm getting confused, but it seems to work.

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

Nifty. I need and end of the list anyway, which is a size byte of 0. That means that the first definition will also start out unaligned, making all definitions uniform.

Thanks,
Markus