first PROGMEM in lss gets marked as __trampolines_end opcodes

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

I noticed the first PROGMEM in lss file gets marked as __trampolines_end opcodes, and the lss interprets the PROGMEM data as actual instructions in the disassembly, just the avr-objdump seems to label it as such, even though it is actually a string in PROGMEM or whatever...

tried on atmega168, attiny24, tinyavr1 series, all same result. I went back to some really old windows lss code from avr studio 4, and it was the same, seems like it has always been this way.

There is nothing wrong with actual code, it seems avr-objdump just does not identify the first PROGMEM  as data, instead interprets it as opcodes.

everything I have tested ( the linux toolchain 3.5.4.1709 and 3.6.2.1759 and old windows avr studio 4 lss files ) all seem to do it...

I am using command... avr-objdump -h -S main.elf > main_test.lss

 

for example I see this...

00000022 <__trampolines_end>:
  22:    54 68           ori    r21, 0x84    ; 132
  24:    69 73           andi    r22, 0x39    ; 57
  26:    20 69           ori    r18, 0x90    ; 144
  28:    73 20           and    r7, r3
  2a:    64 61           ori    r22, 0x14    ; 20
  2c:    74 61           ori    r23, 0x14    ; 20
  2e:    20 32           cpi    r18, 0x20    ; 32
    ...

I expect to see this instead...

00000031 <test_bytes2>:
  31:    54 68 69 73 20 69 73 20 64 61 74 61 20 31 00        This is data 2.

 

I am posting to see if anyone else has come across this before, and if you have, did you find a way to have the avr-objdump correctly interpret the first PROGMEM in the disassembly?

 

c code example (you should be able to paste this into avr studio in windows without any issues)

//includes
#include <inttypes.h>
#include <avr/io.h>
#include <avr/interrupt.h>
#include <util/delay.h>
#include <avr/pgmspace.h>
#include <stdlib.h>
#include <string.h>

#define TEST_DATA1 "This is data 1"
#define TEST_DATA2 "This is data 2"

//one of these below will be labeled as __trampolines_end in lss
static const uint8_t test_bytes1[] PROGMEM __attribute__((used)) = { TEST_DATA1 };
static const uint8_t test_bytes2[] PROGMEM __attribute__((used)) = { TEST_DATA2 };

void main(void) __attribute__((noreturn));  void main(void)
{
	const uint8_t* ptr = test_bytes1;
	uint8_t i=0;
	while( i < sizeof(test_bytes1) )
	{ uint8_t c = pgm_read_byte(ptr++); PORTB = c; }	

	ptr = test_bytes2;
	i=0;
	while( i < sizeof(test_bytes2) )
	{ uint8_t c = pgm_read_byte(ptr++); PORTB = c; }

	while(1);
}

lss output


main.elf:     file format elf32-avr

Sections:
Idx Name          Size      VMA       LMA       File off  Algn
  0 .text         0000005e  00000000  00000000  00000054  2**1
                  CONTENTS, ALLOC, LOAD, READONLY, CODE
  1 .data         00000000  00800060  00800060  000000b2  2**0
                  CONTENTS, ALLOC, LOAD, DATA
  2 .comment      00000030  00000000  00000000  000000b2  2**0
                  CONTENTS, READONLY
  3 .note.gnu.avr.deviceinfo 0000003c  00000000  00000000  000000e4  2**2
                  CONTENTS, READONLY
  4 .debug_aranges 00000020  00000000  00000000  00000120  2**0
                  CONTENTS, READONLY, DEBUGGING
  5 .debug_info   0000053b  00000000  00000000  00000140  2**0
                  CONTENTS, READONLY, DEBUGGING
  6 .debug_abbrev 000004ae  00000000  00000000  0000067b  2**0
                  CONTENTS, READONLY, DEBUGGING
  7 .debug_line   000001d5  00000000  00000000  00000b29  2**0
                  CONTENTS, READONLY, DEBUGGING
  8 .debug_frame  00000024  00000000  00000000  00000d00  2**2
                  CONTENTS, READONLY, DEBUGGING
  9 .debug_str    000002ab  00000000  00000000  00000d24  2**0
                  CONTENTS, READONLY, DEBUGGING
 10 .debug_loc    0000005a  00000000  00000000  00000fcf  2**0
                  CONTENTS, READONLY, DEBUGGING
 11 .debug_ranges 00000010  00000000  00000000  00001029  2**0
                  CONTENTS, READONLY, DEBUGGING

