質問をすることでしか得られない、回答やアドバイスがある。

15分調べてもわからないことは、質問しよう!

新規登録して質問してみよう
ただいま回答率
85.48%
アセンブリ言語

アセンブリ言語とは、機械語を人間にわかりやすい形で記述した低水準言語です。

C

C言語は、1972年にAT&Tベル研究所の、デニス・リッチーが主体となって作成したプログラミング言語です。 B言語の後継言語として開発されたことからC言語と命名。そのため、表記法などはB言語やALGOLに近いとされています。 Cの拡張版であるC++言語とともに、現在世界中でもっとも普及されているプログラミング言語です。

Q&A

解決済

3回答

1353閲覧

アセンブリ言語で読めない箇所があります。

strike1217

総合スコア651

アセンブリ言語

アセンブリ言語とは、機械語を人間にわかりやすい形で記述した低水準言語です。

C

C言語は、1972年にAT&Tベル研究所の、デニス・リッチーが主体となって作成したプログラミング言語です。 B言語の後継言語として開発されたことからC言語と命名。そのため、表記法などはB言語やALGOLに近いとされています。 Cの拡張版であるC++言語とともに、現在世界中でもっとも普及されているプログラミング言語です。

0グッド

2クリップ

投稿2017/07/10 11:28

編集2017/07/11 04:52

ポインタを使用するプログラムです。

C

1 1 #include<stdio.h> 2 2 #include<ctype.h> 3 3 4 4 char *test(char *buf){ 5 5 char *p; 6 6 int c; 7 7 p = buf; 8 8 9 9 while((c = *p) != 0){ 10 10 if(islower(c)) 11 11 *p = (char)toupper(c); 12 12 p++; 13 13 } 14 14 return buf; 15 15 } 16 16 17 17 int main(){ 18 18 char s[] = "you will make me happy\n"; 19 19 printf("%s\n", test(s)); 20 20 21 21 return 0; 22 22 } 23 23

コンパイルしたものを書きます。

.file "pointer_arg.c" .text .globl test .type test, @function test: .LFB2: .cfi_startproc pushq %rbp .cfi_def_cfa_offset 16 .cfi_offset 6, -16 movq %rsp, %rbp .cfi_def_cfa_register 6 subq $32, %rsp movq %rdi, -24(%rbp) movq -24(%rbp), %rax movq %rax, -8(%rbp) jmp .L2 .L4: call __ctype_b_loc@PLT movq (%rax), %rax movl -12(%rbp), %edx movslq %edx, %rdx addq %rdx, %rdx addq %rdx, %rax movzwl (%rax), %eax movzwl %ax, %eax andl $512, %eax testl %eax, %eax je .L3 movl -12(%rbp), %eax movl %eax, %edi call toupper@PLT movl %eax, %edx movq -8(%rbp), %rax movb %dl, (%rax) .L3: addq $1, -8(%rbp) .L2: movq -8(%rbp), %rax movzbl (%rax), %eax movsbl %al, %eax movl %eax, -12(%rbp) cmpl $0, -12(%rbp) jne .L4 movq -24(%rbp), %rax leave .cfi_def_cfa 7, 8 ret .cfi_endproc .LFE2: .size test, .-test .globl main .type main, @function main: .LFB3: .cfi_startproc pushq %rbp .cfi_def_cfa_offset 16 .cfi_offset 6, -16 movq %rsp, %rbp .cfi_def_cfa_register 6 subq $32, %rsp movabsq $7812735413947559801, %rax movq %rax, -32(%rbp) movabsq $7308533390257515808, %rax movq %rax, -24(%rbp) movabsq $2948273595836448, %rax movq %rax, -16(%rbp) leaq -32(%rbp), %rax movq %rax, %rdi call test movq %rax, %rdi call puts@PLT movl $0, %eax leave .cfi_def_cfa 7, 8 ret .cfi_endproc .LFE3: .size main, .-main .ident "GCC: (Debian 6.3.0-18) 6.3.0 20170516" .section .note.GNU-stack,"",@progbits

test()に入ったあとなんですが、、、、
-24(%rbp) = buf
-8(%rbp) = p
-12(%rbp) = c

となっています。(間違っていたらご指摘ください。)

call __ctype_b_loc@PLT movq (%rax), %rax movl -12(%rbp), %edx movslq %edx, %rdx addq %rdx, %rdx addq %rdx, %rax movzwl (%rax), %eax movzwl %ax, %eax andl $512, %eax testl %eax, %eax

読めない箇所はここです。

一体何をやっているんでしょうか?
足し算なんてCのプログラム内にはインクリメント以外出てきていません。
なぜ、こんなにadd命令が多いのでしょう?(512なんて知りません。)

__ctype_b_loc@PLTのパラメータはその直前のeaxレジスタ経由でしょうか?
rdiはインクリメントによって変化していないので、eax以外は考えられませんが・・・
PLT経由の関数の呼び出しはシステムコールの時とは違ってパラメータ用のレジスタは決まっていないということですかね・・・・
この関数はislower()に相当するかと思います。

