LinuxQuestions.org
Latest LQ Deal: Latest LQ Deals
Go Back   LinuxQuestions.org > Forums > Non-*NIX Forums > Programming
User Name
Password
Programming This forum is for all programming questions.
The question does not have to be directly related to Linux and any language is fair game.

Notices


Reply
  Search this Thread
Old 02-01-2007, 02:09 PM   #1
tomtechguy
LQ Newbie
 
Registered: Jan 2007
Distribution: Arch and Slackware
Posts: 10

Rep: Reputation: 0
x86_64 assembly help


Hi, I haven't done much assembler programming (n00b) and I was wondering if I could get some help. I want to write this program that prints off the arguments that are (would be in C at least) pointed to by the char **argv array. This is what I would like the output to say to the following line.

$ ./a.out a b c
argv[0]=./a.out
argv[1]=a
argv[2]=b
argv[3]=c

The following code works fine when no argument is specified, but segfaults when there is at least one argument. I don't have access to my home computer at the moment, so I thought I'd let smarter people than myself figure this out. I'm new to this so be gentle.


Quote:
.data
FMT:
.string "argc[%d]=%s\n"

.text
.globl _start
.extern puts

_start:
pop %r8 #argc into r8

mov $0x0, %rsi #0 into rsi
Loop1:
cmp %r8, %rsi
jge Loop1Out #if rsi>=r8 jump out
mov $FMT, %rdi #make sure FMT is in rdi
pop %rdx #pop an argv off the stack
push %r8
push %rsi
call printf #printf;
pop %rsi
pop %r8
inc %rsi
jmp Loop1
Loop1Out:

pushq $0x0
pop %rdi
pushq $0x3c # exit(3c)
pop %rax
syscall
 
Old 02-02-2007, 11:46 PM   #2
paulsm4
LQ Guru
 
Registered: Mar 2004
Distribution: SusE 8.2
Posts: 5,863
Blog Entries: 1

Rep: Reputation: Disabled
Hi -

For starters, you didn't even mention kind of assembly language this is (Power PC? it certainly doesn't look like Intel x86...) or what platform it's running on (presumably Linux?). That would drastically affect whether instructions like "pop %r8" or "pop %rdx" are appropriate methods for accessing "argv[]".

But why don't you try this:
a) Write a C "hello world" that accesses argc/argv[]
b) compile with "gcc -S -O0"
c) analyze the resulting assembly source file

Just a thought ..
 
Old 02-03-2007, 01:47 PM   #3
iamnothere
Member
 
Registered: Feb 2007
Location: UK
Distribution: Slamd 64, Slackware
Posts: 46

Rep: Reputation: 16
Quote:
Originally Posted by paulsm4
For starters, you didn't even mention kind of assembly language this is (Power PC? it certainly doesn't look like Intel x86...)
Um, well, presumably x86_64 since the title of the thread is "x86_64 assembly help".

At first glance, the problem appears to be that you didn't decrement r8 (argc) at the start. Remember that argc also includes the name of the program. Without the dec, you are using the terminating NULL as an argument which is presumably what is causing the segfault (when passed to printf). Speaking of terminating NULLs, you could just test for that instead of counting the indices, i.e. cmp rdx to 0[1] and break when it's equal.

[1] See the C usenet FAQ for a discussion of the potential for confusion surrounding null pointers. A null pointer is not necessarily binary zero on some architectures, though for x86, it is safe to assume that it is. In C it doesn't matter, since it's the responsibility of the compiler to translate a NULL (or bare 0) to the correct format for the particular architecture. In assembly of course, you'll probably need to do this yourself.
 
Old 02-03-2007, 02:40 PM   #4
paulsm4
LQ Guru
 
Registered: Mar 2004
Distribution: SusE 8.2
Posts: 5,863
Blog Entries: 1

Rep: Reputation: Disabled
Hi again -

OK - sorry. I was looking at the code in your question, and didn't pay any attention to the "x86_64 assembly" part of the question.

As it turns out, the "gcc -S" suggestion I gave wasn't too great, either. I tried it myself on my AMD/64, SusE Linux 10.x system: my output doesn't look anything *remotely* like your code. So "whoops" on that one, too.

I'm still curious: what kind of CPU (AMD/64? Intel/64? Ithanium?) and assembler (GNU AS? Intel assembler?) do you have? Which version of Linux (or, if not Linux, which OS)?

Sorry I couldn't be of more help .. PSM