Disassembly of section .text:

00000000 <__vectors>:
   0:	1f c0       	rjmp	.+62     	; 0x40 <__ctors_end>
   2:	24 c0       	rjmp	.+72     	; 0x4c <__bad_interrupt>
   4:	23 c0       	rjmp	.+70     	; 0x4c <__bad_interrupt>
   6:	22 c0       	rjmp	.+68     	; 0x4c <__bad_interrupt>
   8:	21 c0       	rjmp	.+66     	; 0x4c <__bad_interrupt>
   a:	20 c0       	rjmp	.+64     	; 0x4c <__bad_interrupt>
   c:	1f c0       	rjmp	.+62     	; 0x4c <__bad_interrupt>
   e:	1e c0       	rjmp	.+60     	; 0x4c <__bad_interrupt>
  10:	1d c0       	rjmp	.+58     	; 0x4c <__bad_interrupt>
  12:	1c c0       	rjmp	.+56     	; 0x4c <__bad_interrupt>
  14:	1b c0       	rjmp	.+54     	; 0x4c <__bad_interrupt>
  16:	1a c0       	rjmp	.+52     	; 0x4c <__bad_interrupt>
  18:	19 c0       	rjmp	.+50     	; 0x4c <__bad_interrupt>
  1a:	18 c0       	rjmp	.+48     	; 0x4c <__bad_interrupt>
  1c:	17 c0       	rjmp	.+46     	; 0x4c <__bad_interrupt>
  1e:	16 c0       	rjmp	.+44     	; 0x4c <__bad_interrupt>
  20:	15 c0       	rjmp	.+42     	; 0x4c <__bad_interrupt>

00000022 <__trampolines_end>:
  22:	54 68       	ori	r21, 0x84	; 132
  24:	69 73       	andi	r22, 0x39	; 57
  26:	20 69       	ori	r18, 0x90	; 144
  28:	73 20       	and	r7, r3
  2a:	64 61       	ori	r22, 0x14	; 20
  2c:	74 61       	ori	r23, 0x14	; 20
  2e:	20 32       	cpi	r18, 0x20	; 32
	...

00000031 <test_bytes1>:
  31:	54 68 69 73 20 69 73 20 64 61 74 61 20 31 00        This is data 1.

00000040 <__ctors_end>:
  40:	11 24       	eor	r1, r1
  42:	1f be       	out	0x3f, r1	; 63
  44:	cf ed       	ldi	r28, 0xDF	; 223
  46:	cd bf       	out	0x3d, r28	; 61
  48:	02 d0       	rcall	.+4      	; 0x4e <main>
  4a:	07 c0       	rjmp	.+14     	; 0x5a <_exit>

0000004c <__bad_interrupt>:
  4c:	d9 cf       	rjmp	.-78     	; 0x0 <__vectors>

0000004e <main>:
//one of these below will be labeled as __trampolines_end in lss
static const uint8_t test_bytes1[] PROGMEM __attribute__((used)) = { TEST_DATA1 };
static const uint8_t test_bytes2[] PROGMEM __attribute__((used)) = { TEST_DATA2 };

