From: walburn on
Hi
I am starting to practice x86-64 assembly on my AMD64 box. I use the
yasm assembler and link with the gcc. But i see there is a difference
in the way simple functions like printf() work with assembly in 64bit
mode. In 32bit mode, if we have to do "printf("Hello World!\n"); ",
then all we do is push the string "hello world\n" on the stack and call
printf. But in 64bit mode, if i do the same thing, my program
seg-faults inside printf. On the other hand I write the same hello
world code in C, compile it using gcc, disassemble using objdump and
then rewrite the disassembled stuff using yasm and rebuild my
executable and it works.
Now what gcc does is, instead of pushing "hello world\n" on the stack
it moves it into a register like RDI or RSI and calls printf. I
understand that this is a good optimization technique and does not need
the use of the stack. But for more generic and complex printf
statements, how do I know which register to store the variables in, the
string in and in which order so that it will all get printed correctly
the way I want it.

Here is a copy of my asm code in NASM syntax:

section .data
string1 db "hello world!",10,0

section .text
global main
extern printf, read_int

main:
enter 0,0
; mov rdi, dword string1 ; gcc does this when it calls
printf
; mov rax, 0 ; gcc does this
push dword string1 ; This is how i had done it in 32bit mode.
call printf
pop rcx
leave
ret

I use the yasm assembler and create an ELF64 executable, to run in
64bit mode of AMD64. I use gcc to link the executable. I am running on
Slamd64 10.2 which is a 64bit port of Slackware 10.2. The glibc-version
I am using is 2.3.5. My gcc version is 3.4.4

Any ideas or hints ?
Please help.
Regards,
Vikas

From: Evenbit on

walburn(a)gmail.com wrote:
> Hi

Hi Vikas,

> I am starting to practice x86-64 assembly on my AMD64 box.
> I use the
> yasm assembler and link with the gcc. But i see there is a difference
> in the way simple functions like printf() work with assembly in 64bit
> mode. In 32bit mode, if we have to do "printf("Hello World!\n"); ",
> then all we do is push the string "hello world\n" on the stack and call
> printf. But in 64bit mode, if i do the same thing, my program
> seg-faults inside printf. On the other hand I write the same hello
> world code in C, compile it using gcc, disassemble using objdump and
> then rewrite the disassembled stuff using yasm and rebuild my
> executable and it works.
> Now what gcc does is, instead of pushing "hello world\n" on the stack
> it moves it into a register like RDI or RSI and calls printf. I
> understand that this is a good optimization technique and does not need
> the use of the stack. But for more generic and complex printf
> statements, how do I know which register to store the variables in, the
> string in and in which order so that it will all get printed correctly
> the way I want it.

Good question! I just did a 'quick romp' among the docs...

http://gcc.gnu.org/onlinedocs/gcc-4.1.0/cpp/
http://gcc.gnu.org/onlinedocs/gccint/
http://gcc.gnu.org/onlinedocs/porting/

....and, instead of answers, I got this...

http://gcc.gnu.org/onlinedocs/gccint/Library-Files.html#Library-Files

....which hasn't been written yet! :) So, you will have to look in the
logical places of your HD to find these headers -- and write your own
'standard lib' manual! ;)

>
> Here is a copy of my asm code in NASM syntax:
>
> section .data
> string1 db "hello world!",10,0
>
> section .text
> global main
> extern printf, read_int
>
> main:
> enter 0,0
> ; mov rdi, dword string1 ; gcc does this when it calls
> printf
> ; mov rax, 0 ; gcc does this
> push dword string1 ; This is how i had done it in 32bit mode.
> call printf
> pop rcx
> leave
> ret
>
> I use the yasm assembler and create an ELF64 executable, to run in
> 64bit mode of AMD64. I use gcc to link the executable. I am running on
> Slamd64 10.2 which is a 64bit port of Slackware 10.2. The glibc-version
> I am using is 2.3.5. My gcc version is 3.4.4
>
> Any ideas or hints ?
> Please help.
> Regards,
> Vikas

From: Evenbit on

walburn(a)gmail.com wrote:
> Hi

Hi again,

This is just a semantic *nit* ... offered for what its worth:

> In 32bit mode, if we have to do "printf("Hello World!\n"); ",
> then all we do is push the string "hello world\n" on the stack and call
> printf.
....
> Now what gcc does is, instead of pushing "hello world\n" on the stack
> it moves it into a register like RDI or RSI and calls printf.

If we allow 8 bits per character, then I calculate that we can only
store 8 characters into a 64-bit register. So, if it was true that gcc
moves a string into a register, then it would only print "hello wo" and
the "rld\n" would fall off the end. I don't see anything in your code
that would instruct the CPU to store the contents of the string inside
the register -- so it must be doing something else. :)

Nathan.

From: Robert Redelmeier on
walburn(a)gmail.com wrote in part:
> Now what gcc does is, instead of pushing "hello world\n" on the stack
> it moves it into a register like RDI or RSI and calls printf.

I don't know whether this is a terminology problem, but AFAIK
(I am no `c` expert), `c` does _not_ push strings on the stack.
It might put them there as local [automatic?] variables

The `printf` function expects a _pointer_ to a format string on
the stack (above the ret addr), followed by a variable number of
variable items as dictated by the format string. Check your dump.

> I understand that this is a good optimization technique and
> does not need the use of the stack.

X86_64 might use the "fastcall" convention, passing parameters
in registers. Not as helpful as you might think (except kernel)
since the stack should to be in L1 cache where memory vs register
often doesn't make any overall difference due to hw scheduling.

-- Robert

From: Frank Kotler on
walburn(a)gmail.com wrote:
> Hi
> I am starting to practice x86-64 assembly on my AMD64 box.

Courtesy of Darren, over on clax:

The 64bit ABI for AMD64 systems:
<http://www.x86-64.org/documentation/abi-0.96.pdf>

....
> Here is a copy of my asm code in NASM syntax:

Just out of curiousity, can you show us some Yasm syntax (I assume it
looks pretty similar? - unless you use the AT&T option???)

As you can see, they've *completely* fucked up ("improved", I mean!) the
ABI. Porting 32-bit code is a *much* bigger deal than just changing eax
to rax and assembling with an assembler that supports it (almost
anything *but* Nasm :(

Talk about the "death of assembly"? 64-bit is what's going to do it, not
any "anti-assembler activists"!!!

(for Nathan, it is of course the address/offset of the string... and
even "nittier" - the "\n" isn't translated to 10... maybe Gas?... we
have to write "10", as Vikas does in his code)

How are you liking 64-bit, besides the fact that it's confusing to program?

Best,
Frank

This *may* be relevant too...

<http://www.caldera.com/developers/gabi/latest/contents.html>
 |  Next  |  Last
Pages: 1 2 3 4 5 6 7 8 9 10 11
Prev: Input/Output
Next: Programming GPU with ASM