Last edited by paulsm4; 02-03-2007 at 02:51 PM.
 
Old 02-04-2007, 10:57 AM   #5
tomtechguy
LQ Newbie
 
Registered: Jan 2007
Distribution: Arch and Slackware
Posts: 10

Original Poster
Rep: Reputation: 0
$ uname -a
Linux helios 2.6.18-gentoo-r6 #6 Mon Jan 15 22:52:44 EST 2007 x86_64 AMD Athlon(tm) 64 Processor 3700+ AuthenticAMD GNU/Linux

using gas as the assembler and ld (through gcc) to link.
$ as -g --64 test.s -o test.o
$ gcc -g test.o -o test -nostartfiles

Yeah the assembly that gcc generates for x86_64 is kinda scary to me, but perhaps I should endeavor to emulate it more closely.

As I understand if I run "./a.out a b c d" then the stack should look like this...

----top
0 (NULL)
pointer to the C string "d"
'' "c"
'' "b"
'' "a"
'' "./a.out"
4
----bottom

Is this correct?

Here's the corresponding C for what I want to do...

Quote:
#include <stdio.h>
int main(int argc, char **argv) {
int i;
for (i=0; i<argc; ++i) {
printf("argv[%d]=%s\n", i, argv[i]);
}
}
I actually may have some time to work on this today. Testing for the NULL at the end seems like a much better idea that what I'm currently doing. Thanks for the help so far.

EDIT:

Almost forgot...
GNU assembler version 2.16.1 (x86_64-pc-linux-gnu) using BFD version 2.16.1
GNU ld version 2.16.1
gcc version 4.1.1 (Gentoo 4.1.1-r1)

Last edited by tomtechguy; 02-04-2007 at 11:00 AM.
 
Old 02-04-2007, 02:00 PM   #6
iamnothere
Member
 
Registered: Feb 2007
Location: UK
Distribution: Slamd 64, Slackware
Posts: 46

Rep: Reputation: 16
Quote:
Originally Posted by paulsm4
OK - sorry. I was looking at the code in your question, and didn't pay any attention to the "x86_64 assembly" part of the question.
Heh, funny old thing the human brain. I can read a piece of text then immediately forget every word, yet I can still remember the diameter of Jupiter from looking it up twenty years ago. ?

Quote:
Originally Posted by paulsm4
As it turns out, the "gcc -S" suggestion I gave wasn't too great, either. I tried it myself on my AMD/64, SusE Linux 10.x system: my output doesn't look anything *remotely* like your code. So "whoops" on that one, too.
An excellent way to learn assembly language. This is how I learnt back when I was using DOS.
Note though, that gcc's default (un-optimized) output is relatively inefficient, try using -O2 and comparing it with the default output to see how gcc improves the basic code.

Quote:
Originally Posted by tomtechguy
As I understand if I run "./a.out a b c d" then the stack should look like this...

----top
0 (NULL)
pointer to the C string "d"
'' "c"
'' "b"
'' "a"
'' "./a.out"
4
----bottom

Is this correct?
Yes, that's correct, the parameters go on the stack in reverse order, last one at the top (well, after the NULL) and so on. Thus argc is at the bottom of the stack. You just need to remember to ignore argv[0] and you should be OK.

Last edited by iamnothere; 02-04-2007 at 02:26 PM.
 
Old 02-05-2007, 02:26 AM   #7
paulsm4
LQ Guru
 
Registered: Mar 2004
Distribution: SusE 8.2
Posts: 5,863
Blog Entries: 1

Rep: Reputation: Disabled
Hi, again -

For whatever it's worth:
1. I'm able to find and print "argc" (it's at -4(%rsp))
2. I believe I can access "argv" (but I can't print it yet)
3. I'm able to call C library "printf" (last time I looked, it took arguments off the stack. My current version of GCC now allocates registers instead)
4. I'm able to make Linux system calls (similarly, the last time I looked, Linux system calls were invoked via "int 0x80". Under Linux/64, they're instead invoked via "syscall", and the call numbers and parameters are completely changed from Linux/32).