movq (%rax), %rax
わざわざカッコを付けている理由はなんでしょうか?
() ・・・括弧内のレジスタにアドレスが入っていたら、()はC言語で言う所の間接演算子(*)と同じ効果という理解で正しいでしょうか?
この行はなぜ必要なんですか?

testl %eax, %eax
同じレジスタのANDを取ってどうするんでしょうか??
意味がよく分かりません。

どなたか教えてください。
Linux 64bit Debianです。

[追記]
私の本のなかでは、islower()の呼び出しは以下のようになっています。
movl -12(%rbp), %eax
movl %eax, %ecx
movq __imp_islower(%rip), %rax
call *(%rax)

call命令の際のレジスタについているアスタリスクはなんのために付いているのでしょうか?
こちらの方が分かりやすいですね。

[追記2]
最適化-O2でやったコードを載せます。

.file "pointer_arg.c" .text .p2align 4,,15 .globl test .type test, @function test: .LFB15: .cfi_startproc pushq %r13 .cfi_def_cfa_offset 16 .cfi_offset 13, -16 pushq %r12 .cfi_def_cfa_offset 24 .cfi_offset 12, -24 movq %rdi, %r13 pushq %rbp .cfi_def_cfa_offset 32 .cfi_offset 6, -32 pushq %rbx .cfi_def_cfa_offset 40 .cfi_offset 3, -40 subq $8, %rsp .cfi_def_cfa_offset 48 movsbq (%rdi), %rbx testb %bl, %bl je .L10 call __ctype_b_loc@PLT movq %r13, %rbp movq %rax, %r12 .p2align 4,,10 .p2align 3 .L4: movq (%r12), %rax testb $2, 1(%rax,%rbx,2) je .L3 call __ctype_toupper_loc@PLT movq (%rax), %rax movl (%rax,%rbx,4), %eax movb %al, 0(%rbp) .L3: addq $1, %rbp movsbq 0(%rbp), %rbx testb %bl, %bl jne .L4 .L10: addq $8, %rsp .cfi_def_cfa_offset 40 movq %r13, %rax popq %rbx .cfi_def_cfa_offset 32 popq %rbp .cfi_def_cfa_offset 24 popq %r12 .cfi_def_cfa_offset 16 popq %r13 .cfi_def_cfa_offset 8 ret .cfi_endproc .LFE15: .size test, .-test .section .text.startup,"ax",@progbits .p2align 4,,15 .globl main .type main, @function main: .LFB16: .cfi_startproc subq $40, %rsp .cfi_def_cfa_offset 48 movabsq $7812735413947559801, %rax movq %rax, (%rsp) movabsq $7308533390257515808, %rax movq %rsp, %rdi movq %rax, 8(%rsp) movabsq $2948273595836448, %rax movq %rax, 16(%rsp) call test movq %rax, %rdi call puts@PLT xorl %eax, %eax addq $40, %rsp .cfi_def_cfa_offset 8 ret .cfi_endproc .LFE16: .size main, .-main .ident "GCC: (Debian 6.3.0-18) 6.3.0 20170516" .section .note.GNU-stack,"",@progbits

気になる質問をクリップする

クリップした質問は、後からいつでもMYページで確認できます。

またクリップした質問に回答があった際、通知やメールを受け取ることができます。

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

guest

回答3

0

ベストアンサー

アセンブルしたものを書きます。

それ、まだアセンブルしていないから笑。コンパイル(してアセンブリコードを生成)しただけです。
俺にもわからない事だらけのアセンブリコードだけど、大まかな想像はつきます。

この関数はislower()に相当するかと

そう、この問題は islower() だ。では islower() って、何だ?

足し算なんてCのプログラム内にはインクリメント以外出てきていません。
なぜ、こんなにadd命令が多いのでしょう?(512なんて知りません。)

君が足し算を書いていないのに、って思い上がるな(笑)。islower()を君が書いたわけではあるまい。でも、でも調べる手がかりはあるでしょ。512の根拠は簡単にわかったぞ。

movq (%rax), %rax
括弧内のレジスタにアドレスが入っていたら、()はC言語で言う所の間接演算子(*)と同じ効果?

言うまでもないほど当たり前の事を言うが、レジスタにも、メモリにも、常に何か値が入っている。値が入っていない事なんて、ない。
「レジスタにアドレスが入っていたら」ではなく、「レジスタ%raxの値を、メモリアドレスとして、そのメモリの値を%raxに読み込む」、それだけ。rax = *rax; みたいな事です。

同じレジスタのANDを取ってどうするんでしょうか??

testl命令だけを見たら分からないかもしれないが、

andl $512, %eax
testl %eax, %eax
je .L3

je命令は条件分岐命令です。どんな条件で分岐するか、調べよ。testl命令の意味も、そこにある。このプロセッサのアセンブリ言語で、この3命令は決まり文句の一つと言っていい。

