目的
前回x86でC言語のキャストが、実際にどのように型変換を行っているかを調べた。
今回は32ビットARMで同じ検証をする。
C言語の型変換をx86アセンブリで確認する(int, short, float)
gcc -O0 -S test.c -o test.s
int -> short
intは4バイト
shortは2バイト
strh命令でr3レジスタの下位16ビットをメモリへ格納している。
ここでintからshortへ変換している。
int a=100;
short b=(short)a;
movs r3, #100
str r3, [r7, #4]
ldr r3, [r7, #4]
strh r3, [r7, #2] @ movhi
元のコード
int main(){
int a=100;
short b=(short)a;
return 0;
}
.arch armv7-a
.fpu vfpv3-d16
.eabi_attribute 28, 1
.eabi_attribute 20, 1
.eabi_attribute 21, 1
.eabi_attribute 23, 3
.eabi_attribute 24, 1
.eabi_attribute 25, 1
.eabi_attribute 26, 2
.eabi_attribute 30, 6
.eabi_attribute 34, 1
.eabi_attribute 18, 4
.file "test.c"
.text
.align 1
.global main
.syntax unified
.thumb
.thumb_func
.type main, %function
main:
@ args = 0, pretend = 0, frame = 8
@ frame_needed = 1, uses_anonymous_args = 0
@ link register save eliminated.
push {r7}
sub sp, sp, #12
add r7, sp, #0
movs r3, #100
str r3, [r7, #4]
ldr r3, [r7, #4]
strh r3, [r7, #2] @ movhi
movs r3, #0
mov r0, r3
adds r7, r7, #12
mov sp, r7
@ sp needed
ldr r7, [sp], #4
bx lr
.size main, .-main
.ident "GCC: (Debian 12.2.0-14+deb12u1) 12.2.0"
.section .note.GNU-stack,"",%progbits
short -> int
ldrshは16ビットの符号を保ったままビットに広げる命令
short b=100;
int a=(int)b;
movs r3, #100
strh r3, [r7, #6] @ movhi
ldrsh r3, [r7, #6]
str r3, [r7]
元のコード
int main(){
short b=100;
int a=(int)b;
return 0;
}
.arch armv7-a
.fpu vfpv3-d16
.eabi_attribute 28, 1
.eabi_attribute 20, 1
.eabi_attribute 21, 1
.eabi_attribute 23, 3
.eabi_attribute 24, 1
.eabi_attribute 25, 1
.eabi_attribute 26, 2
.eabi_attribute 30, 6
.eabi_attribute 34, 1
.eabi_attribute 18, 4
.file "test.c"
.text
.align 1
.global main
.syntax unified
.thumb
.thumb_func
.type main, %function
main:
@ args = 0, pretend = 0, frame = 8
@ frame_needed = 1, uses_anonymous_args = 0
@ link register save eliminated.
push {r7}
sub sp, sp, #12
add r7, sp, #0
movs r3, #100
strh r3, [r7, #6] @ movhi
ldrsh r3, [r7, #6]
str r3, [r7]
movs r3, #0
mov r0, r3
adds r7, r7, #12
mov sp, r7
@ sp needed
ldr r7, [sp], #4
bx lr
.size main, .-main
.ident "GCC: (Debian 12.2.0-14+deb12u1) 12.2.0"
.section .note.GNU-stack,"",%progbits
int -> float
int a = 42;
float f;
f = (float)a;
movs r3, #42
str r3, [r7, #4]
ldr r3, [r7, #4]
vmov s15, r3 @ int42をFPレジスタs15に複製
vcvt.f32.s32 s15, s15 @ 32bit整数→32bit浮動小数点に変換
vstr.32 s15, [r7]
元のコード
int main() {
int a = 42;
float f;
f = (float)a;
return 0;
}
.arch armv7-a
.fpu vfpv3-d16
.eabi_attribute 28, 1
.eabi_attribute 20, 1
.eabi_attribute 21, 1
.eabi_attribute 23, 3
.eabi_attribute 24, 1
.eabi_attribute 25, 1
.eabi_attribute 26, 2
.eabi_attribute 30, 6
.eabi_attribute 34, 1
.eabi_attribute 18, 4
.file "test.c"
.text
.align 1
.global main
.syntax unified
.thumb
.thumb_func
.type main, %function
main:
@ args = 0, pretend = 0, frame = 8
@ frame_needed = 1, uses_anonymous_args = 0
@ link register save eliminated.
push {r7}
sub sp, sp, #12
add r7, sp, #0
movs r3, #42
str r3, [r7, #4]
ldr r3, [r7, #4]
vmov s15, r3 @ int
vcvt.f32.s32 s15, s15
vstr.32 s15, [r7]
movs r3, #0
mov r0, r3
adds r7, r7, #12
mov sp, r7
@ sp needed
ldr r7, [sp], #4
bx lr
.size main, .-main
.ident "GCC: (Debian 12.2.0-14+deb12u1) 12.2.0"
.section .note.GNU-stack,"",%progbits
float -> int
float f = 12.3;
int a;
a = (int)f;
movw r3, #52429
movt r3, 16708
str r3, [r7, #4] @ float
vldr.32 s15, [r7, #4]
vcvt.s32.f32 s15, s15 @ float → int に変換
vmov r3, s15 @ int
str r3, [r7]
元のコード
int main() {
float f = 12.3;
int a;
a = (int)f;
return 0;
}
.arch armv7-a
.fpu vfpv3-d16
.eabi_attribute 28, 1
.eabi_attribute 20, 1
.eabi_attribute 21, 1
.eabi_attribute 23, 3
.eabi_attribute 24, 1
.eabi_attribute 25, 1
.eabi_attribute 26, 2
.eabi_attribute 30, 6
.eabi_attribute 34, 1
.eabi_attribute 18, 4
.file "test.c"
.text
.align 1
.global main
.syntax unified
.thumb
.thumb_func
.type main, %function
main:
@ args = 0, pretend = 0, frame = 8
@ frame_needed = 1, uses_anonymous_args = 0
@ link register save eliminated.
push {r7}
sub sp, sp, #12
add r7, sp, #0
movw r3, #52429
movt r3, 16708
str r3, [r7, #4] @ float
vldr.32 s15, [r7, #4]
vcvt.s32.f32 s15, s15
vmov r3, s15 @ int
str r3, [r7]
movs r3, #0
mov r0, r3
adds r7, r7, #12
mov sp, r7
@ sp needed
ldr r7, [sp], #4
bx lr
.size main, .-main
.ident "GCC: (Debian 12.2.0-14+deb12u1) 12.2.0"
.section .note.GNU-stack,"",%progbits
まとめ
int -> short strh命令を使い、上位16ビットを切り捨てている。
short -> int ldrsh命令を使って拡張している。
int -> float vcvt.f32.s32命令を使って変換している。
float -> int vcvt.s32.f32命令を使って変換している。
動作環境(Linux / ARM 版)
OS: Armbian 23.08.0-trunk (Debian 12 Bookworm)
Kernel: Linux 6.1.38-meson (armv7l)
CPU: ARM Cortex-A5, 4 cores, Little Endian
GCC: 12.2.0
Architecture: armv7l
備考: Windows10からSSH接続して使用