Here's my code:
Code:
#
# ASM/Linux "Hello world"
#
# REFERENCES:
# - 32-bit "print cmd-line args" example:
#   http://asm.sourceforge.net/articles/linasm-src.html#args
#   <= Obsolete: GCC "printf()" now called with register args instead of stack;
#                32-bit "int $0x80" replaced with "syscall"
#                Linux/64 API call #'s completely different
#
# - x86-64 ABI:
#   http://www.x86-64.org/documentation/abi.pdf
#
# - Differences between 32-bit and 64-bit assembly:
#   http://www.milw0rm.com/papers/110
#
# - Changes from sourceforge.net example:
#   - Changed comment symbols from "//" to "#"
#   - Changed 32-bit "l" qualifiers and "%exx" opcodes to 64-bit "q"/"%rxx"
#   - Etc etc
#
.equ SYS_exit,60    # SYS_exit formerly "1" under "int $0x80" Linux/32 ABI
.equ SYS_write,1    # SYS_write formerly "4"
.equ STDOUT,1

.section  .data
FMT1:
	.asciz "argc: %d\n"
ENDL:
	.asciz "\n"

.section  .text
.globl main
main:
	# Saver buffer pointer
	pushq   %rbp
	movq	%rsp, %rbp
	movl	%edi, -4(%rbp)

	# Get and print argc
#	printf(FMT1, argc);
	movl	-4(%rbp), %esi
	movq	$FMT1, %rdi
	xor	%eax, %eax
	call printf

	# Make sure argc >= 2
	movl    -4(%rbp), %eax
	cmp	$2, %eax
	jl	exit

	# Try to print 1st letter of argv[1]
        movq 	-16(%rbp), %rax 
	addq	$8, %rax
	movq	(%rax), %rsi
 	mov 	$1, %rax     # OS call = SYS_write
 	mov	$1, %edi     # fd = 1 (stdout)
 	mov	$1, %edx     # len= 1
	                     # %rsi = string pointer
 	syscall

exit:
	mov	$SYS_exit, %rax
	mov	$0, %rdi
	syscall
		
	ret
And here's my makefile:
Quote:
#
# makefile
#
CC=gcc
CFLAGS=-O2 -m64
AS=as
ASFLAGS=-g --64
LD=ld

helloc: hello.c
$(CC) $(CFLAGS) -o helloc hello.c

hello.s: hello.c
$(CC) $(CFLAGS) -S hello.c
mv hello.s hello.gcc.s

hello.asm64: hello.asm64.s
$(AS) $(ASFLAGS) $@.s -o $@.o
$(CC) -m64 -g $@.o -o hello.asm64

x.asm64: x.c
gcc -O0 -m64 -S x.c
as --64 x.s -o x.o
gcc -m64 -g x.o -o x.asm64 -lc

clean:
rm -f *.o helloc hello.asm64 x.asm64
"hello.asm64.s" is the program above. "x.c" is a temp file I've been modifying and compiling with "gcc -m64 -O0 -S" to try to figure out how things work in this Brave New 64-bit world ;-)

I hope that's at least a *little" bit of help to you ... and I'm curious what you come up with when you get it completely working.

Your .. PSM
 
Old 02-05-2007, 02:20 PM   #8
schneidz
LQ Guru
 
Registered: May 2005
Location: boston, usa
Distribution: fedora-30
Posts: 5,290

Rep: Reputation: 916Reputation: 916Reputation: 916Reputation: 916Reputation: 916Reputation: 916Reputation: 916Reputation: 916
one more suggestion leveraging off of the 'gcc -S' idea.

maybe it would help to 'gcc -g' and step thru it in gdb/ dbx ?
 
  


Reply


Thread Tools Search this Thread
Search this Thread:

Advanced Search

Posting Rules
You may not post new threads
You may not post replies
You may not post attachments
You may not edit your posts

BB code is On
Smilies are On
[IMG] code is Off
HTML code is Off



Similar Threads
Thread Thread Starter Forum Replies Last Post
assembly and c tokernizer Programming 8 04-16-2006 11:40 AM
assembly ? blackzone Programming 3 10-15-2004 02:36 AM
I need help for Assembly skb Programming 10 08-01-2003 04:51 PM
assembly genghis Programming 2 06-12-2003 07:46 AM
assembly sanjay pradhan Programming 1 02-01-2002 10:05 AM

LinuxQuestions.org > Forums > Non-*NIX Forums > Programming

All times are GMT -5. The time now is 10:55 PM.

Main Menu
Advertisement
My LQ
Write for LQ
LinuxQuestions.org is looking for people interested in writing Editorials, Articles, Reviews, and more. If you'd like to contribute content, let us know.
Main Menu
Syndicate
RSS1  Latest Threads
RSS1  LQ News
Twitter: @linuxquestions
Open Source Consulting | Domain Registration