私の本のなかでは、islower()の呼び出しは以下のようになっています

その本は、ほぼ関数呼出でislower()を実現してるようです。それに対して今見てるコードは、islower()をインライン展開で実現してるようです。コンパイラが、どんなコードを生成するかは、コンパイラによっても、コンパイル条件(最適化オプション等々)によっても、違いが生じます。当たり前。

投稿2017/07/10 22:27

rubato6809

総合スコア1380

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

strike1217

2017/07/11 00:57

あ、すいません。アセンブルの方は修正しますね。
strike1217

2017/07/11 01:16

http://kira000.hatenadiary.jp/entry/2014/08/26/052447 TEST TEST EAX,EAX if(EAX==0) ZF = 1 EAXの値を0と比較してフラグに反映 else ZF = 0 EAXが0と等しければZF=1,EAXが0でなければZF=0 JE(JZ) JE 041001000 if(ZF == 1) ZFが1なら041001000にジャンプ GOTO 041001000 512?? 意味が分からないです・・・・ 「この3命令は決まり文句の一つと言っていい。」 そうなんですか!
strike1217

2017/07/11 01:45 編集

「rax = *rax; みたいな事です。 」 待ってください。 islower()の戻り値は0か0以外です。 raxは関数の戻り値を入れるのに使用されるはずです。 なぜ「%raxの中にアドレスが入っている」・・・という事になるのでしょうか? この関数の場合、戻り値はポインタではなく、値ですよね・・・・
strike1217

2017/07/11 01:58

__ctype_b_loc@PLT に入る直前は、rax = 0x79(121) その直後は、rax = 0x7ffff7fce6b0 movq (%rax), %rax で、rax = 0x7ffff7b866c0に変化しています。 movslq %edx, %rdx rdx = 0x79(121) movzwl (%rax), %eax rdx = 0xf2(242), rax = 0xc608(50696) andl $512, %eax rax = 0x200(512) となっていました。
fuzzball

2017/07/11 03:49 編集

2つ上 >>islower()の戻り値は0か0以外です。 なんでislower()の話をしているのだろうか? __ctype_b_locは、 const unsigned short * * __ctype_b_loc (void); と定義されている。 short**だから、(rax)にrdx*2を足した上で、(rax)してる。
nob.

2017/07/11 02:24

横から失礼します。 andl $512, %eax testl %eax, %eax は小文字のビットをテストしているのでしょう。 ctype.h の中で小文字を 0x200 で定義してるんじゃないでしょうか? (大文字なのかも知れない・・・) andlでゼロフラグが立てば次の test 命令はいらないと思いますが、and では立たないんだっけ?
nob.

2017/07/11 02:32

今調べてみました。 ubuntu 16.04 の /usr/include/ctype.h では enum として _ISlower = _ISbit (1), /* lowercase. */ _IScntrl = _ISbit (9), /* Control character. */ ですね。 なんか、的外れなことを言ってるよう泣きが・・・・
strike1217

2017/07/11 02:56

返り値がポインタのポインタになっているということですか? ?そうなの?
fuzzball

2017/07/11 03:49 編集

shortは2バイト。たぶん。sizeofで調べて下さい。
strike1217

2017/07/11 03:08

short = 2B ・・・・ 2 ^ 16 = 65536 ・・・全く関係ないですね。 movl -12(%rbp), %edx movslq %edx, %rdx addq %rdx, %rdx addq %rdx, %rax rdx には、Cの値が入ります(アドレスですよね) C = C+C; rax = rax + C; int 型からshortへのキャスト・・・・おお? いや、違うかな・・・・・
fuzzball

2017/07/11 03:50 編集

(deleted)
strike1217

2017/07/11 03:31

! __ctype_b_loc = islower()と同義なのかと勘違いしていました。 call __ctype_b_loc@PLT movq (%rax), %rax movl -12(%rbp), %edx movslq %edx, %rdx addq %rdx, %rdx addq %rdx, %rax movzwl (%rax), %eax movzwl %ax, %eax andl $512, %eax testl %eax, %eax どこまでかは正確には分からないのですが、このあたりまでのコードで、islower()を実現しているということですか! 「それに対して今見てるコードは、islower()をインライン展開で実現してるようです。」 やっとこれの言っていることの意味がわかりました。
fuzzball

2017/07/11 03:51 編集

各文字のフラグ。フラグというのはislower、isupper、isdigitなどのフラグ。ctype.hを見れば分かります。(なんで直値で書かれているのかは分かりませんが) nob.さんが書いていたのはこれのことで、512 = 0x200 = islowerのフラグではないか?という推測でした。 p.s. 勘違いしてなさそうだったので削除していたコメントは復活させました。
strike1217

2017/07/11 03:54 編集

#define __isctype(c, type) ((*__ctype_b_loc())[(int) (c)] & (unsigned short int )type) #define islower(c) __isctype((c), _ISlower) となっていました。 以下はnobさんと同じですね。 _ISlower = _ISbit (1), /* lowercase. */ #defien _ISbit(bit) ((bit) < 8 ? ((1<<(bit)) << 8) : ((1 << (bit)) >> 8)) になってますね。
fuzzball

