Using avr-gcc as "dumb" assembler and having access to io.h

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

I'm making a project for the ATTiny10 (or smaller). For this project I thought I'd like to use gcc as essentially a "dumb" assembler, but I'm having trouble including the I/O register definitions. I'm using Ubuntu (well, Kubuntu to be exact). The first step was to install gcc-avr.

sudo apt-get install gcc-avr

However, whenever I try to access any I/O register, I get an undefined reference to that label, despite including io.h like so:

#include <avr/io.h>

I assembled the code using the following command:

avr-gcc -nostdlib -mmcu=attiny10 -DF_CPU=1000000 -g test.s -o test.elf

After a lot of research I have actually found the answer while writing the question. There are two things I figured out I needed to do.

1) The first thing I figured out was that the relevant header files are not actually included in gcc-avr. You actually need to install the avr-libc package as well:

sudo apt-get install avr-libc

This would put the relevant files in /usr/lib/avr/include/avr/

2) This still did not make the include work properly. This, I found out to be due to a quirk documented here. Namely, that C style preprocessor commands would only be parsed in assembly language files by default if the file extension is an upper-case S but not if it's a lower-case s. This would cause the include to silently be completely ignored, as it appeared to just be a comment as far as the assembler is concerned.

Note that the invokation of the C preprocessor will be automatic when the filename provided for the assembler file ends in .S (the capital letter "s"). This would even apply to operating systems that use case-insensitive filesystems since the actual decision is made based on the case of the filename suffix given on the command-line, not based on the actual filename from the file system.

As an alternative to using .S, the suffix .sx is recognized for this purpose (starting with GCC 4.3.0). This is primarily meant to be compatible with other compiler environments that have been providing this variant before in order to cope with operating systems where filenames are case-insensitive (and, with some versions of make that could not distinguish between .s and .S on such systems).

Alternatively, the language can explicitly be specified using the -x assembler-with-cpp option

Hopefully this can help someone in a similar situation.

This topic has a solution.
Last Edited: Thu. Jan 23, 2020 - 07:07 PM
  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

There's a little more to it than you have already surmised. These pages in the user manual will help:

 

https://www.nongnu.org/avr-libc/user-manual/assembler.html

https://www.nongnu.org/avr-libc/user-manual/group__avr__sfr__notes.html

 

I personally therefore favour:

// foo.S
#define __SFR_OFFSET 0
#include <avr/io.h>

entry:
    ser r16
    ldir r17, 0xAA
    out DDRB, r16
loop:
    in r16, PORTB
    xor r16, r17
    out PORTB, r16
    rjmp loop
    

By defining __SFR_OFFSET as 0 you can just immediately use IN/OUT on the SFR register names in the 0x00..0x3F IO space (the 0x20..0x5F RAM space)

 

But if I build the above using the commands you showed I would get an error about "main undefined". That is because, by default the linker will link in the CRT file for the build target and as well as an interrupt vector table it ends by doing an "RCALL main" on the basis that usually it works with C code and there will be a function called main(). But I want to start my asm with "entry:" and what's more I want entry: to be at 0x0000 in flash. So to your other build options I would add -nostartfiles when writing "raw Asm".

 

(however if I wanted to use interrupts and I did not mind the CRT using up the space for a complete IVT I might not use the option in which case the entry to this code has to be "main:")

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

clawson wrote:
By defining __SFR_OFFSET as 0 you can just immediately use IN/OUT on the SFR register names in the 0x00..0x3F IO space (the 0x20..0x5F RAM space)

Thanks for the hint. That's really useful advice and could have been a headache down the line. I've up until this point used AVR Studio for ASM projects, and the I/O port addresses have been defined in terms of the I/O mapping, not the memory mapping, so this has not been an issue you have to worry about. I guess gcc, being c centric, just doesn't offer the I/O addresses by default, even with a different name, as a design choice?

 

clawson wrote:
But if I build the above using the commands you showed I would get an error about "main undefined". That is because, by default the linker will link in the CRT file for the build target and as well as an interrupt vector table it ends by doing an "RCALL main" on the basis that usually it works with C code and there will be a function called main(). But I want to start my asm with "entry:" and what's more I want entry: to be at 0x0000 in flash. So to your other build options I would add -nostartfiles when writing "raw Asm".
Then either your compiler and mine behave differently, or you didn't copy the command fully. :)

-nostdlib already implies -nostartfiles together with the other two "-no" options, -nodefaultlibs and -nolibc, as documented here.

Last Edited: Thu. Jan 23, 2020 - 05:52 PM
  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

See Tip #5 (in my signature, below; may not be visible on mobile) for how to tell the forum that a question is solved

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...
This reply has been marked as the solution. 
  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 1

awneil wrote:

See Tip #5 (in my signature, below; may not be visible on mobile) for how to tell the forum that a question is solved

Actually, that technically doesn't work. I solved the issue in the opening post, and the forum software doesn't allow the opening post to be marked as a solution, only replies. I could mark a reply as the solution just to be done with it, but that wouldn't be the post containing the solution to the stated question! Something to think about.

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

You could raise that in the Site Feedback forum:

 

https://www.avrfreaks.net/forums/site-feedback

 

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...