How to write a swap function in assembly? - linux

I've been trying to figure out how to write a x86 GAS swap function for my program. I know its easier to do xchg or just write it C, but I want to be able to write it out anyways.
On my 1st midterm we were given this as as swap function:
movl 8(%ebp), %edx
movl 12(%ebp), %ecx
movl (%edx), %ebx
movl (%ecx), %eax
movl %eax, (%edx)
movl %ebx, (%ecx)
but I receive a segmentation fault when running this. Haven't been able to succeed in finding my answer anywhere else on the web, so much help would be appreciated.
EDIT:
C CODE:
void program2()
{
int numA[2] = {5,10};
int *num1 = &numA[0];
int *num2 = &numA[1];
int loop=0;
printf("stop3\n");
for(loop=0;loop<=10;loop++)
{
*num1 *=2;
*num2 *=3;
printf("%d\n%d\n",*num1,*num2);
_asSwap(*num1,*num2);
printf("stop5\n");
printf("P2num1= %d\n P2num2= %d\n",*num1,*num2);
}
Assembly:
_asSwap:
push %ebp
movl %esp, %ebp
movl 8(%ebp), %edx
movl 12(%ebp), %ecx
movl (%edx), %ebx
movl (%ecx), %eax
movl %eax, (%edx)
movl %ebx, (%ecx)
pop %ebp
ret

You passed the values, not the pointers. If you'd included the prototype in your C, the compiler would have caught that (instead of warning about an un-declared function, and assuming it took int parameters).
extern int _asSwap(int *a, int *b);
A debugger would also have caught this, if you checked the address that segfaulted.
Also, it's not normal to prefix your C function names with _. OS X prefixes _ onto C symbol names, and so did Linux a.out (now replaced by ELF). So you in some cases need a leading _ in the asm, but don't use it in C.

Related

X86: making system calls without referring the standard library

I wrote the code that reads from stdin and writes to the stdout:
#include <stdio.h>
#include <unistd.h>
int main() /* copy input to output */
{
char buf[BUFSIZ];
int n;
while ((n = read(0, buf, BUFSIZ)) > 0)
write(1, buf, n);
return 0;
}
After I converted into the assembly code (a .s file) in 32-bit AT&T syntax:
.text
.globl _start
_start:
pushl %ebp
movl %esp, %ebp
andl $-16, %esp #16 bit alignment
subl $8224, %esp #space for local variables
jmp _READ
_WRITE:
movl 8220(%esp), %eax
movl %eax, 8(%esp)
leal 28(%esp), %eax
movl %eax, 4(%esp)
movl $1, (%esp)
call write
int $0x80
_READ:
movl $8192, 8(%esp) #buffer length
leal 28(%esp), %eax
movl %eax, 4(%esp)
movl $0, (%esp)
call read
movl %eax, 8220(%esp)
cmpl $0, 8220(%esp)
jg _WRITE
movl $0, %eax
leave
ret
It works fine, but I'm not sure how to making the "read" and "write" system calls using plain assembly(i.e. moving numbers into certain registers and use "int 0x80" to execute the system calls).
My goal is to make it work even if it is compiled with the "-nostdlib" option.
Hint: 32-bit x86 is old, slow, weird and deprecated. You should use amd64 instead.
The list of system calls for Linux i386 is available in Linux source code:
https://github.com/torvalds/linux/blob/master/arch/x86/entry/syscalls/syscall_32.tbl
Or in glibc headers in asm/unistd_32.h. You can and should #include <asm/unistd.h> so you can use $__NR_write instead of $4 to make your asm source code self-documenting.
The system call number goes in eax. Parameter sequence is always ebx, ecx, edx, esi, edi, ebp. So code becomes:
.text
.globl _start
_start:
pushl %ebp
movl %esp, %ebp
andl $-16, %esp #16 bit alignment
subl $8224, %esp #space for local variables
jmp _READ
_WRITE:
movl 8220(%esp), %edx
leal 28(%esp), %ecx
movl $1, %ebx
movl $4, %eax
int $0x80
_READ:
movl $8192, %edx #buffer length
leal 28(%esp), %ecx
movl $0, %ebx
movl $3, %eax
int $0x80
movl %eax, 8220(%esp)
cmpl $0, 8220(%esp)
jg _WRITE
movl $1, %eax
movl $0, %ebx
int $0x80
Assemble and link with:
$ as --32 hel.s -o hel.o
$ ld -melf_i386 hel.o -o hel
http://www.linuxjournal.com/article/4048
See also
What are the calling conventions for UNIX & Linux system calls on i386 and x86-64
https://blog.packagecloud.io/eng/2016/04/05/the-definitive-guide-to-linux-system-calls/

Getting ASCII number value

Hi Guys I got some annoying problem ,so I try to write a code just to reverse small string sequential
I Already got this :
.section .data
string:
.ascii "AAAAAABBBBBB"
length:
.quad . -string #Dot = 'here'
.section .text
.globl _start #Make entry point visible to linker
_start:
movl $4, %eax #4=write
movl $1, %ebx #1=stdout
movl $string, %ecx
movl length, %edx
int $0x80 #Call Operating System
movl length,%edi #counter
shrl $1,%edi #half of string
movl $0,%ecx #start from index one
movl length,%edx #start from end
reverse:
movl string(,%ecx,1),%eax
movl string(,%edx,1),%ebx
movl %eax,string(,%edx,1)
movl %ebx,string(,%ecx,1)
inc %ecx
dec %edx
dec %edi
loop reverse #looping
movl $4, %eax #4=write
movl $1, %ebx #1=stdout
movl $string, %ecx
movl length, %edx
int $0x80 #Call Operating System
movl $0, %ebx #Make program return syscall exit status
movl $1, %eax #1=exit
int $0x80 #Call System Again
And it's not working correctly , cuz in gbd i get wrong values in registers after making
movl string(,%ecx,1),%eax
or the next steps I think there should be in %eax value for A letter but its doesn't any ideas ?
Working at 64arch but emulating in as --32 so its problem with my addressing i guess
You should be processing bytes not longs, so use movb with 8 bit registers (al and bl, for example). Also, the LOOP instruction uses ECX automatically, you probably meant JNZ there to repeat until EDI reaches zero.

Linux x86 assembly printing problems

I wrote this to print argv[0] in x86:
.section .data
newline: .int 0xa, 0
.section .text
.globl _start
_start:
sub %al, %al
movl 4(%esp), %edi /* Pointer to argv[0]. */
sub %ecx, %ecx /* Set %ecx to 0.*/
not %ecx /* Set %ecx to -1.*/
repne scasb /* Search for %al over and over.*/
not %ecx /* Set %ecx to |%ecx| - 1.*/
dec %ecx
movl %ecx, %edx /* Move the strlen of argv[0] into %edx.*/
movl $4, %eax
movl $1, %ebx
movl 4(%esp), %ecx
int $0x80
movl $newline, %ecx
movl $1, %edx
int $0x80
movl $1, %eax
movl $0, %ebx
int $0x80
When I run this file ("print"), the output is this:
[08:27 assembly]$ ./print test
./print[08:30 assembly]$
When I ran this through gdb, the actual string length held in edx is 27, and the string it's checking is "/home/robert/assembly/print", not "./print". So I changed the %esp offsets to 8, to check argv[1]. With the same command as before, the output is this:
test
[08:33 assembly]$
Why does checking argv[0] cause the strange output, when argv[1] does as expected?
I think gdb is "helping" you by adding the full path to argv[0]. After printing, %eax holds the number of characters printed, so you'll want to reload %eax for sys_write again to print the $newline (%ebx should still be okay) - by luck, "test" is the right length. Lord knows what system call you're getting with that longer string!
I'd say you're doing good! (might be a good idea to check argc to make sure argv[1] is there before you try to print it).

Segmentation Fault in Assembly Language

I am learning AT&T x86 assembly language. I am trying to write an assembly program which takes an integer n, and then return the result (n/2+n/3+n/4). Here is what I have done:
.text
.global _start
_start:
pushl $24
call profit
movl %eax, %ebx
movl $1, %eax
int $0x80
profit:
popl %ebx
popl %eax
mov $0, %esi
movl $4, %ebp
div %ebp
addl %eax, %esi
movl %ecx, %eax
movl $3, %ebp
div %ebp
addl %eax, %esi
movl %ecx, %eax
movl $2, %ebp
div %ebp
addl %eax, %esi
movl %esi, %eax
cmpl %ecx, %esi
jg end
pushl %ebx
ret
end:
mov %ecx, %eax
ret
The problem is I am getting segmentation fault. Where is the problem?
I think the code fails here:
_start:
pushl $24
call profit
movl %eax, %ebx
movl $1, %eax
int $0x80
profit:
popl %ebx
popl %eax
So, you push $24 (4 bytes) and then call profit, which pushes eip and jumps to profit. Then you pop the value of eip into ebx and the value $24 into eax.
Then, in the end, if jg end branches to end:, then the stack won't hold a valid return address and ret will fail. You probably need pushl %ebx there too.
cmpl %ecx, %esi
jg end
pushl %ebx
ret
end:
mov %ecx, %eax
; `pushl %ebx` is needed here!
ret
You do not appear to be doing function calls correctly. You need to read and understand the x86 ABI (32-bit, 64-bit) particularly the "calling convention" sections.
Also, this is not your immediate problem, but: Don't write _start, write main as if this were a C program. When you start doing something more complicated, you will want the C library to be available, and that means you have to let it initialize itself. Relatedly, do not make your own system calls; call the wrappers in the C library. That insulates you from low-level changes in the kernel interface, ensures that errno is available, and so on.
you use ecx without ever explicitly initializing it (I'm not sure if Linux will guarantee the state of ecx when the process starts - looks like it's 0 in practice if not by rule)
when the program takes the jg end jump near the end of the procedure, the return address is no longer on the stack, so ret will transfer control to some garbage address.
Your problem is that you pop the return address off of the stack and when you branch to end you don't restore it. A quick fix is to add push %ebx there as well.
What you should do is modify your procedure so it uses the calling convention correctly. In Linux, the caller function is expected to clean the arguments from the stack, so your procedure should leave them where they are.
Instead of doing this to get the argument and then restoring the return address later
popl %ebx
popl %eax
You should do this and leave the return address and arguments where they are
movl 4(%esp), %eax
and get rid of the code that pushes the return address back onto the stack. You then should add
subl $4, %esp
after the call to the procedure to remove the argument from the stack. It's important to follow this convention correctly if you want to be able to call your assembly procedures from other languages.
It looks to me like you have a single pushl before you call profit and then the first thing that profit does is to do two popl instructions. I would expect that this would pop the value you pushed onto the stack as well as the return code so that your ret would not work.
push and pop should be the same number of times.
call pushes the return address onto the stack.

Printing Range Of ASCII Characters From Registers in x86 Assembly

I'm trying to print a range of ascii characters with this assembly program.
I'm trying to do it using only the registers, but haven't been having much luck. Everything looks fine to me, but I'm a novice at assembly programming and might have missed something obvious. Any insight will be appreciated. Thanks :)
emphasized text
.text
.global _start
_start:
movl $1, %edx
movl $65, %ebx
start_loop:
addl $1, %ebx
movl $0x04, %eax
int $0x80
cmpl $126, %ebx
jle start_loop
jmp start_loop
exit
movl $0, %ebx
movl $1, %eax
int $0x80
You are invoking the sys_write system call. sys_write() takes three arguments, file descriptor of the output device(it should be 1 for stdout),address of the buffer where you stored the value to be printed, and the size of the data to be printed. So you have to store file descriptor in %ebx, and store address of the buffer in %ecx and size of the data in %edx. To store the file descriptor you can use the following instruction.
movl $1, %ebx // store 1 (stdout) in ebx)
To store the size of the data you can use:
movl $1, %edx // size is 1 byte
Now, you have to store the address of the buffer, you need to put your data in the memory some where and need to store the address of the memory in %ecx. Assume that you want store the data in the stack it self, then you can do like this:
subl $4, %esp // get 4 bytes of memory in the stack
movl $65, (%esp) // store data in the memory where esp points to
movl %esp, %ecx // store address of the data in the ecx
Now you can issue the int 0x80.
movl $04, %eax // store syscall number in eax
int $0x80 // issue the trap interrupt
As a whole you can write the following code:
movl $1, %ebx
subl $0x4, %esp
movl $64, (%esp)
start_loop:
movl (%esp), %eax
addl $1, %eax
movl %eax, (%esp)
movl %esp, %ecx
movl $1, %edx
movl $0x04, %eax
int $0x80
movl (%esp), %eax
cmpl $126, %eax
jle start_loop
addl $0x4, %esp
See Linux System Calls Part2 at http://www.rulingminds.com/syscallspart2 to know more about registers and system calls usage.
"Thank you very much for the informative answer, but is there a way to store and retrieve the value to be printed in a register without pointing to it?" -- this should probably have been edited into the question.
If you insist on using only syscalls (int $0x80) to interface with the system then the answer is no. You have to somehow pass a buffer to write and rullingminds answer applies.
Using the libc putchar(3) it's straight forward. I use %ebx to keep the ascii code as this register is on linux preserved between function calls. Simply assemble using gcc filename.S (remembering to use -m32 if you are on x86_64).
.text
.extern putchar
.global main
main:
# make room for argument to putchar on the stack
sub $4, %esp
# initialize ebx with first value to print
mov $'A', %ebx
1:
# give character to print as argument
mov %ebx, (%esp)
call putchar
# move to next character
inc %ebx
# are we done?
cmp $'~', %ebx
jle 1b
# print newline
movl $10, (%esp)
call putchar
# adjust stack back to normal
add $4, %esp
# return 0 from main
mov $0, %eax
ret

Resources