2017/07/11 03:56

_ISbit (1) = 0x200 でbingo。
strike1217

2017/07/11 03:58

おおお! すごい! やっと見つかった感じですかね!
strike1217

2017/07/11 04:03 編集

_ISlower = 0x200なので、 #define islower(c) ((*__ctype_b_loc())[(int) (c)] & (unsigned short int )_ISlower) これをインライン展開(?)したら、質問中のアセンブリプログラムが出現するわけですね! 関数で実装されているものだと勘違いしていました。 マクロで実装されているから、自分の書いたものとは関係のないものが記述されていたわけですね!
fuzzball

2017/07/11 04:06

分からないことを放置して先に進むからこうなる。時間の無駄。
rubato6809

2017/07/11 04:59

nob. さん > andlでゼロフラグが立てば次の test 命令はいらないと思いますが、and では立たないんだっけ? はい。その通りです。なので、and, or 等のビット論理演算命令の直後に test 命令でフラグを変化させ、判定する。これがこの石の定石。
strike1217

2017/07/11 05:05

and 命令だけでは判定ができないので、test 命令でフラグを変化させ、判定する。 ほおぉ・・・左様ですか。
fuzzball

2017/07/11 05:14

>>rubato6809さん え!andはZF変化しますよね?
strike1217

2017/07/11 05:20

ん? 最初の質問のアセンブリコード testl %eax, %eax これをコメントアウトしてみました。 正常に動作しますよ!
strike1217

2017/07/11 05:21 編集

例の謎の、movl 0x0, %eax と同じような不要なコードという事になりますが・・・
strike1217

2017/07/11 05:30

andl $512, %eax testl %eax, %eax 論理積を取るものがお互い異なるので、仮にandlでフラグが変化しても、testl命令の際の論理積で、フラグが同じ値に変化するとは限らないような気がするんですが・・・・ andl命令でフラグを変化できないための補うtestl命令なら、testl $512, %eaxとしなくてはいけないのではないでしょうか?
rubato6809

2017/07/11 05:45 編集

> え!andはZF変化しますよね? え?そうでしたっけ?この辺りが68Kなんかと違ったと記憶してましたが??? だとしたら、gccのコード生成、ダサすぎじゃあ。。。
fuzzball

2017/07/11 05:44

68kと違うのはmovでフラグが変化するかどうか、ってやつじゃないですかねw
guest

0

間違いを教えながらベストアンサーにしてもらったままでは申し訳ないので、少しサービス(笑)。

call *(%rax)

%raxに関数のポインタが入ってる場合、*を付けるという理解で正しいですよね。

違う。
絶対アドレス(absolute)の場合は * を付ける。
相対アドレス(PC relative)の場合は付けない。

違うんですか・・・・同じことだと思ったのですが・・・・

命令が同じでも、オペランドの形式が異なると操作対象が異なる、即ち機械語の動作が異なる。いわゆるアドレッシングモードの件。
上のやり取りを見て、call命令のアドレッシングモードがややこしく感じたので、思いつく限りの呼出方を並べて、as はどう扱うのか試してみました。
subr: は、呼ばれると %rax を +1 して返す。これを、aFunc: は何度も呼び出す(acode.s)。

.section .rodata xx: .quad subr .text subr: inc %rax # ++rax ret .global aFunc aFunc: mov $0, %rax call subr # 最も普通 call (subr) # 上と同じコード call *(xx) # xx経由 call *xx # xx経由 mov $subr, %rdx # 絶対アドレスをロード call *%rdx # call %rdx # Warning lea subr(%rip), %rdx # 実効アドレスをロード, PIE call *%rdx # call %rdx # Warning lea xx(%rip), %rdx # アドレスが置かれたメモリのアドレスをロード call *(%rdx) # xx経由 call (%rdx) # Warning ret

呼出側(ccode.c)。

C

1#include <stdio.h> 2int aFunc(void); 3int main(void) 4{ 5 printf("subr() has been called %d times.\n", aFunc()); 6 return 0; 7}

コンパイルと動作確認はシンプルに。

sh

1$ cc ccode.c acode.s 2acode.s: Assembler messages: 3acode.s:18: Warning: indirect call without `*' 4acode.s:22: Warning: indirect call without `*' 5acode.s:26: Warning: indirect call without `*' 6$ ./a.out 7subr() has been called 10 times.

アセンブラが警告warningを出す命令は、直前の命令と同じ機械語が生成されることが確認できるはず。「お前、手を抜いて''を省いたな。今回は''を補ってアセンブルしてやるから、次はちゃんと書けよ(笑)」。ちなみに、手元のasはバージョン2.26.1。

さて、callに限らず、分岐命令とは、CPU内部で命令ポインタ%ripの値を変更する命令です。
何の値が%ripに代入されるかという違いがcall命令のアドレッシングモードの違いです。試した命令は次の4種類に整理できそうです。

