|
Prev: Input/Output
Next: Programming GPU with ASM
From: walburn on 12 Mar 2006 01:29 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 12 Mar 2006 06:19 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 12 Mar 2006 07:41 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 12 Mar 2006 10:00 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 12 Mar 2006 10:06
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> |