下面是一个简单的示例程序,这个程序显示了如何实现C和ASM的接口。
Contents: readme.txt -- this file endian_demo.c -- the C source file, implements the main function function.S -- the AT&T-format ASM file, implements the ASM functions Makefile -- the makefile for compiling the program Instructions to Compile: ----------------------- Just run "make" in the source file folder. If everything goes well, an executable binary file named "endian_demo" will be created in the same folder. Instructions to Run: ------------------- Just run "./endian_demo" in the folder in which the program is compiled. Argument should be specified in the command line. For example: ./endian_demo 1 255 1334 More than one number should be specified. If no number specified, the program will print a usage message. Source Files: ------------------ endian_demo.c : This is the main C source file of the program. It implements the main() function, which parses the command-line argument, and invokes the ASM functions to swap the endian of the number and print the hexadecimal form of the number. function.S : This is the AT&T format assembly file which implements the two functions: writeHexASCII and swapEnds. To make the assembly code interface the ANSI C code, we need to understand how the gcc C compiler generating code for the arguments of the functions and the return value of the functions. Arguments of a function is passed via the stack of the program. Before invoking the function, arguments is pushed into the stack, and then call the function. In the function itself, it should retrive the arguments from the stack, whose current address is stored in the esp register of the x86 CPU. Return value is passed via the register eax. The function puts the return value in eax, then a "ret" instruction will return to the place where this functions is invoked. void writeHexASCII(char *buffer,unsigned int number); This function takes two arguments, the address of the buffer and the number to be converted to hexadecimal strings. Each digits of the hex value is extracted from the number using the shifting instruction, then converted to hex value, and then moved to the buffer. unsigned int swapEnds(unsigned int x); This functions takes one argument and returns the swapped value. The bytes of the number is extracted and swapped, and then return the value in eax register. Assumptions: ------------ 1. The target linux system is running on Intel X86 32-bit CPU 2. GNU make and gcc are installed on the system. 以下是代码: 这个是主程序文件endian_demo.c
#include <stdio.h>
#include <stdlib.h> extern void writeHexASCII( char *buffer,unsigned int number); extern unsigned int swapEnds(unsigned int x); int main( int arg_c, char **arg_v) { int i; unsigned int num, num_swap; char buf[16]; if(arg_c < 2) { fprintf(stderr, "Usage: %s NUM1 NUM2 NUM3.../n", arg_v[0]); return -1; } i = 1; while(i < arg_c) { num = atoi(arg_v[i]); num_swap = swapEnds(num); fprintf(stdout, "%d: ", num); writeHexASCII(buf, num); fprintf(stdout, "%s <-> ", buf); writeHexASCII(buf, num_swap); fprintf(stdout, "%s = ", buf); fprintf(stdout, "%d/n", num_swap); i++; } return 0; } 这个是实现endian swap和hex转字符串的函数,文件名function.S
/* here we use AT&T format assembly */
.text .code32 .globl writeHexASCII .globl swapEnds /* 0x8(%esp) = number 0x4(%esp) = *buffer %ecx = shift length %eax = hex value %edi = loop count */ writeHexASCII: movl $28,%ecx movl $0,%edi mov 0x4(%esp),%edx jmp if_loop_end loop_start: mov 0x8(%esp),%eax shr %cl,%eax and $0xf,%eax cmpl $9,%eax jg hex_abcdef hex_0_9: addl $0x30,%eax jmp hex_convert_complete hex_abcdef: addl $0x57,%eax hex_convert_complete: mov %al,(%edx) add $1,%edx subl $4,%ecx addl $1,%edi if_loop_end: cmpl $7,%edi jle loop_start movb $0x0,(%edx) ret /* 0x4(%esp) = x %edi = temp value */ swapEnds: mov 4(%esp),%eax and $0xff000000,%eax shr $24,%eax mov %eax,%edi movzbl 4(%esp),%eax shl $24,%eax or %eax,%edi mov 4(%esp),%eax and $0xff0000,%eax shr $8,%eax or %eax,%edi mov 4(%esp),%eax and $0xff00,%eax shl $8,%eax or %eax,%edi mov %edi,%eax ret 下面是一个简单的Makefile,用来编译这个程序:
all: endian_demo
endian_demo: function.o endian_demo.o gcc -o $@ function.o endian_demo.o function.o: function.S gcc -o $@ -c $< endian_demo.o: endian_demo.c gcc -o $@ -c $< -ansi clean: rm -f *.o rm -f endian_demo |