1.「call ラベル」「call (ラベル)」
例:"call subr", "call (subr)"
前者は最も一般的な形式。機械語に含まれる(機械語にエンコードされる、とも言う)のはラベルまでの距離。いわゆるPC相対分岐です。
%rip = %rip + ラベルまでの距離

2.「call *ラベル」「call *(ラベル)」
例:"call *xx", "call *(xx)"
%rip = ???

3.「call *%レジスタ」「call %レジスタ」
例:"call *%rdx", "call %rdx"
%rip = ???

4.「call *(%レジスタ)」「call (%レジスタ)」
例:"call *(%rdx)", "call (%rdx)"
%rip = ???

%raxに関数のポインタが入ってる場合、*を付けるという理解で正しいですよね

というような、字面・上辺だけで早合点しようとするのではなく、(少なくとも一度は)具体的に・深く・何か工夫して・予想を立てられるなら、それに基づいて・自分の手を動かして・確かめて欲しいものです。ということで、こんな確かめ方もあるよという紹介をしたので、2.〜4.は???の部分をstrike君への穴埋め問題とします笑。技術的に通じる日本語で回答するように。

投稿2017/07/12 05:15

rubato6809

総合スコア1380

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

strike1217

2017/07/12 06:31

あ、ありがとうございます。 ちょうどアスタリスクが理解不足だったので!
strike1217

2017/07/12 08:58

「*」はjmp命令やcall命令以外にも使用可能ですか?(jmpとcallしか見たことがないです。)
rubato6809

2017/07/12 13:45

さあね。 どの命令で使えると嬉しいですか?その命令で試してみるといいよ。 アセンブラがエラーにしなきゃ、使えるってこと。
strike1217

2017/07/13 07:05 編集

mov $subr, %rdx # 絶対アドレスをロード call *%rdx これだけできなんですが、アセンブルエラーです。 $は即値のsyntaxですよね。 ラベルに付けられるんですか?
strike1217

2017/07/13 07:18

call *(xx) # xx経由 call *xx # xx経由 こちらもエラーですね。 これができるなら、call *subr もできるはずです。 アスタリスクは、絶対アドレスが入っているレジスタに対する構文ではないでしょうか?
strike1217

2017/07/13 07:29

レジスタに相対アドレスを書く・・・・なんて出来ません。 なので、レジスタに関数へのポインタを入れれば、その時点で絶対アドレスとして扱われるはずです。 「%raxに関数のポインタが入ってる場合、*を付けるという理解で正しいですよね。」 要は同じことですよね。 レジスタに入る関数のポインタは必ず絶対アドレスになるので・・・・ 例外があれば教えてください。
strike1217

2017/07/13 07:45 編集

call subr # 最も普通 call (subr) これが出来ることの意味は、括弧もラベルに対しても構文ではなく、レジスタに対するものだということが分かります。(ラベルに対しては付けても付けなくもおk!) もう1つおかしな部分は、上で書いた事以外に call *(xx) call *xx は、xxはポインタのポインタになっています。 call xx ならエラーは出ませんが、実行するとsegmentation faultです。
rubato6809

2017/07/13 14:14

> mov $subr, %rdx # 絶対アドレスをロード > call *%rdx どちらの行がアセンブルエラーになるのですか?それとも両方?他にもエラーになる行がありますか? 要するに、エラー報告として、なってない。どの行がエラーになったのか、不正確・曖昧。念の為、エラーメッセージも見せてもらいたいね。 > これだけできなんですが、アセンブルエラーです(←通じない日本語w) 私は、私の手元で、エラーにならず動作するコードを紹介しました。 アセンブルエラーになるなら、asのバージョンが違うのかもね。君はasのバージョンを確かめましたか? > アスタリスクは、絶対アドレスが入っているレジスタに対する構文ではないでしょうか? 君の「絶対アドレスが入っているレジスタに対する構文」という言い方が、私には逆立ちして聞こえます。機械語の動作やアセンブリ言語の表記は、(「このレジスタには絶対アドレスが入っているぞ!・入ってるはずだ!」「こっちのレジスタに入っている値はアドレスではない」といった)君の主観(或いは評価)で決まるのではないからです。 私なりに言い換えれば、「この構文でアセンブルされた機械語は、レジスタの値を(絶対)アドレスとして扱う(その結果、〜〜へ飛ぶ)」です。 > レジスタに相対アドレスを書く・・・・なんて出来ません レジスタに、飛び先までの距離(を相対アドレスと呼ぶなら)をロードする事なら、可能ですよ。そうするための、アセンブリコードの書き方はあります。 > call xx ならエラーは出ませんが、実行するとsegmentation faultです それは当然の結果でしょう。ならなかったら奇跡w。 だけど君は、その理由が理解できていないようだ。違いますか?
rubato6809

2017/07/14 01:15

