0
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

x86LEA命令で乗算をする方法

0
Posted at

初めに

C言語で乗算の処理を書くとlea命令が生成されることがあります。

コンパイル

test.c
int main() {
    int a = 1, b = 2, c = 3, d = 4;
    int x = a + b*3 + c*5 + d;

    return x;
}

bcc(WindowsXP)

bcc32 -S test.c
test.asm
	.386p
	model flat
	ifndef	??version
	?debug	macro
	endm
	endif
	?debug	S "test.c"
	?debug	T "test.c"
_TEXT	segment dword public use32 'CODE'
_TEXT	ends
_DATA	segment dword public use32 'DATA'
_DATA	ends
_BSS	segment dword public use32 'BSS'
_BSS	ends
DGROUP	group	_BSS,_DATA
_TEXT	segment dword public use32 'CODE'
_main	proc	near
?live1@0:
   ;	
   ;	int main(){
   ;	
	push      ebp
	mov       ebp,esp
	push      ebx
   ;	
   ;	    int a=1,b=2,c=3,d=4;
   ;	
@1:
	mov       eax,1
	mov       edx,2
	mov       ecx,3
	mov       ebx,4
   ;	
   ;	    int x=a+b*3+c*5+d;
   ;	
?live1@32: ; EAX = a, EDX = b, ECX = c, EBX = d
	lea       edx,dword ptr [edx+2*edx]
	add       eax,edx
	lea       ecx,dword ptr [ecx+4*ecx]
	add       eax,ecx
	add       ebx,eax
	mov       eax,ebx
   ;	
   ;	    return x;
   ;	
?live1@48: ; EAX = x
   ;	
   ;	}
   ;	
?live1@64: ; 
@3:
@2:
	pop       ebx
	pop       ebp
	ret 
_main	endp
_TEXT	ends
	public	_main
	?debug	D "test.c" 23649 25327
	end

b*3lea edx,dword ptr [edx+2*edx]
c*5lea ecx,dword ptr [ecx+4*ecx]
となっている。

gcc(Ubuntu)

こちらは予想したコードが生成されませんでした。

gcc -m32 -S -O0 -masm=intel \
-fno-asynchronous-unwind-tables \
-fno-unwind-tables \
-fno-stack-protector \
-fno-pic \
-fno-pie \
test.c
test.s
	.file	"test.c"
	.intel_syntax noprefix
	.text
	.globl	main
	.type	main, @function
main:
	push	ebp
	mov	ebp, esp
	sub	esp, 32
	mov	DWORD PTR [ebp-4], 1
	mov	DWORD PTR [ebp-8], 2
	mov	DWORD PTR [ebp-12], 3
	mov	DWORD PTR [ebp-16], 4
	mov	edx, DWORD PTR [ebp-8]
	mov	eax, edx
	add	eax, eax
	add	edx, eax
	mov	eax, DWORD PTR [ebp-4]
	lea	ecx, [edx+eax]
	mov	edx, DWORD PTR [ebp-12]
	mov	eax, edx
	sal	eax, 2
	add	eax, edx
	lea	edx, [ecx+eax]
	mov	eax, DWORD PTR [ebp-16]
	add	eax, edx
	mov	DWORD PTR [ebp-20], eax
	mov	eax, DWORD PTR [ebp-20]
	leave
	ret
	.size	main, .-main
	.ident	"GCC: (Ubuntu 11.4.0-1ubuntu1~22.04.2) 11.4.0"
	.section	.note.GNU-stack,"",@progbits

leaで乗算する仕組み

num1 * num2は

mov reg,num1
lea reg,dword ptr [reg+(num2-1)*reg]

で処理できます。
使用できるnum2の数には制限があります。
使える数と使えない数に関しては筆者もまだ理解できていません。

試しにアセンブリでプログラムを書いて確かめます。

test.asm
BITS 32

section .text
global _start

_start:

    ;3*8
    mov edx, 3
    lea edx, dword [edx+7*edx]
    
    ;2*5
    mov ecx,2
    lea ecx, dword [ecx+4*ecx]
    
    int 3 ; //ここで止め、GDBからEAXの値を確認
    
    ; exit(0)
    mov eax, 1      ; sys_exit
    mov ebx, 0 
    int 0x80
nasm -f elf32 test.asm
ld -m elf_i386 -o test test.o
gdb ./test
run
info registers eax

GDBで止めて乗算が正常に計算されているかを確認します。

0x08049015 in _start ()
(gdb) info registers edx ecx
edx            0x18                24
ecx            0xa                 10

3*8=24,2*5=10よって正しく計算されていることが分かります。

lea本来の使い方

test.asm
; info registers eax ebx
BITS 32

section .text
global _start

main:
    push ebp
    mov ebp,esp
    sub esp,4

    ; int val=5;
    mov eax,5
    mov dword [ebp-4],eax
    
    ; eax=&val
    lea eax, dword [ebp-4]
    
    ; ebx=val
    mov ebx, dword [ebp-4]
    int 3 ; ここで止めてレジスタを確認
        
    mov esp,ebp
    pop ebp
    ret

_start:

    call main
    
    ; exit(0)
    mov eax, 1      ; sys_exit
    mov ebx, 0 
    int 0x80

leaで取得されるのはアドレス、movで取得されるのはそのアドレスに保存された値となります

0x08049015 in main ()
(gdb) info registers eax ebx
eax            0xffffd294          -11628
ebx            0x5                 5
0
0
4

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
0
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?