[C言語]undefined reference to '__ashlsi3'
struct st_spi { /* struct SPI */
union { /* CTRL */
unsigned int DWORD;
struct {
unsigned int RESV1 :21;
unsigned char SSO :1;
unsigned char RESV4 :1;
unsigned char IE :1;
unsigned char IRRDY :1;
unsigned char ITRDY :1;
unsigned char RESV5 :1;
unsigned char ITOE :1;
unsigned char IROE :1;
unsigned char RESV6 :3;
} BIT;
} CTRL;
こんな構造体を宣言してから、BITアクセスの方法を検討。
SPI.CTRL.DWORD = SPI.CTRL.DWORD | (1<<4);
main関数内で上のように書いたら、エラー無し。
これでCTRLレジスタの4bit目をHに設定出来た。
$ bat.ccomp
INFO : gcc ---------------------------
INFO : as ---------------------------
INFO : ld ---------------------------
INFO : objcopy (srec) ----------------
INFO : objcopy (ihex) ----------------
ちなみにこのバッチは以下でCygwin上で実行してる。
#!/bin/csh -f
set src_name = uart_int
echo "INFO : gcc ---------------------------"
lm32-elf-gcc -c $src_name.c
echo "INFO : as ---------------------------"
lm32-elf-as startup.s -o startup.o
echo "INFO : ld ---------------------------"
lm32-elf-ld -Map $src_name.map -T memory.def startup.o $src_name.o -o $src_name
echo "INFO : objcopy (srec) ----------------"
lm32-elf-objcopy -O srec $src_name $src_name.srec
echo "INFO : objcopy (ihex) ----------------"
lm32-elf-objcopy -O ihex $src_name $src_name.hex
次に、main内の直書きではなくて関数化してみる。
void wr_1bit_h (int * reg_base){
*reg_base = *reg_base | (1<<4);
}
こんな関数を作って、mainから次のように呼び出し。
wr_1bit_h(&SPI.CTRL);
次のようなwarningが出るが、エラーは無い。
ちなみにこのワーニングは調べてみたが解決せず。ポインタの理解が間違っている事だと思うが。
シミュレーションでは、このままでも想定動作してたので一時的に放置。
$ bat.ccomp
INFO : gcc ---------------------------
uart_int.c: In function `main':
uart_int.c:170: warning: passing arg 1 of `wr_1bit_h' from incompatible pointer type
INFO : as ---------------------------
INFO : ld ---------------------------
INFO : objcopy (srec) ----------------
INFO : objcopy (ihex) ----------------
最後に、レジスタアドレスとbit番号を引数で渡すように関数を修正。
void wr_1bit_h (int * reg_base, int bit_num){
*reg_base = *reg_base | (1<}
関数を上のようにして、mainから下のように呼び出す。
wr_1bit_h(&SPI.CTRL, 4);
これをコンパイルすると、「undefined reference to `__ashlsi3'」と出た。
$ bat.ccomp
INFO : gcc ---------------------------
uart_int.c: In function `main':
uart_int.c:168: warning: passing arg 1 of `wr_1bit_h' discards qualifiers from pointer target type
INFO : as ---------------------------
INFO : ld ---------------------------
uart_int.o: In function `wr_1bit_h':
uart_int.c:(.text+0x220): undefined reference to `__ashlsi3'
INFO : objcopy (srec) ----------------
lm32-elf-objcopy: 'uart_int': No such file
INFO : objcopy (ihex) ----------------
lm32-elf-objcopy: 'uart_int': No such file
(2015.2.25追記)
ashlsi3不足に関して良い情報が見当たらない。
今不足している関数について、自分でアセンブラで自作出来ないものか?
そのためには、指定レジスタの指定ビットへHをライトする関数wr_1bit_hについて、
どこの機能が不足してるのか調べる。
リンカで問題あるため最終的なelfは生成されないが、オブジェクトファイルは出来てる。
objdumpで表示してみる。
lm32-elf-objdump.exe -d uart_int.o
:
000001ec:
1ec: 37 9c ff ec addi sp,sp,-20 → spに-20を加算したものをspへ格納
1f0: 5b 8b 00 0c sw (sp+12),r11 → r11の値をアドレス(sp+12)へ格納
1f4: 5b 9b 00 08 sw (sp+8),fp → fpの値をアドレス(sp+8)へ格納
1f8: 5b 9d 00 04 sw (sp+4),ra → raの値をアドレス(sp+4)へ格納
<ここまでで、この関数内で使用するr11、fp、raの値をspへ保存した>
1fc: 34 1b 00 14 mvi fp,20 → addi rd, r0, imm16の疑似命令。r0が0だから省略されてる?
200: b7 7c d8 00 add fp,fp,sp → add rX, rY, rZ。rYをrZへ加算しrXへ格納
204: 5b 61 00 00 sw (fp+0),r1 → r1の値をアドレス(fp+0)へ格納
208: 5b 62 ff fc sw (fp+-4),r2 → r2の値をアドレス(fp-4)へ格納
20c: 2b 61 00 00 lw r1,(fp+0) → fpに即値0を加えたアドレスの値をr1へ格納
210: 28 2b 00 00 lw r11,(r1+0) → r1に即値0を加えたアドレスの値をr11へ格納
214: 34 01 00 01 mvi r1,1 → addi rd, r0, imm16の疑似命令。r0が0だから省略されてる?
218: 2b 62 ff fc lw r2,(fp+-4) → (fp-4)の値をr1へ格納
21c: f8 00 00 00 calli 21c→ 戻りアドレス「PC+4」をraへ格納。それから21c(=PC+0x30)へ無条件分岐。ここが__ashlsi3に該当する模様。
220: b9 61 10 00 or r2,r11,r1 → r11とr1のORを取って、その結果をr2へ格納
224: 2b 61 00 00 lw r1,(fp+0) → (fp+0)の値をr1へ格納
228: 58 22 00 00 sw (r1+0),r2 → r2の値をアドレス(r1+0)へ格納
<ここから先で、main関数に戻るためr11、fp、raの値をspから復元させる>
22c: 2b 8b 00 0c lw r11,(sp+12) → (sp+12)の値をr11へ格納
230: 2b 9b 00 08 lw fp,(sp+8) → (fp+8)の値をfpへ格納
234: 2b 9d 00 04 lw ra,(sp+4) → (fp+4)の値をraへ格納
238: 37 9c 00 14 addi sp,sp,20 → spに20を加算したものをspへ格納
23c: c3 a0 00 00 ret → raのアドレスへ条件分岐
<スタックポインタ定義=0x20000000 +0x2000 -4>
. = 0x20000000 + (1024*8) - 4;
_sp_base = .;
<LatticeMico32 Processor Reference Manual>
ra= call命令における戻りアドレス保存用に使用される。しかしながら汎用レジスタ。
sp= 未使用領域の先頭を指す
fp= アクティブフレームで使用された領域の先頭を指す
参考:スタックポインタ、フレームポインタ
http://www.kijineko.co.jp/tech/creintro/stack.html