> アスタリスクは、絶対アドレスが入っているレジスタに対する構文 に似た気持ちを表現するなら 「レジスタの値は絶対アドレスである、とCPUに解釈させる構文が'*'」ということかな。
strike1217

2017/07/14 01:55

「レジスタの値は絶対アドレスである、とCPUに解釈させる構文が'*'」なら call *xx なぜラベルに'*'を付けられるんでしょうか? call *xxこれができるのに、なぜcall *subrは出来ないんですか? アセンブルバージョンとエラーは後で載せます。少々お待ちを!
strike1217

2017/07/14 02:01

call *(xx) # xx経由 call *xx # xx経由 mov $subr, %rdx # 絶対アドレスをロード call *%rdx # これができません。 残りのは問題ないですね。 上にも書きましたが、$subr $は即値の構文ではないのですか? なんでラベルに付けられるんでしょう?
rubato6809

2017/07/14 02:02

穴埋め問題の回答は、まだですか? 案外、大事だと私は思っているのでね、よろしく〜w
strike1217

2017/07/14 02:13 編集

例えば、call *xxを追加しただけで・・・・ /usr/lib/gcc/x86_64-linux-gnu/6/../../../x86_64-linux-gnu/Scrt1.o: 関数 `_start' 内: (.text+0x20): `main' に対する定義されていない参照です /usr/bin/ld: 最終リンクに失敗しました: 無効な操作です collect2: error: ld returned 1 exit status となります。 gasのエラーというより、リンカのエラーですね。 アドレス解決ができていなんですかね・・・・(わからない) 私も初心者なので、分かりませんが、とりあえずエラーの出ていない穴埋め問題にチャレンジしますわ。 エラーが出ている文の文法がちょっと理解できないです。
strike1217

2017/07/14 02:16

どう回答すれば良いのか分からないんですが・・・ 3. %rip = %rdx 4. %rip = %rdxのアドレスが示してるアドレス(ポインタのポインタ) という感じでしょうか?
strike1217

2017/07/14 02:37

gcc (Debian 6.3.0-18) 6.3.0 20170516 かなり新しいですね。rolloing editionなので
rubato6809

2017/07/14 02:40 編集

> 例えば、call *xxを追加しただけで・・・・ > /usr/lib/gcc/x86_64-linux-gnu/6/../../../x86_64-linux-gnu/Scrt1.o: 関数 `_start' 内: > (.text+0x20): `main' に対する定義されていない参照です ??? 2つのソースファイル(ccode.c と acode.s)は私と同じにしたか?どのようにコンパイルしたか?私が示したやり方と同じか?どこに、どう「”call *xx”を追加」したか? アセンブラのバージョンは $ as -v とすれば表示される(標準入力待ちになるので、CTRL-Dを打たないと終わらない)。
strike1217

2017/07/14 02:42

コンパイルのやり方は、rubato6809さんと同じですよ。 最初にエラーが出てきたので、他のやり方でも試してみましたが・・・
rubato6809

2017/07/14 02:46

gcc (Debian 6.3.0-18) 6.3.0 20170516 は、私のgcc version 5.4.0 20160609 より新しいので、私のasより古いはずはなかろう。そうすると、エラーの原因は、私と同じやり方をしていないから、即ち、早とちりして、自分勝手なやり方で試したから、という想像が成り立つ。
strike1217

2017/07/14 02:47

いえ!、同じようにやりました。
strike1217

2017/07/14 02:50 編集

コンパイルも同じです。 今再度やり直しました。 それ以前に、文法的も少々納得がいかな部分があるんですが・・・
rubato6809

2017/07/14 02:51

同じファイルで、同じやり方だ、というなら、 $ as acode.s としてみなさい。私だと、次の4行が表示され、a.out ファイルが作られ、正常終了する。 acode.s: Assembler messages: acode.s:18: Warning: indirect call without `*' acode.s:22: Warning: indirect call without `*' acode.s:26: Warning: indirect call without `*'
rubato6809

2017/07/14 02:54

as -a acode.s とすれば、アセンブルリストを表示する。
strike1217

2017/07/14 02:54

それもやりました。 同じくエラーはないですね。
strike1217

2017/07/14 02:57

ダメですね。gasの方は出来ても、リンカのアドレス解決ができていないようです。 私の回答の答え合わせを・・・お願いします!
rubato6809

2017/07/14 02:59

Warning は出ますか? アセンブルエラーにならないなら、アセンブリ言語上の文法エラーは無い、という事だ。すると、リンク上のエラーだ。 君のソースコードをみせなさい。どこか何か、書き間違いをしているに違いない。
strike1217

2017/07/14 03:03 編集

何度もエラーが出てきて出来なかったので、rubato6809さんのをコピー&ペーストしました。 全く同じですよ。 > 最終リンカに失敗しました:出力に対するセクションがありません とのことです。 私の回答の答え合わせを!
rubato6809

2017/07/14 03:06

> rubato6809さんのをコピー&ペーストしました。全く同じ ではシステムの環境を、どちらかに一致させてみないと再現できないかもね。私はそこまで付き合うつもりは無いので。
strike1217

