2008 December 8th Monday

本文介绍如何将C语言程序与汇编语言程序进行链接,包括编译过程、使用动态链接库(DLL)导入导出变量及函数的方法,并展示了如何在DLL中使用类。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

   How to link a program wrote in C language and a program in asm language?

## addfun.s
.section .data
str:
.ascii "hi/n/0"
.globl addfun
.type addfun, @function
.section .text
addfun:
pushl %ebp
movl %esp, %ebp

movl 12(%ebp), %eax
movl 8(%ebp), %ebx
addl %ebx, %eax

movl %ebp, %esp
popl %ebp
ret

# subfun.s
.section .data
str:
.ascii "hi/n/0"
.globl subfun
.type subfun, @function
.section .text
subfun:
pushl %ebp
movl %esp, %ebp

movl 12(%ebp), %eax
movl 8(%ebp), %ebx
subl %ebx, %eax

movl %ebp, %esp
popl %ebp
ret

  First, the above two asm sources must be compiled to object files.

as addfun.s -o addfun.o
as subfun.c -o subfun.o

//callasm.c
#include <stdio.h>

// declare two extern functions.
extern int addfun(int, int);
extern int subfun(int, int);

int main(int argc, char *argv[]){
  int r=0;

  r = addfun(3, 5);
  fprintf(stderr, "added result = %d/n", r);

  r = subfun(3, 5);
  fprintf(stderr, "subtracted result = %d/n", r);

  return 0;
}

  Secondly, let's compile and link them.

gcc -o callasm callasm.c addfun.o subfun.o -lc

  OK, a binary file is producted.  We can run it, now.

ADDRESS_OR_OFFSET(%BASE_OR_OFFSET,%INDEX,MULTIPLIER)

  All of the fields are optional. To calculate the address, simply perform the following calculation:

FINALADDRESS=ADDRESS_OR_OFFSET+%BASE_OR_OFFSET+MULTIPLIER*%INDEX

Parameter#N<---N*4+4(%ebp)
...
Parameter2<---12(%ebp)
Parameter1<---8(%ebp)
ReturnAddress<---4(%ebp)
Old%ebp<---(%ebp)
LocalVariable1<----4(%ebp)
LocalVariable2<----8(%ebp)and(%esp)

as write-record.s -o write-record.o
as read-record.s -o read-record.o

ld -shared write-record.o read-record.o -o librecord.so

as write-records.s -o write-records
ld -L . -dynamic-linker /lib/ld-linux.so.2 -o write-records -lrecord write-records.o

Memory Layout of a Linux Program at Startup

Environment Variables
...
Arg #2
Arg #1
Program name
# of arguments          %esp

Unmapped Memory
                        Break
Program Code and Data

  How to make a .so lib for a linux program?

  There is an example.

//datatime.h
#ifndef __DATETIME_H

#define __DATETIME_H

/*  */
typedef strUCt
{
int year;
int mon;
int day;
}DATETYPE;
 
/*  */
typedef struct
{
char hour;
char min;
char sec;
}TIMETYPE;
 
int getdate(DATETYPE *d); /*  */
int gettime(TIMETYPE *t); /*  */

#endif

#ifdef SHARED
int (*getdate)(DATETYPE *d);
#else
int getdate(DATETYPE *d);
#endif
 
#ifdef SHARED
int (*gettime)(TIMETYPE *t);
#else
int gettime(TIMETYPE *t);
#endif
 
#endif

//getdate.c
#include "time.h"
#include "datetime.h"

int getdate(DATETYPE *d)
{
long ti;
struct tm *tm;
 
time(&ti);
tm=localtime(&ti);
d->year=tm->tm_year+1900;
d->mon=tm->tm_mon+1;
d->day=tm->tm_mday;
}

//gettime.c
#include "time.h"
#include "datetime.h"

int gettime(TIMETYPE *t)
{
long ti;
struct tm *tm;

time(&ti);
tm=localtime(&ti);
t->hour=tm->tm_hour;
t->min=tm->tm_min;
t->sec=tm->tm_sec;
}

//make file.
all : libmy.so

SRC = getdate.c gettime.c

TGT = $(SRC:.c=.o)

$(SRC) : adatetime.h
@touch $@
 
%.o : %.c
cc -c $?
 
libmy.so : $(TGT)
gcc -s -shared -o $@ $(TGT)

  After, get my.so, we can write a program use it.

//dy.c
#include "stdio.h" /*  */

#include "dlfcn.h" /*  */
#define SOFILE "./my.so" /*  */

#define SHARED /*  */
#include "datetime.h" /*  */

