Mac OS XのasはIntel記法で同じラベルが2度出るとエラーになります。
$ cat intel.s .intel_syntax noprefix call foo call foo $ i386-darwin-as intel.s intel.s:3:suffix or operands invalid for `call'
この問題を修正するパッチを作成しました。
--- odcctools.orig/as/i386.c 2012-06-07 21:55:08 +0900 +++ odcctools/as/i386.c 2012-06-14 22:36:17 +0900 @@ -6917,6 +6917,7 @@ preceded by an offset modifier and if it's not an equate. */ if (intel_parser.op_modifier != T_OFFSET) { +#if 0 symbolS *symbolP; symbolP = symbol_find(prev_token.str); @@ -6925,6 +6926,7 @@ #else if (!symbolP || S_GET_SEGMENT(symbolP) != absolute_section) #endif +#endif intel_parser.is_mem = 1; } } @@ -7074,6 +7076,7 @@ preceded by an offset modifier and if it's not an equate. */ if (intel_parser.op_modifier != T_OFFSET) { +#if 0 symbolS *symbolP; symbolP = symbol_find(cur_token.str); @@ -7082,6 +7085,7 @@ #else if (!symbolP || S_GET_SEGMENT(symbolP) != absolute_section) #endif +#endif intel_parser.is_mem = 1; }
作業過程
パッチを作成するまでにやったことをまとめます。
AT&T記法ではエラーにならないことから、文法上の問題ではなくバグだと推測しました。
$ cat att.s call foo call foo $ i386-darwin-as att.s $ file a.out a.out: Mach-O object i386
エラーの文字列で検索すると停止箇所が分かりました。
i386.c: 2466-2472
if (t == current_templates->end) { /* We found no match. */ as_bad (_("suffix or operands invalid for `%s'"), current_templates->start->name); return 0; }
これはmatch_template()の中です。その関数の中の各所に以下のような通過ログ出力を埋め込み、分岐をトレースしました。原始的なprintfデバッグです。
printf("%s:%d\n", __FILE__, __LINE__);
Intel記法の処理では1回目と2回目のcallで分岐が異なります。AT&T記法の処理では分岐が同じことから、本来は必要ない分岐をしているのではないかと推測しました。
分岐箇所を絞り込んでいくと、symbol_find()の結果が1回目と2回目で異なることが分かりました。
i386.c: 7077-7085
symbolS *symbolP; symbolP = symbol_find(cur_token.str); #ifdef NeXT_MOD if (!symbolP) #else if (!symbolP || S_GET_SEGMENT(symbolP) != absolute_section) #endif intel_parser.is_mem = 1;
これはシンボルが既出かどうかを調べています。1回目はNULLですが、2回目は有効なポインタです。これが1回目と2回目で分岐が異なる原因です。
AT&T記法の処理ではsymbol_find()を行っていないことから、チェック不要と判断してコメントアウトしました。これが冒頭のパッチで、正常に動作しているようです。シンボルテーブルへの登録自体は別の箇所で行われているため、影響はないようです。
あくまで推測ですが、途中でシンボル関係の仕様が変わってsymbol_find()が不要になったのに、Intel記法は使われていないためキャッチアップされなかったような印象です。