2017/07/14 03:10

あら・・・・ 別のLinux mintを使ってやってみました。 できました!! それで・・・私の回答の答え合わせをお願いします。
strike1217

2017/07/14 03:12

こちらのlinuxはgccのバージョンが古いですね。 古い方だとできるのかな?
strike1217

2017/07/14 05:04

これについては再度質問します。
guest

0

コメントが長くなってしまったので、こちらに書きますね。

#define islower(c) ((*__ctype_b_loc())[(int) (c)] & (unsigned short int )_ISlower)

andl $512, %eax
rax = 0x200(512)
の後・・・

testl %eax, %eax
これがまだ謎ですね・・・・同じものをAND取ってどうするのか分からないですね・・・・

C = C+C;
rax = rax + C;
あとこれの必要性も見えないです。

投稿2017/07/11 04:42

編集2017/07/11 04:44
strike1217

総合スコア651

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

fuzzball

2017/07/11 04:44

最適化かけても消えないですか?
strike1217

2017/07/11 04:46

gccでコンパイルの際には、最適化のオプションは入れていません。 -O0で最適化無効になるはずです。 最適化オプションなしのデフォルトでは、自動的に最適化されるんでしたっけ?
fuzzball

2017/07/11 04:48 編集

最適化したら「testl %eax, %eax」が無くなりませんか?という意味です。
strike1217

2017/07/11 04:50

試しに、gcc -O2 source.c -S でやってみました。
strike1217

2017/07/11 04:51

call __ctype_b_loc@PLT 28 movq %r13, %rbp 29 movq %rax, %r12 このようになりました。
strike1217

2017/07/11 04:51

ちょっと、分かりにくいので、質問の方に追記いたします。
fuzzball

2017/07/11 04:55

どうでもいいけど、回答欄に質問を書かないでください。
strike1217

2017/07/11 04:55

あれ?オプションなしでコンパイルすると自動的に最適化されなかったけ? ・・・・されないようですね。 「testl %eax, %eax」は、なくなりますね。 call __ctype_b_loc@PLTの後はすごく短くなりますね。
strike1217

2017/07/11 04:56

「回答欄に質問を書かないでください。」 あ、すいません。考察するスペースが欲しくて、つい・・・
strike1217

2017/07/11 05:07

andl $512, %eax この行までで、(*__ctype_b_loc())[(int) (c)] を算出し、(unsigned short int )_ISlowerとandを取っているんですね・・・ __ctype_b_loc()の内部と C = C+C; rax = rax + C; の関係が分からないですね・・・う~~~ん
fuzzball

2017/07/11 05:21

unsigned short table[] というテーブルの場合、&table[0] と &table[1] のアドレスの差が2なのは分かりますか?
strike1217

2017/07/11 05:23

static const unsigned short table[] はいはい!差分は2ですね!
fuzzball

2017/07/11 05:24

だからx2してるんですよ。
strike1217

2017/07/11 05:26

差分が2でx2・・・? それがどうして%rdxなんですか?
strike1217

2017/07/11 05:33

