GNU Assembler (gas) on x86_64
D. Hugh Redelmeier
hugh-pmF8o41NoarQT0dZR+AlfA at public.gmane.org
Wed Dec 20 05:46:29 UTC 2006
| From: Marc Lijour <marc-bbkyySd1vPWsTnJN9+BGXg at public.gmane.org>
| I try to follow Richard Blum "Assembly Language" book (Wrox) which focuses on
| Linux and GNU gas -which is a very good thing.
|
| However, my platform is x86_64, not i686. I could tweak the code a little bit
| to avoid segfault by using information gathered at
Why code for x86_64 if you don't have the manual? At least some
x86_64 linux distros (eg. Fedora) let you compile and run i386 code.
| http://www.x86-64.org/documentation/assembly . Now the code looks like this:
|
| # Using printf from libc
| .section .data
| output:
| .asciz "The processor Vendor ID is '%s'\n"
|
| .section .bss
| .lcomm buffer, 12
| .section .text
| .globl _start
| _start:
| nop
| movq $0, %rax
| cpuid
| movq $buffer, %rdi
| movq %rbx, (%rdi)
| movq %rdx, 4 (%rdi)
| movq %rcx, 8 (%rdi)
| pushq $buffer
| pushq $output
| call printf
| addq $8, %rsp
| pushq $0
| call exit
|
| The unmodified example from the book gives this result on Intel i686:
| $ ./cpuid2_i686
| The processor Vendor ID is 'GenuineIntel'
|
| But the code above gives me this on my AMD64:
| $ ./cpuid2_x86_64
| AuthenticAMD
|
| (followed by no newline)
|
| Question: why is the string (label output) not used by printf??
I expect that you need to pay attention to the ABI (Application Binary
Interface). This spells out coding conventions for subroutine calls,
among other things.
Google got me to http://www.x86-64.org/documentation/abi.pdf
Section 3.2 talks about the function calling sequence.
Section 3.2.3 talks about parameter passing.
The first pointer arg should be passed in %rdi. The second should be
passed in %rsi.
Don't forget to terminate C strings with '\0'.
You can also find a manuals for the x86_64. I used this one:
http://www.amd.com/us-en/assets/content_type/white_papers_and_tech_docs/24594.pdf
I discovered (on page 365) that CPUID operates on 32-bit operands even
when the CPU is in 64-bit mode. Page 102 explains CPUID without
making this explicit.
Here's my guess at what your code should look like (UNTESTED).
Warning: I've never written a line of x86_64 code in my life. The
last Intel processor that I did much assembly for was the i8080.
.section .data
output:
.asciz "The processor Vendor ID is '%s'\n"
.section .bss
# polite to align the buffer since it is accessed as 4-byte units.
.align 4
# note: length needs to be 13 (room for '\0')
.lcomm buffer, 13
.section .text
.globl _start
_start:
# CPUID argument is only 32 bits.
movl $0, %eax
cpuid
movq $buffer, %rsi
# CPUID results are only 32-bit units
movl %ebx, (%rsi)
movl %edx, 4 (%rsi)
movl %ecx, 8 (%rsi)
# terminate the string
movb $0, 12(%rsi)
# printf second arg in %rdi
movq $output, %rdi
call printf
# exit(0)
movq $0, %rdi
call exit
Useful trick: write something in C and see what gcc comes up with (-S
flag causes it to compile to assembly code).
Problem: it seems to write bad assembler that gas apparently corrects.
I see movl used for 64-bit moves, for example. A mystery that I won't
try to unravel.
Here's my sample C code:
#include <stdio.h>
int
main()
{
printf("format %s\n", "arg");
return 0;
}
--
The Toronto Linux Users Group. Meetings: http://gtalug.org/
TLUG requests: Linux topics, No HTML, wrap text below 80 columns
How to UNSUBSCRIBE: http://gtalug.org/wiki/Mailing_lists
More information about the Legacy
mailing list