avr-as and pascal like strings

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

I'm trying to place pascal string like constants in flash (length byte followed by ASCII string with no trailing zero byte)

The following is failing with "Error: illegal relocation size: 1"

FOO:	.byte	((BAR - . - 2) & 0x7F)	; calculate length
		.ascii	"foo"
BAR:	.word	0x1234				; dummy for this example

I could just hard code the length, except I have eventually want this in a macro as I have several hundred string.

I assume the error is because ((BAR - . - 2) & 0x7F) resolves to a two byte type even although we can see its value would always fit within a byte.

I tried using lo8() but it appears not to be recognised within this context - Error: junk at end of line, first unrecognized character is `('.

It didn't seem a particularly unusually thing to want to do so I'm hoping someone can point me in the right direction with this.

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

Pure guesswork, but easy to try:

FOO:   .byte   ((BAR - . - 2) & 0x7F)   ; calculate length
      .byte   "foo" 
BAR:

.ascii adds the NUL terminator
.byte should not add a terminator.

You will still have issues with alignment, since things normally like to be word-aligned. You may end up with a .word for the length.

David.

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

No, .ascii does not add a \0, you're confusing it with .asciz.

Jörg Wunsch

Please don't send me PMs, use email if you want to approach me personally.

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

I tried it, and you will need to use

FOO:	.word	(BAR-FOO-2) 
	.ascii	"foo"
BAR:

avr-as does not like to have the (expression) in the .byte

It also needs the .ascii

I have tried using .set for the length and it does not like it. Although you can use literal length values like .byte 3 .. .ascii "foo"

David.

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

Jorg, there must be a way to get the 8bit expression into the .byte

It evaluates an "ABS" expression for the length. Surely avr-as should just check the value of the expression and not the "sizeof(expression)"

David.

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

My problem seems to be related to the forward use of a label as the following compiles...

BAR:		.ascii "foo"
FOO:		.byte  (FOO - BAR - 1)

but that does not help me as the fields are in the wrong order.

And even this compile with only a warning

BAR:		.ascii "foo"
FOO:		.byte  0xffff

example.S:190: Warning: value 0xffff truncated to 0xff

and so does this, and without the warning despite an apparent truncation (assuming BAR - FOO = 0xFFFC)

BAR:		.ascii "foo"
FOO:		.byte  BAR - FOO

Is this an avr-as specific problem or should I be asking in a gnu-as forum (is there one?)

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

I expect that a gcc-as expert will answer this easily.

If you can place the "string" in a "no code" style section, you can calculate the length as a defined (backward) reference expression using .set
You can then use .byte len ... .ascii "string"

I have tried using an assembler macro, but cannot get a "string" to work as a macro argument.

I have tried a C style macro, but the sequence of ASM statements come out on one line.

I am sure that there will be an elegant solution.

David.

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0
.macro CREATE_S string
.set CCOUNT,0
.irpc param,\string
.set CCOUNT,CCOUNT+1
.endr
.byte CCOUNT
.ascii "\string"
.endm

.text

FOO: CREATE_S foo
FRED: CREATE_S fred

If these are all 'together, and no code in between, the linker will take care of the alignment at the end. If you need code inside these, then you would need to put your own byte alignment in (check if CCOUNT is even, if so add a .byte 0). Something like-

.macro CREATE_S string
.set CCOUNT,0
.irpc param,\string
.set CCOUNT,CCOUNT+1
.endr
.byte CCOUNT
.ascii "\string"
.if !(CCOUNT & 1)
.byte 0
.endif
.endm

.text

FRED: CREATE_S fred
nop
FOO: CREATE_S foo

which would get the 'nop' word aligned.

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

> I expect that a gcc-as expert will answer this easily.

I'm afraid you'd have to look out somewhere on a GNU binutils
mailing list to find gas experts.

Jörg Wunsch

Please don't send me PMs, use email if you want to approach me personally.

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

Thanks Jorg, but Curt has provided the answer.

	.macro PASCAL tring
	.set CCOUNT,0
	.irpc param,\tring
	.set CCOUNT,CCOUNT+1
	.endr
	.byte CCOUNT
	.ascii "\tring"
	.endm

	.text

FOO:	PASCAL "foo"
	nop
FRED:	PASCAL "fred"
	nop
DV:	PASCAL "David"
	nop
PR:	PASCAL "Prentice"

I changed the name of the macro argument to "tring", which removes the "\s" Warning from "\string".

avr-as looks after the alignment. There is an automatic padding at the end of each string.

I can go down to the pub now.

David.

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

I'd consider the irpc method a workaround rather than a real answer...

But I'm not sure whether the unability to calculate the difference
between two relocatable symbols within the same section into an absolute
value is a generic deficiency in gas or just related to the AVR port
only.

Jörg Wunsch

Please don't send me PMs, use email if you want to approach me personally.

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

Curt,

That looks like just what I need. Many thanks. And David for his fix (I was just wondering what the problem was when you posted). Thanks to you both I have a reasonable work round. I owe you both I pint!

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

Quote:
avr-as looks after the alignment. There is an automatic padding at the end of each string.
not on mine (gcc 3.4.6)- if code is inserted, you (may) need to align yourself (look at the lss listing to verify).

I missed the \s thing, as I saw 0 Warnings (but missed the assembler messages).

Last Edited: Mon. May 5, 2008 - 04:13 PM
  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Quote:
But I'm not sure whether the unability to calculate the difference
between two relocatable symbols within the same section into an absolute
value is a generic deficiency in gas or just related to the AVR port
only.

The expression obviously resolves into an absolute value. However, the operands in the expression are unresolved when avr-as first encounters them.

A normal assembler will place the symbols into the symbol table as "unknown type and value". They would be evaluated correctly on the "second pass". Or in the case of a single pass assembler, when all the graphs have been walked.

So an Error or Warning should only occur if the expressions were not "absolute" at the end of assembly. And the linker is being passed an external type that it cannot handle.

David.

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

curtvm wrote:
Quote:
avr-as looks after the alignment. There is an automatic padding at the end of each string.
not on mine (gcc 3.4.6)- if code is inserted, you (may) need to align yourself (look at the lss listing to verify).

Seems to be aligning for me with avr-gcc (GCC) 4.2.2

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

curtvm wrote:
Quote:
avr-as looks after the alignment. There is an automatic padding at the end of each string.
not on mine (gcc 3.4.6)- if code is inserted, you (may) need to align yourself (look at the lss listing to verify).

Try my example code. The location counter seems to be incremented correctly.

I just tested on the command line with a avr-as file.s

  12 0000 0366 6F6F 	FOO:	PASCAL "foo"
  13 0004 0000      		nop
  14 0006 0466 7265 	FRED:	PASCAL "fred"
  14      64
  15 000b 0000      		nop
  16 000d 0544 6176 	DV:	PASCAL "David"
  16      6964 
  17 0013 0000      		nop
  18 0015 0850 7265 	PR:	PASCAL "Prentice"
  18      6E74 6963 
  18      65

Oops. You are quite correct. I am not used to the idea of having a byte oriented location counter.

An .align 2 at the end of the macro solves that.

David.

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

Does it have to be assembly?
Something like

#define PROG_STRING(str) struct {\
    unsigned char sz;            \
    char data[sizeof(str)-1];    \
} str ## prog_string PROGMEM = { sizeof(str)-1, str } ;

Might do the trick in C, but not C++.
C++ will complain about not
having room for the null byte.
If you are not typing in all your code by hand,
whatever program generator you use should be
able to count bytes.

"SCSI is NOT magic. There are *fundamental technical
reasons* why it is necessary to sacrifice a young
goat to your SCSI chain now and then." -- John Woods

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

dl8dtl wrote:
But I'm not sure whether the unability to calculate the difference
between two relocatable symbols within the same section into an absolute
value is a generic deficiency in gas or just related to the AVR port
only.

Targetting ARM7 this code assembles ok:

	.byte 2f - 1f
1:	
	.ascii "foo bar"
2:

So at least it seems to exist some port relation.

Regards,

Carlos.

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

Quote:
An .align 2 at the end of the macro solves that.
actually an .align 1 will do the trick.

I tried gcc 4.2.2, and it also does not align on the word. You have to read the listing carefully (look for addresses that start on an odd number). Also to make it easier to spot when testing, use something other than 'nop'.

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

sjb wrote:
Seems to be aligning for me with avr-gcc (GCC) 4.2.2

No, scrub that. It's not aligning. Not sure what I was looking at before.

Actually this is good for me as I want the maximum packing density, and padding is not going to help with that.

Do I only need to worry about padding when I get back to a code section? In some places I have these Pascal strings within code blocks. Is this the reason to pad, and is this that only reason to pad? If so I'll just pad as I enter the code blocks.

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

You need to do whatever it takes to get instructions on a word boundary (the program counter addresses words only).

You can omit the .align 1 from the macro (which replaces my ccount 'even' test), and simply do it yourself after the strings are created, or you can let the macro handle it (and lose a byte for any string that is not an 'odd' number in size). I would put it in the macro unless/until you are really hurting for space (you will know where to get the extra space if needed).

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

Quote:
actually an .align 1 will do the trick.

Yes, I thought that too on the way back from the pub.

	.macro  PASCAL x
	.section "n" 
	.set	old, .
	.ascii	"\x" 
	.set	len, . - old 
	.text 
	.byte	len 
	.ascii	"\x"
	.align	1
	.endm

DV:	PASCAL	"David"
	nop
PR:	PASCAL	"Prentice"
	nop

I think that this method might keep Jorg happy.

Although personally I think that:

	.macro  PASCAL x
	.byte	_2 - _1 
_1:	.ascii	"\x"
_2:	.align	1
	.endm

would be the elegant way to do it.

David.

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

I'm not sure I like that 'phantom' section floating around (harmlessly, I guess). I also don't think using 'irpc' is a workaround, as we are actually interested in the character count, not calculating location counter addresses (as long as 1 character is 1 byte). Phantom section vs. irpc, I'll take the latter.

Here's my final version, with optional alignment

//x is string, a is alignment
//no a passed = no alignment (packed)
//a = ALIGN = aligned for code to follow
.set ALIGN,1
.macro  PASCAL x,a
  .set CCOUNT,0
  .irpc param,\x
    .set CCOUNT,CCOUNT+1
  .endr
  .byte CCOUNT
  .ascii   "\x"
  .align   \a
.endm

T0:   PASCAL   "12"
T1:   PASCAL   "345",ALIGN
    push r0
    push r1
T2:   PASCAL   "12"
T3:   PASCAL   "34"
T4:   PASCAL   "5678",ALIGN
    pop r1
    pop r0

the lss listing is a little confusing to read, as the packed strings kind of screws up the addresses, and you will get bytes that are listed 'twice'.

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

I think that the "no code" .section is just the GNU way of doing things.

It is no different to the way that you do stack frames on a 68000. With any normal assembler you would have a .ds or .rs (declare or reserve storage) directive. With the 6502 I used to do *=*+expression to reserve storage. The assembler would not complain about the location counter being manipulated backwards providing no actual bytes were being output.

I would agree that neither the .iprc or the .section method is elegant and I would also choose .iprc myself.

David.