int main()
{
DATETYPE d;
TIMETYPE t;
void *dp;
char *error;


dp=dlopen(SOFILE,RTLD_LAZY); /*  */
 
if (dp==NULL) /*  */
{
fputs(dlerror(),stderr);
exit(1);
}
 
getdate=dlsym(dp,"getdate"); /*  */
 
error=dlerror(); /*  */
if (error) /*  */
{
fputs(error,stderr);
exit(1);
}
 
getdate(&d); /*  */
printf(": %04d-%02d-%02d/n",d.year,d.mon,d.day);
 
gettime=dlsym(dp,"gettime"); /*  */
 
error=dlerror(); /*  */
if (error) /*  */
{
fputs(error,stderr);
exit(1);
}
 
gettime(&t); /*  */
printf(": %02d:%02d:%02d/n",t.hour,t.min,t.sec);
 
dlclose(dp); /*  */
 
exit(0); /*  */
 


// yet another make file.
all : dy
 
DYSRC = dy.c
 
DYTGT = $(DYSRC:.c=.o)
 
%.o : %.c
    cc -c $?
 
dy : $(DYTGT)
    cc -rdynamic -s -o $@ $(DYTGT) -ldl

  Now, we can run it.  Note: -rdynamic tell compiler to product a program with *.so; -s will remove symbol table
from object file; -ldl to load ld program in order to load those dl* functions.

How to import variables and functions using DLL?

//lib.h
#ifndef LIB_H

#define LIB_H

extern "C" int __declspec(dllexport) add(int x, int y);
extern int __declspec(dllexport) dllGlobalVar;
#endif

//lib.cpp
#include "lib.h"
#include <windows.h>
#include <stdio.h>

int dllGlobalVar;

BOOL APIENTRY DllMain( HANDLE hModule, DWORD ul_reason_for_call, LPVOID lpReserved)
{

switch (ul_reason_for_call)
{
case DLL_PROCESS_ATTACH:
printf("/nprocess attach of dll/n");
dllGlobalVar = 100;
break;
case DLL_THREAD_ATTACH:
printf("/nthread attach of dll/n");
break;
case DLL_THREAD_DETACH:
printf("/nthread detach of dll/n");
break;
case DLL_PROCESS_DETACH:
printf("/nprocess detach of dll/n");
break;

}
return TRUE;
}

int add(int x, int y){
return x + y;
}

  Make it a DLL.  If you need static load a DLL, you had better add a .def file and make a .lib file.

LIBRARY lib

EXPORTS

add @ 1

dllGlobalVar DATA

Static load

//stCall.cpp
#include <stdio.h>

#pragma comment(lib, "lib.lib")

//extern int dllGlobalVar;
extern int _declspec(dllimport) dllGlobalVar;
extern "C" __declspec(dllimport) add(int x, int y);

int main(){
printf("%d ", dllGlobalVar);

dllGlobalVar = 1;

printf("dll variable: %d/n", dllGlobalVar);
printf("dll function: %d/n", add(2,3));
return 0;

}

Dynamic load

//dtDll.cpp

#include <stdio.h>
#include <windows.h>

typedef int(*lpAddFun)(int, int);

int main(int argc, char *argv[])
{

HINSTANCE hDll;
lpAddFun addFun;

hDll = LoadLibrary(".//lib.dll");
if (hDll != NULL) {
addFun = (lpAddFun)GetProcAddress(hDll, "add");
if (addFun != NULL) {
int result = addFun(2, 3);
printf("%d", result);
}
}
FreeLibrary(hDll);
}

How to use classes in DLL?

//point.h
#ifndef POINT_H
#define POINT_H

#ifdef DLL_FILE
class _declspec(dllexport) point
#else
class _declspec(dllimport) point
#endif
{
public:
float y;
float x;
point();
point(float x_coordinate, float y_coordinate);
};
#endif

//circle.h
#ifndef CIRCLE_H
#define CIRCLE_H

#include "point.h"

#ifdef DLL_FILE
class _declspec(dllexport)circle
#else
class _declspec(dllimport)circle //?$BF~(B?circle
#endif
{
public:
void SetCentre(const point centrePointt);
void SetRadius(float r);
float GetGirth();
float GetArea();
circle();

private:
float radius;
point centre;
};

#endif

//clsDll
#include "circle.h"
#include <stdio.h>

#pragma comment(lib, "clsDll.lib")

int main(int argc, char *argv[])
{
circle c;
point p(2.0, 2.0);

c.SetCentre(p);
c.SetRadius(1.0);

printf("area:%f girth:%f", c.GetArea(), c.GetGirth());
return 0;
}

  Make it a DLL, too.

//clsCall.cpp

#include "circle.h"
#include <stdio.h>

#pragma comment(lib, "clsDll.lib")

int main(int argc, char *argv[])
{
circle c;
point p(2.0, 2.0);

c.SetCentre(p);
c.SetRadius(1.0);

printf("area:%f girth:%f", c.GetArea(), c.GetGirth());
return 0;
}

  Yes, it is to static load a DLL.

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值