void main(void) __attribute__((noreturn));  void main(void)
{
  4e:	e1 e3       	ldi	r30, 0x31	; 49
  50:	f0 e0       	ldi	r31, 0x00	; 0
	const uint8_t* ptr = test_bytes1;
	uint8_t i=0;
	while( i < sizeof(test_bytes1) )
	{ uint8_t c = pgm_read_byte(ptr++); PORTB = c; }
  52:	84 91       	lpm	r24, Z
  54:	88 bb       	out	0x18, r24	; 24
  56:	31 96       	adiw	r30, 0x01	; 1
  58:	fc cf       	rjmp	.-8      	; 0x52 <main+0x4>

0000005a <_exit>:
  5a:	f8 94       	cli

0000005c <__stop_program>:
  5c:	ff cf       	rjmp	.-2      	; 0x5c <__stop_program>

 

compile script

#!/bin/bash

#variables
MCU=attiny24
OUT=$MCU
USR=$USER

TOOLCHAIN=/home/$USR/dev/lib_avr/avr8-gnu-toolchain-3.6.2.1759-linux_x86_64
GCC=$TOOLCHAIN/bin
PAC=$TOOLCHAIN/PACKS/Atmel.ATtiny_DFP.1.3.172
PACB=$PAC/gcc/dev/$MCU/
PACI=$PAC/include/
PACS=-B $PACB -I $PACI
CUR=$(pwd)

#options
OPT='-DF_CPU=8000000UL -Os -Wshadow -fpack-struct -fshort-enums -g2 -Wall -ffreestanding -finline-limit=3 -fno-inline-small-functions'

#files to compile
FILES=(main )

#make output directory
if [ -e "$OUT" ];
then
    echo found existing bin directory
else
	echo creating output directory
	mkdir $OUT
fi

#compile
reset
echo "__________________________________________________________"
echo "STARTING COMPILE"
cd $OUT
#=========================================================== -std=gnu99

#reset object linking
OL=""

#compile to object file (if not compiling correctly, echo the command below and make sure all variables are set)
FM=${FILES[0]}
for FL in "${FILES[@]}"
do
$GCC/avr-gcc -x c -funsigned-char -funsigned-bitfields -DDEBUG -I $PACI $OPT -mmcu=$MCU -B $PACB -c -std=gnu99 -MD -MP -MF "$FL.d" -MT"$FL.d" -MT"$FL.o" -o "$FL.o" "$CUR/$FL.c"
OL+="$FL.o " #prep the object linking
done

#compile objects to elf file
$GCC/avr-gcc -o $FM.elf  $OL   -Wl,-Map="$FM.map" -Wl,--start-group -Wl,-lm  -Wl,--end-group -Wl,--gc-sections -mmcu=$MCU -B $PACB  

#create hex from elf (must remove any extra data when dumping with -R)
$GCC/avr-objcopy -O ihex -R .eeprom -R .fuse -R .lock -R .signature -R .user_signatures  "$FM.elf" "$FM.hex"

#create srec from elf
$GCC/avr-objcopy -O srec -R .eeprom -R .fuse -R .lock -R .signature -R .user_signatures "$FM.elf" "$FM.srec"

#create eeprom file from elf
$GCC/avr-objcopy -j .eeprom  --set-section-flags=.eeprom=alloc,load --change-section-lma .eeprom=0  --no-change-warnings -O ihex "$FM.elf" "$FM.eep"

#compile objects to elf file again with source comments (must have -g switch to insert source code into elf file)
$GCC/avr-gcc -g -o $FM.elf  $OL   -Wl,-Map="$FM.map" -Wl,--start-group -Wl,-lm  -Wl,--end-group -Wl,--gc-sections -mmcu=$MCU -B $PACB
#dump elf to assembly (must have elf that was generated with -g)
$GCC/avr-objdump -h -S "$FM.elf" > "$FM.lss"

#===========================================================
echo "COMPILE FINISHED"
echo "__________________________________________________________"
#display GCC version
$GCC/avr-gcc --version
#display code size
echo "HEX SIZE USAGE"
$GCC/avr-objdump -Pmem-usage $FM.elf
$GCC/avr-size $FM.elf
echo "__________________________________________________________"
cd ..
#===============================================================

 

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

The location has MANY names _trampolines_end is just one if them but when the disassembler comes to label the location it picks the first of many symbols in the list for that location and _trampolines_end just happens to be the first one it picks. This is not an error. Use nm to see the list of symbols that all have that same value. 

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

thanks clawson

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

The lss interprets the PROGMEM data as actual instructions in the disassembly, just the avr-objdump seems to label it as such, even though it is actually a string in PROGMEM or whatever...

AFAIK, objdump has never been smart enough to tell flash data from flash code, nor is there a "smarter" alternative.

Maybe it's a feature: "you told be to disassemble, and that's what I'm doing!"

 

(Hmm.  You'd think the debug info in a .elf file would be enough for it to do a good job.  But that's in multiple separate sections - I think when you say "objdump -S", that means "disassemble the .text section", so it doesn't have access to the debug symbol info (it does have SOME symbols, though...))

 

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

I don't think it could rely on "debug symbols". A lot of code gets built without -g and it needs a strategy to be able to label that too.