patternMinor
Finding the maximum of a given list of data in GNU Assembly x86 (32 bit)
Viewed 0 times
themaximumbitx86assemblyfindinglistdatagivengnu
Problem
I am following the book Programming from the Ground Up and as an answer to a question in the Use the Concepts section of chapter 4:
Value in Chapter 3 so that it is a function which takes a pointer to several values
and returns their maximum. Write a program that calls maximum with 3
different lists, and returns the result of the last one as the program’s exit status
code.
I wrote the following code:
maxfunc.s
```
# NAME: maxfunc.s
# PURPOSE: A modular approach of finding the maximum of lists
.section .data
# The data section has three lists for testing, change the code
# highlighted in the text section to change the list passed.
data_1:
.long 1, 2, 3, 4, 5, 6, 7, 8, 9, 0
data_2:
.long 23, 45, 62, 13, 87, 54, 0
data_3:
.long 1, 2, 3, 3, 3, 7, 6, 5, 8, 1, 1, 0
# VARIABLES:
# 1. %edi - Will be our index variable, to access the items
# 2. %ebx - The element we're looking at currently
# 3. %eax - The maximum value we've found so far
# 4. %ecx - To store the address of the list
.section .text
.globl _start
_start:
# Push the address of the list we want to find the maximum of
pushl $data_3
# ^
# +---> Change this to select your list
call maximum
addl $4, %esp # Reset the stack
movl %eax, %ebx
movl $1, %eax
int $0x80
.type maximum, @function
maximum:
# Setup
pushl %ebp
movl %esp, %ebp
# The initial setup:
# Get the address of the list
# Set the index to 0
# Get the first item from the list
# The first item is currently the largest
movl $0, %edi
movl 8(%ebp), %ecx
movl (%ecx, %edi, 4), %ebx
movl %ebx, %eax
max_loop:
cmpl $0, %ebx
je exit_loop
incl %edi
movl (%ecx, %edi, 4), %ebx
cmpl %eax, %ebx
jle max_loop
# %ebx is greater than %eax
- Convert the maximum program given in the Section called Finding a Maximum
Value in Chapter 3 so that it is a function which takes a pointer to several values
and returns their maximum. Write a program that calls maximum with 3
different lists, and returns the result of the last one as the program’s exit status
code.
I wrote the following code:
maxfunc.s
```
# NAME: maxfunc.s
# PURPOSE: A modular approach of finding the maximum of lists
.section .data
# The data section has three lists for testing, change the code
# highlighted in the text section to change the list passed.
data_1:
.long 1, 2, 3, 4, 5, 6, 7, 8, 9, 0
data_2:
.long 23, 45, 62, 13, 87, 54, 0
data_3:
.long 1, 2, 3, 3, 3, 7, 6, 5, 8, 1, 1, 0
# VARIABLES:
# 1. %edi - Will be our index variable, to access the items
# 2. %ebx - The element we're looking at currently
# 3. %eax - The maximum value we've found so far
# 4. %ecx - To store the address of the list
.section .text
.globl _start
_start:
# Push the address of the list we want to find the maximum of
pushl $data_3
# ^
# +---> Change this to select your list
call maximum
addl $4, %esp # Reset the stack
movl %eax, %ebx
movl $1, %eax
int $0x80
.type maximum, @function
maximum:
# Setup
pushl %ebp
movl %esp, %ebp
# The initial setup:
# Get the address of the list
# Set the index to 0
# Get the first item from the list
# The first item is currently the largest
movl $0, %edi
movl 8(%ebp), %ecx
movl (%ecx, %edi, 4), %ebx
movl %ebx, %eax
max_loop:
cmpl $0, %ebx
je exit_loop
incl %edi
movl (%ecx, %edi, 4), %ebx
cmpl %eax, %ebx
jle max_loop
# %ebx is greater than %eax
Solution
In general I try to stick to the naming conventions of the registers themselves. Although, I have been criticized for it because many programmers think of these conventions as archaic. But I think it helps reading the code.
General-Purpose Registers (GPR) - 16-bit naming conventions[edit] The 8 GPRs are:
Cited from: https://en.wikibooks.org/wiki/X86_Assembly/X86_Architecture
Instead of passing the args on the stack, I opted to pass the address in the base register. AMD64 defines way different calling conventions than the original 32bit stuff. If this were a non trivial program we'd definitely want to adhere to the sysv calling conventions which define which registers may be overwritten or must be preserved between calls, stack alignment, etc. In the
The next book to get if you want to learn a great deal more about assembly AFTER programming from the ground up is Professional Assembly Language.
Linus Torvalds has criticized
http://yarchive.net/comp/linux/cmov.html
General-Purpose Registers (GPR) - 16-bit naming conventions[edit] The 8 GPRs are:
- Accumulator register (AX). Used in arithmetic operations.
- Counter register (CX). Used in shift/rotate instructions and loops.
- Data register (DX). Used in arithmetic operations and I/O operations.
- Base register (BX). Used as a pointer to data (located in segment register DS, when in segmented mode).
- Stack Pointer register (SP). Pointer to the top of the stack.
- Stack Base Pointer register (BP). Used to point to the base of the stack.
- Source Index register (SI). Used as a pointer to a source in stream operations.
- Destination Index register (DI). Used as a pointer to a destination in stream operations.
Cited from: https://en.wikibooks.org/wiki/X86_Assembly/X86_Architecture
.section .data
data_1:
.long 1, 3, 4, 5, 6, 7, 8, 9, 0
data_2:
.long 23, 45, 62, 13, 87, 54, 0
data_3:
.long 1, 3, 7, 6, 5, 8, 1, 1, 0
.section .text
.globl _start
.type maximum, @function
.type exit, @function
_start:
movl $data_3, %ebx
call maximum
exit:
movl %eax, %ebx
movl $1, %eax
int $0x80
maximum:
movl (%ebx), %edx # notice i did not index address here.
movl %edx, %eax
movl $1, %esi
max_loop:
cmpl $0, %edx
je exit_loop
movl (%ebx, %esi, 4), %edx
cmpl %edx, %eax
cmovng %edx, %eax
incl %esi
jmp max_loop
exit_loop:
retInstead of passing the args on the stack, I opted to pass the address in the base register. AMD64 defines way different calling conventions than the original 32bit stuff. If this were a non trivial program we'd definitely want to adhere to the sysv calling conventions which define which registers may be overwritten or must be preserved between calls, stack alignment, etc. In the
maximum function we could use a cmov__ instruction if we wanted to conditionally move the data register to the accumulator (current max) if it was greater. The next book to get if you want to learn a great deal more about assembly AFTER programming from the ground up is Professional Assembly Language.
Linus Torvalds has criticized
cmov instructions because of the out of order execution nature of modern processors. Which the Professional Assembly Language book explains in detail.http://yarchive.net/comp/linux/cmov.html
Code Snippets
.section .data
data_1:
.long 1, 3, 4, 5, 6, 7, 8, 9, 0
data_2:
.long 23, 45, 62, 13, 87, 54, 0
data_3:
.long 1, 3, 7, 6, 5, 8, 1, 1, 0
.section .text
.globl _start
.type maximum, @function
.type exit, @function
_start:
movl $data_3, %ebx
call maximum
exit:
movl %eax, %ebx
movl $1, %eax
int $0x80
maximum:
movl (%ebx), %edx # notice i did not index address here.
movl %edx, %eax
movl $1, %esi
max_loop:
cmpl $0, %edx
je exit_loop
movl (%ebx, %esi, 4), %edx
cmpl %edx, %eax
cmovng %edx, %eax
incl %esi
jmp max_loop
exit_loop:
retContext
StackExchange Code Review Q#156886, answer score: 5
Revisions (0)
No revisions yet.