そもそも・・・ static const unsigned short *const ptable = table+128; return (void *)&ptable; これでは、ptableは常に同じ値になりますよね・・・・ パラメータによって変動しないので・・・ うう~~ん。頭が痛い(´Д`)ハァ…
fuzzball

2017/07/11 05:43 編集

>>それがどうして%rdxなんですか? movl -12(%rbp), %edx これ。 >>これでは、ptableは常に同じ値になりますよね・・・・ テーブルの先頭アドレスを取得する関数なのだから当たり前。 フラグを取り出す関数じゃないよ。 アセンブリ言語にはshort*なんて無い。全てvoid*だと思えばいい。 void*でshort*のテーブル(配列)にアクセスするなら添字は2倍になる。
strike1217

2017/07/11 06:47

「テーブルの先頭アドレスを取得する関数」 ほぇ?ptable = table+128; ptableは先頭ではないですよね? ptable = tableなら先頭ですが・・・ movq (%rax), %rax で rax = table+128(アドレス) その後、rax = table+128+%rdx(c)*2 その後、(%rax)&512
strike1217

2017/07/11 06:50

%rdx ことCは int 型ですが・・・
strike1217

2017/07/11 06:54

rax = table+128+%rdx(c)*2 これは・・・rax = table + 128 + (121)*2 ということですよね・・・
fuzzball

2017/07/11 06:59

>> ほぇ?ptable = table+128; ptableは先頭ではないですよね? だから「テーブル」と書いたのですが。 考え方の話です。
strike1217

2017/07/11 06:59

table+128は 大量の0を無視して一番最初の X(0x200)を指します。 そこから、(121)*2の要素って・・・最後の方の0・・・?
fuzzball

2017/07/11 07:04 編集

>>rax = table + 128 + (121)*2 ということですよね・・・ 違います。Cとアセンブリが混ざってます。 >>(121)*2の要素って・・・最後の方の0・・・? これも同様。
strike1217

2017/07/11 07:04

あら?違いますか rax = table+128+%rdx(c)*2 こちらは合っていますか?
fuzzball

2017/07/11 07:04

ちゃんと消化しなさい。
strike1217

2017/07/11 07:15 編集

うん? rax = table + 128で、rax = 0x7ffff7b866c0 rax = table + 128 + (121)*2 これで、0x7ffff7b867b2  ・・・・ありゃ? どうなってるんだろ・・・ 差は0x2fになってますね。242ですよ。
strike1217

2017/07/11 07:17

short = 2Bより table + 128 + 121の配列の位置ということですね!!
strike1217

2017/07/11 07:19

Cの値が121というのは、おかしいですよね? c = *p Cは一時的にポインタを入れる変数ですが・・・
fuzzball

2017/07/11 07:30

Cって大文字で書いているのは何か意味があるのでしょうか? char *p; int c; c = *p; でcにポインタが入っていると思っているのならC言語の勉強をやり直して下さい。
strike1217

2017/07/11 07:32

あ、ごめんなさい。 cはポインタではありませんでしたね。 すいません。 大文字は・・・・関係ないです。 すいません。
strike1217

2017/07/11 07:34

man ascii で y = 121になってますね。 ああああ~~やっと解決したぁぁ。 いやぁ 残りの強敵はこいつですかね。 testl %eax, %eax
strike1217

2017/07/11 07:43

call *(%rax) このアスタリスクについてもまだ未解決ですね。
fuzzball

2017/07/11 08:14

>>testl %eax, %eax ただの想像ですが、andl $512, %eax までがislower()のコード(インライン展開?)で、 testl %eax, %eax からが、呼び出し元のislower()の戻り値をチェックするコード。 この2つを単純にくっつけているために、接合部分に冗長なコードが残ってしまったような気がします。 >>call *(%rax) まずドキュメントを調べて下さい。何度同じことを‥。 AT&T absolute (as opposed to PC relative) jump/call operands are prefixed by `*'; they are undelimited in Intel syntax.
strike1217

2017/07/11 08:27

「この2つを単純にくっつけているために、接合部分に冗長なコードが残ってしまったような気がします。」 あ~ なるほど!
strike1217

2017/07/11 08:37 編集

This means it will jump to the address contained in the register. call *(%rax) %rax内がアドレスだった場合の関数の呼び出し方法という事ですかね。 関数のポインタのようなものですね。 call %raxではダメという事ですね。
strike1217

2017/07/11 08:32

フラグをセットするためのtest命令なら、 testl $512, %eax でなくてはならない気がするんですが・・・・
fuzzball

2017/07/11 08:45 編集

どこをどう読んだのか? * の意味は "absolute (as opposed to PC relative)" です。 >>フラグをセットするためのtest命令なら、 andl $512, %eax を実行後の eax の値は 0 か 512。 testl %eax, %eax は eax が 0 かどうかチェックしている。 eax == 0 なら ZF=1 eax != 0 なら ZF=0 以上。
strike1217

2017/07/11 08:52

andl $512, %eax を実行後の eax の値は 0 か 512。 ビット列でANDを取ったら、0か512? 2通りしかないってことですよね? ん?なんで?
fuzzball

2017/07/11 09:08

また脊髄反射。 何も考えずに質問して、回答が来たら納得はするけど何一つ身に付いていない。 分かった気になっているだけ。
strike1217

2017/07/11 09:13 編集

え、ちょっと待ってください。 andl $512, %eaxで、%eaxの中に、0以外の値が入ってたら、普通に0か512以外にも数字が出てきますが・・・ あ、すいません。 512 = 10000・・・ 勘違いしていました。 0か512以外は出てこないですね。
strike1217

2017/07/11 09:20 編集

call *(%rax) %raxに関数のポインタが入ってる場合、*を付けるという理解で正しいですよね。 http://d.hatena.ne.jp/pakepion/20081021/1224592877 ふぅ、解決いたしましたわ。 fuzzballさんに評価を入れられないので、rubato6809さんをBestAnswerにいたしますわ。
fuzzball

2017/07/11 09:21 編集

>>%raxに関数のポインタが入ってる場合、*を付けるという理解で正しいですよね。 違う。 絶対アドレス(absolute)の場合は * を付ける。相対アドレス(PC relative)の場合は付けない。 スルー耐性の高さだけは褒めてあげるよw
strike1217

2017/07/11 09:23

む! 違うんですか・・・・同じことだと思ったのですが・・・・
guest

あなたの回答

tips

太字

斜体

打ち消し線

見出し

引用テキストの挿入

コードの挿入

リンクの挿入

リストの挿入

番号リストの挿入

表の挿入

水平線の挿入

プレビュー

15分調べてもわからないことは
teratailで質問しよう!

ただいまの回答率
85.48%

質問をまとめることで
思考を整理して素早く解決

テンプレート機能で
簡単に質問をまとめる

質問する

関連した質問