I am currently developing software for the Atmel AVR32 AT32UC3C0512C. The software consists of C modules (.c files) as well as standalone assembler modules (.S files). My IDE is Microchip Studio 7.0.2594 (formerly known as Atmel Studio). The toolchain incorporates avr32-gcc 4.4.7.
In the assembler modules, I actually can access global variables that I have defined in the C modules, but the method I am using since many years seems quite dumb to me:
Suppose I have defined a global variable global_Test in a C file (e.g., unsigned long global_Test; in one of the C modules). In a standalone assembler .S module (important note: that is really an uppercase S, not a lowercase s), I can access the variable by the following method:
.pushsection .MySection, "ax", @progbits
.org 0x00000000
/* Define the function with appropriate scope */
.global MyFunc
.type MyFunc, @function
.balign 4
MyFunc:
/* Some code ... */
/* Load the variable address into R8 */
LDDPC R8, global_Test_Addr
/* Do something with the variable, e.g., set it to 1 */
MOV R9, 1
ST.W R8, R9
/* Further code ... */
ret
.type global_Test_Addr, @function
.balign 4
global_Test_Addr:
.long global_Test
This method works reliably, but as mentioned above, it seems dumb to me. It is clear that the address of the variable is known at compile time or link time, respectively, but I didn't find a way to use it in another way than shown above. For example, the following does not work:
.pushsection .MySection, "ax", @progbits
.org 0x00000000
/* Define the function with appropriate scope */
.global MyFunc
.type MyFunc, @function
.balign 4
MyFunc:
/* Some code ... */
/* Load the variable address into R8 */
MOV R8, global_Test & 0x0000FFFF
ORH R8, global_Test >> 16
/* Further code ... */
ret
With the above code, the assembler throws errors like
error: invalid operands (*UND* and *ABS* sections) for `&'
error: invalid operands (*UND* and *ABS* sections) for `>>'
In case somebody wonders: Loading a register like R8 in two steps is necessary because the AVR32 instruction set does not feature an instruction that loads a 32-bit immediate into a register at once.
I am aware that the MCU mentioned above has only 64 kB of internal RAM, and hence I simply could use MOV R8, global_Test, which works and does not lead to error messages.
However, I am interested in general why something simple like MOV R8, global_Test >> 16 leads to errors, especially taking into account that e.g. MOV R8, 123456789 >> 16 does not lead to errors. I don't get why the constant 123456789 is treated differently from the constant global_Test, which (in assembler code) is the address of global_Test and is evaluated at compile or linkage time.
Update / Additional information
I should have mentioned that I believe that the toolchain is constructed in a way that I wouldn't have expected. It seems that the assembler modules are not translated by a special assembler like gas, but by the normal avr32-gcc that also translates the C modules. That is, the (preprocessing) assembler is the same executable as the C compiler. When building the project, I see the following line in the output:
Invoking: AVR32/GNU Preprocessing Assembler : 4.4.7
"C:\Program Files (x86)\Atmel\Studio\7.0\toolchain\avr32\avr32-gnu-toolchain\bin\avr32-gcc.exe" -x assembler-with-cpp -c -mpart=uc3c0512c -I "C:\Program Files (x86)\Atmel\Studio\7.0\Packs\atmel\UC3C_DFP\1.0.49\include\AT32UC3C0512C" -I "../source" -I "C:\Program Files (x86)\Atmel\Studio\7.0\Packs\atmel\UC3C_DFP\1.0.77\include\AT32UC3C0512C" -MD -MP -MF "core/slave/tc-s.d" -MT"core/slave/tc-s.d" -MT"core/slave/tc-s.o" -Wa,-g -o "core/slave/tc-s.o" "../core/slave/tc-s.S"
I vaguely remember that I can invoke a different assembler if I change the file extension for the assembler module from an uppercase S to a lowercase s, but this didn't work a few moments ago (the same compiler / assembler was invoked). I'll have to investigate this.
gccon a.Sruns it through the C preprocessor (for#if/#define/#includeprocessing), then through the assembleras. That's all, no magic, same assembler you'd use with a.s. The hi/lo stuff is handled by the assembler not the preprocessor. As 0___________ says, look at C compiler output for a function the returns the address of a global, or which loads or stores a global, to see exactly what they're called in AVR32 syntax. The GAS manual might also say, but asking a compiler is easy in this case. (For load or store, hopefully can use lo(symbol) in an addr mode.)